diff --git a/crates/brk_bencher/src/io.rs b/crates/brk_bencher/src/io.rs index 7013974fe..6c12617a9 100644 --- a/crates/brk_bencher/src/io.rs +++ b/crates/brk_bencher/src/io.rs @@ -8,7 +8,7 @@ use std::{ use std::fs; #[cfg(target_os = "macos")] -use libproc::pid_rusage::{pidrusage, RUsageInfoV2}; +use libproc::pid_rusage::{RUsageInfoV2, pidrusage}; pub struct IoMonitor { pid: u32, diff --git a/crates/brk_bencher/src/lib.rs b/crates/brk_bencher/src/lib.rs index 9eda9ee3d..4806d709c 100644 --- a/crates/brk_bencher/src/lib.rs +++ b/crates/brk_bencher/src/lib.rs @@ -113,7 +113,9 @@ impl Bencher { self.0.stop_flag.store(true, Ordering::Relaxed); if let Some(handle) = self.0.monitor_thread.lock().take() { - handle.join().map_err(|_| Error::Internal("Monitor thread panicked"))??; + handle + .join() + .map_err(|_| Error::Internal("Monitor thread panicked"))??; } self.0.progression.flush()?; diff --git a/crates/brk_bencher_visualizer/src/chart.rs b/crates/brk_bencher_visualizer/src/chart.rs index d7e20f38f..dea6c25ea 100644 --- a/crates/brk_bencher_visualizer/src/chart.rs +++ b/crates/brk_bencher_visualizer/src/chart.rs @@ -43,14 +43,18 @@ pub fn generate(config: ChartConfig, runs: &[Run]) -> Result<()> { let max_value = runs.iter().map(|r| r.max_value()).fold(0.0, f64::max); let (time_scaled, time_divisor, time_label) = format::time(max_time_s); - let (value_scaled, scale_factor, y_label) = scale_y_axis(max_value, &config.y_label, &config.y_format); + let (value_scaled, scale_factor, y_label) = + scale_y_axis(max_value, &config.y_label, &config.y_format); let x_labels = label_count(time_scaled); let root = SVGBackend::new(config.output_path, SIZE).into_drawing_area(); root.fill(&BG_COLOR)?; let mut chart = ChartBuilder::on(&root) - .caption(&config.title, (FONT, FONT_SIZE_BIG).into_font().color(&TEXT_COLOR)) + .caption( + &config.title, + (FONT, FONT_SIZE_BIG).into_font().color(&TEXT_COLOR), + ) .margin(20) .margin_right(40) .x_label_area_size(50) @@ -62,7 +66,14 @@ pub fn generate(config: ChartConfig, runs: &[Run]) -> Result<()> { for (idx, run) in runs.iter().enumerate() { let color = COLORS[idx % COLORS.len()]; - draw_series(&mut chart, &run.data, &run.id, color, time_divisor, scale_factor)?; + draw_series( + &mut chart, + &run.data, + &run.id, + color, + time_divisor, + scale_factor, + )?; } configure_legend(&mut chart)?; @@ -93,14 +104,18 @@ pub fn generate_dual( let max_value = runs.iter().map(|r| r.max_value()).fold(0.0, f64::max); let (time_scaled, time_divisor, time_label) = format::time(max_time_s); - let (value_scaled, scale_factor, y_label) = scale_y_axis(max_value, &config.y_label, &config.y_format); + let (value_scaled, scale_factor, y_label) = + scale_y_axis(max_value, &config.y_label, &config.y_format); let x_labels = label_count(time_scaled); let root = SVGBackend::new(config.output_path, SIZE).into_drawing_area(); root.fill(&BG_COLOR)?; let mut chart = ChartBuilder::on(&root) - .caption(&config.title, (FONT, FONT_SIZE_BIG).into_font().color(&TEXT_COLOR)) + .caption( + &config.title, + (FONT, FONT_SIZE_BIG).into_font().color(&TEXT_COLOR), + ) .margin(20) .margin_right(40) .x_label_area_size(50) @@ -164,7 +179,13 @@ type Chart<'a, 'b> = ChartContext< Cartesian2d, >; -fn configure_mesh(chart: &mut Chart, x_label: &str, y_label: &str, y_format: &YAxisFormat, x_labels: usize) -> Result<()> { +fn configure_mesh( + chart: &mut Chart, + x_label: &str, + y_label: &str, + y_format: &YAxisFormat, + x_labels: usize, +) -> Result<()> { let y_formatter: Box String> = match y_format { YAxisFormat::Bytes => Box::new(|y: &f64| { if y.fract() == 0.0 { @@ -200,9 +221,12 @@ fn draw_series( time_divisor: f64, scale_factor: f64, ) -> Result<()> { - let points = data - .iter() - .map(|d| (d.timestamp_ms as f64 / 1000.0 / time_divisor, d.value / scale_factor)); + let points = data.iter().map(|d| { + ( + d.timestamp_ms as f64 / 1000.0 / time_divisor, + d.value / scale_factor, + ) + }); chart .draw_series(LineSeries::new(points, color.stroke_width(1)))? @@ -221,7 +245,12 @@ fn draw_dashed_series( ) -> Result<()> { let points: Vec<_> = data .iter() - .map(|d| (d.timestamp_ms as f64 / 1000.0 / time_divisor, d.value / scale_factor)) + .map(|d| { + ( + d.timestamp_ms as f64 / 1000.0 / time_divisor, + d.value / scale_factor, + ) + }) .collect(); // Draw dashed line by skipping every other segment @@ -234,7 +263,12 @@ fn draw_dashed_series( .map(|(_, w)| PathElement::new(vec![w[0], w[1]], color.stroke_width(2))), )? .label(label) - .legend(move |(x, y)| PathElement::new(vec![(x, y), (x + 10, y), (x + 20, y)], color.stroke_width(2))); + .legend(move |(x, y)| { + PathElement::new( + vec![(x, y), (x + 10, y), (x + 20, y)], + color.stroke_width(2), + ) + }); Ok(()) } diff --git a/crates/brk_bencher_visualizer/src/lib.rs b/crates/brk_bencher_visualizer/src/lib.rs index 9f1b3ccb6..2646f257c 100644 --- a/crates/brk_bencher_visualizer/src/lib.rs +++ b/crates/brk_bencher_visualizer/src/lib.rs @@ -2,7 +2,7 @@ mod chart; mod data; mod format; -use data::{read_dual_runs, read_runs, Cutoffs, DualRun, Result, Run}; +use data::{Cutoffs, DualRun, Result, Run, read_dual_runs, read_runs}; use std::{ fs, path::{Path, PathBuf}, @@ -57,10 +57,24 @@ impl Visualizer { let io_runs = read_dual_runs(crate_path, "io.csv")?; // Combined charts (all runs) - self.generate_combined_charts(crate_path, crate_name, &disk_runs, &memory_runs, &progress_runs, &io_runs)?; + self.generate_combined_charts( + crate_path, + crate_name, + &disk_runs, + &memory_runs, + &progress_runs, + &io_runs, + )?; // Individual charts (one per run) - self.generate_individual_charts(crate_path, crate_name, &disk_runs, &memory_runs, &progress_runs, &io_runs)?; + self.generate_individual_charts( + crate_path, + crate_name, + &disk_runs, + &memory_runs, + &progress_runs, + &io_runs, + )?; Ok(()) } @@ -246,4 +260,3 @@ impl Visualizer { Ok(()) } } - diff --git a/crates/brk_bindgen/src/analysis/names.rs b/crates/brk_bindgen/src/analysis/names.rs index 021ed7370..ab02f5a87 100644 --- a/crates/brk_bindgen/src/analysis/names.rs +++ b/crates/brk_bindgen/src/analysis/names.rs @@ -151,7 +151,10 @@ mod tests { #[test] fn test_common_prefix_lth() { let names = vec!["lth_cost_basis_max", "lth_cost_basis_min", "lth_cost_basis"]; - assert_eq!(find_common_prefix(&names), Some("lth_cost_basis_".to_string())); + assert_eq!( + find_common_prefix(&names), + Some("lth_cost_basis_".to_string()) + ); } #[test] diff --git a/crates/brk_bindgen/src/generate/constants.rs b/crates/brk_bindgen/src/generate/constants.rs index 04fe098b6..b0edccb8f 100644 --- a/crates/brk_bindgen/src/generate/constants.rs +++ b/crates/brk_bindgen/src/generate/constants.rs @@ -9,11 +9,11 @@ use brk_cohort::{ AGE_RANGE_NAMES, AMOUNT_RANGE_NAMES, EPOCH_NAMES, GE_AMOUNT_NAMES, LT_AMOUNT_NAMES, MAX_AGE_NAMES, MIN_AGE_NAMES, SPENDABLE_TYPE_NAMES, TERM_NAMES, YEAR_NAMES, }; -use brk_types::{pools, Index, PoolSlug}; +use brk_types::{Index, PoolSlug, pools}; use serde::Serialize; use serde_json::Value; -use crate::{to_camel_case, VERSION}; +use crate::{VERSION, to_camel_case}; /// Collected constant data for client generation. pub struct ClientConstants { diff --git a/crates/brk_bindgen/src/generate/fields.rs b/crates/brk_bindgen/src/generate/fields.rs index 914d77912..97a066202 100644 --- a/crates/brk_bindgen/src/generate/fields.rs +++ b/crates/brk_bindgen/src/generate/fields.rs @@ -73,11 +73,17 @@ pub fn generate_parameterized_field( indent: &str, ) { let field_name = syntax.field_name(&field.name); - let type_ann = metadata.field_type_annotation(field, pattern.is_generic, None, syntax.generic_syntax()); + let type_ann = + metadata.field_type_annotation(field, pattern.is_generic, None, syntax.generic_syntax()); let path_expr = compute_path_expr(syntax, pattern, field, "acc"); let value = compute_field_value(syntax, field, metadata, &path_expr); - writeln!(output, "{}", syntax.field_init(indent, &field_name, &type_ann, &value)).unwrap(); + writeln!( + output, + "{}", + syntax.field_init(indent, &field_name, &type_ann, &value) + ) + .unwrap(); } /// Generate a tree node field with a specific child node for pattern instance base detection. @@ -127,7 +133,12 @@ pub fn generate_tree_node_field( ) }; - writeln!(output, "{}", syntax.field_init(indent, &field_name, &type_ann, &value)).unwrap(); + writeln!( + output, + "{}", + syntax.field_init(indent, &field_name, &type_ann, &value) + ) + .unwrap(); } /// Generate a leaf field using the actual metric name from the TreeNode::Leaf. diff --git a/crates/brk_bindgen/src/generators/javascript/api.rs b/crates/brk_bindgen/src/generators/javascript/api.rs index 705f123e9..5776b6dc7 100644 --- a/crates/brk_bindgen/src/generators/javascript/api.rs +++ b/crates/brk_bindgen/src/generators/javascript/api.rs @@ -2,7 +2,11 @@ use std::fmt::Write; -use crate::{Endpoint, Parameter, generators::{normalize_return_type, write_description}, to_camel_case}; +use crate::{ + Endpoint, Parameter, + generators::{normalize_return_type, write_description}, + to_camel_case, +}; /// Generate API methods for the BrkClient class. pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) { @@ -33,7 +37,13 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) { // Add endpoint path writeln!(output, " *").unwrap(); - writeln!(output, " * Endpoint: `{} {}`", endpoint.method.to_uppercase(), endpoint.path).unwrap(); + writeln!( + output, + " * Endpoint: `{} {}`", + endpoint.method.to_uppercase(), + endpoint.path + ) + .unwrap(); if !endpoint.path_params.is_empty() || !endpoint.query_params.is_empty() { writeln!(output, " *").unwrap(); @@ -89,7 +99,12 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) { } } writeln!(output, " const query = params.toString();").unwrap(); - writeln!(output, " const path = `{}${{query ? '?' + query : ''}}`;", path).unwrap(); + writeln!( + output, + " const path = `{}${{query ? '?' + query : ''}}`;", + path + ) + .unwrap(); if endpoint.supports_csv { writeln!(output, " if (format === 'csv') {{").unwrap(); diff --git a/crates/brk_bindgen/src/generators/javascript/client.rs b/crates/brk_bindgen/src/generators/javascript/client.rs index c0c0e8fd5..c92da745c 100644 --- a/crates/brk_bindgen/src/generators/javascript/client.rs +++ b/crates/brk_bindgen/src/generators/javascript/client.rs @@ -506,7 +506,11 @@ pub fn generate_static_constants(output: &mut String) { // VERSION, INDEXES, POOL_ID_TO_POOL_NAME writeln!(output, " VERSION = \"{}\";\n", constants.version).unwrap(); write_static_const(output, "INDEXES", &format_json(&constants.indexes)); - write_static_const(output, "POOL_ID_TO_POOL_NAME", &format_json(&constants.pool_map)); + write_static_const( + output, + "POOL_ID_TO_POOL_NAME", + &format_json(&constants.pool_map), + ); // Cohort constants with camelCase keys for (name, value) in CohortConstants::all() { diff --git a/crates/brk_bindgen/src/generators/javascript/types.rs b/crates/brk_bindgen/src/generators/javascript/types.rs index 0f0f89401..2b3cfddbf 100644 --- a/crates/brk_bindgen/src/generators/javascript/types.rs +++ b/crates/brk_bindgen/src/generators/javascript/types.rs @@ -4,7 +4,11 @@ use std::fmt::Write; use serde_json::Value; -use crate::{TypeSchemas, generators::{MANUAL_GENERIC_TYPES, write_description}, get_union_variants, ref_to_type_name, to_camel_case}; +use crate::{ + TypeSchemas, + generators::{MANUAL_GENERIC_TYPES, write_description}, + get_union_variants, ref_to_type_name, to_camel_case, +}; /// Generate JSDoc type definitions from OpenAPI schemas. pub fn generate_type_definitions(output: &mut String, schemas: &TypeSchemas) { diff --git a/crates/brk_bindgen/src/generators/python/api.rs b/crates/brk_bindgen/src/generators/python/api.rs index b2657030a..e848456f9 100644 --- a/crates/brk_bindgen/src/generators/python/api.rs +++ b/crates/brk_bindgen/src/generators/python/api.rs @@ -2,7 +2,11 @@ use std::fmt::Write; -use crate::{Endpoint, Parameter, escape_python_keyword, generators::{normalize_return_type, write_description}, to_snake_case}; +use crate::{ + Endpoint, Parameter, escape_python_keyword, + generators::{normalize_return_type, write_description}, + to_snake_case, +}; use super::client::generate_class_constants; use super::types::js_type_to_python; @@ -30,22 +34,58 @@ pub fn generate_main_client(output: &mut String, endpoints: &[Endpoint]) { writeln!(output).unwrap(); // Generate metric() method for dynamic metric access - writeln!(output, " def metric(self, metric: str, index: Index) -> MetricEndpointBuilder[Any]:").unwrap(); - writeln!(output, " \"\"\"Create a dynamic metric endpoint builder for any metric/index combination.").unwrap(); + writeln!( + output, + " def metric(self, metric: str, index: Index) -> MetricEndpointBuilder[Any]:" + ) + .unwrap(); + writeln!( + output, + " \"\"\"Create a dynamic metric endpoint builder for any metric/index combination." + ) + .unwrap(); writeln!(output).unwrap(); - writeln!(output, " Use this for programmatic access when the metric name is determined at runtime.").unwrap(); - writeln!(output, " For type-safe access, use the `metrics` tree instead.").unwrap(); + writeln!( + output, + " Use this for programmatic access when the metric name is determined at runtime." + ) + .unwrap(); + writeln!( + output, + " For type-safe access, use the `metrics` tree instead." + ) + .unwrap(); writeln!(output, " \"\"\"").unwrap(); - writeln!(output, " return MetricEndpointBuilder(self, metric, index)").unwrap(); + writeln!( + output, + " return MetricEndpointBuilder(self, metric, index)" + ) + .unwrap(); writeln!(output).unwrap(); // Generate helper methods - writeln!(output, " def index_to_date(self, index: Index, i: int) -> Union[date, datetime]:").unwrap(); - writeln!(output, " \"\"\"Convert an index value to a date/datetime for date-based indexes.\"\"\"").unwrap(); + writeln!( + output, + " def index_to_date(self, index: Index, i: int) -> Union[date, datetime]:" + ) + .unwrap(); + writeln!( + output, + " \"\"\"Convert an index value to a date/datetime for date-based indexes.\"\"\"" + ) + .unwrap(); writeln!(output, " return _index_to_date(index, i)").unwrap(); writeln!(output).unwrap(); - writeln!(output, " def date_to_index(self, index: Index, d: Union[date, datetime]) -> int:").unwrap(); - writeln!(output, " \"\"\"Convert a date/datetime to an index value for date-based indexes.\"\"\"").unwrap(); + writeln!( + output, + " def date_to_index(self, index: Index, d: Union[date, datetime]) -> int:" + ) + .unwrap(); + writeln!( + output, + " \"\"\"Convert a date/datetime to an index value for date-based indexes.\"\"\"" + ) + .unwrap(); writeln!(output, " return _date_to_index(index, d)").unwrap(); writeln!(output).unwrap(); // Generate API methods @@ -112,7 +152,13 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) { } } writeln!(output).unwrap(); - writeln!(output, " Endpoint: `{} {}`\"\"\"", endpoint.method.to_uppercase(), endpoint.path).unwrap(); + writeln!( + output, + " Endpoint: `{} {}`\"\"\"", + endpoint.method.to_uppercase(), + endpoint.path + ) + .unwrap(); // Build path let path = build_path_template(&endpoint.path, &endpoint.path_params); diff --git a/crates/brk_bindgen/src/generators/python/client.rs b/crates/brk_bindgen/src/generators/python/client.rs index 6fb68602a..e08ac79a5 100644 --- a/crates/brk_bindgen/src/generators/python/client.rs +++ b/crates/brk_bindgen/src/generators/python/client.rs @@ -654,7 +654,12 @@ def _dep(c: BrkClientBase, n: str, i: Index) -> DateMetricEndpointBuilder[Any]: .unwrap(); writeln!(output, " @property").unwrap(); writeln!(output, " def name(self) -> str: return self._n").unwrap(); - writeln!(output, " def indexes(self) -> List[str]: return list({})", idx_var).unwrap(); + writeln!( + output, + " def indexes(self) -> List[str]: return list({})", + idx_var + ) + .unwrap(); writeln!( output, " def get(self, index: Index) -> Optional[MetricEndpointBuilder[T]]: return _ep(self.by._c, self._n, index) if index in {} else None", diff --git a/crates/brk_bindgen/src/generators/python/mod.rs b/crates/brk_bindgen/src/generators/python/mod.rs index fa1c684f1..2deb25459 100644 --- a/crates/brk_bindgen/src/generators/python/mod.rs +++ b/crates/brk_bindgen/src/generators/python/mod.rs @@ -38,11 +38,23 @@ pub fn generate_python_client( ) .unwrap(); writeln!(output, "from urllib.parse import urlparse").unwrap(); - writeln!(output, "from datetime import date, datetime, timedelta, timezone").unwrap(); + writeln!( + output, + "from datetime import date, datetime, timedelta, timezone" + ) + .unwrap(); writeln!(output, "import json\n").unwrap(); writeln!(output, "if TYPE_CHECKING:").unwrap(); - writeln!(output, " import pandas as pd # type: ignore[import-not-found]").unwrap(); - writeln!(output, " import polars as pl # type: ignore[import-not-found]\n").unwrap(); + writeln!( + output, + " import pandas as pd # type: ignore[import-not-found]" + ) + .unwrap(); + writeln!( + output, + " import polars as pl # type: ignore[import-not-found]\n" + ) + .unwrap(); writeln!(output, "T = TypeVar('T')\n").unwrap(); types::generate_type_definitions(&mut output, schemas); diff --git a/crates/brk_bindgen/src/generators/rust/api.rs b/crates/brk_bindgen/src/generators/rust/api.rs index ac5faac60..5d7e7520e 100644 --- a/crates/brk_bindgen/src/generators/rust/api.rs +++ b/crates/brk_bindgen/src/generators/rust/api.rs @@ -115,7 +115,13 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) { } // Add endpoint path writeln!(output, " ///").unwrap(); - writeln!(output, " /// Endpoint: `{} {}`", endpoint.method.to_uppercase(), endpoint.path).unwrap(); + writeln!( + output, + " /// Endpoint: `{} {}`", + endpoint.method.to_uppercase(), + endpoint.path + ) + .unwrap(); let params = build_method_params(endpoint); writeln!( @@ -128,7 +134,12 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) { let (path, index_arg) = build_path_template(endpoint); if endpoint.query_params.is_empty() { - writeln!(output, " self.base.get_json(&format!(\"{}\"{}))", path, index_arg).unwrap(); + writeln!( + output, + " self.base.get_json(&format!(\"{}\"{}))", + path, index_arg + ) + .unwrap(); } else { writeln!(output, " let mut query = Vec::new();").unwrap(); for param in &endpoint.query_params { @@ -149,13 +160,26 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) { } } writeln!(output, " let query_str = if query.is_empty() {{ String::new() }} else {{ format!(\"?{{}}\", query.join(\"&\")) }};").unwrap(); - writeln!(output, " let path = format!(\"{}{{}}\"{}, query_str);", path, index_arg).unwrap(); + writeln!( + output, + " let path = format!(\"{}{{}}\"{}, query_str);", + path, index_arg + ) + .unwrap(); if endpoint.supports_csv { writeln!(output, " if format == Some(Format::CSV) {{").unwrap(); - writeln!(output, " self.base.get_text(&path).map(FormatResponse::Csv)").unwrap(); + writeln!( + output, + " self.base.get_text(&path).map(FormatResponse::Csv)" + ) + .unwrap(); writeln!(output, " }} else {{").unwrap(); - writeln!(output, " self.base.get_json(&path).map(FormatResponse::Json)").unwrap(); + writeln!( + output, + " self.base.get_json(&path).map(FormatResponse::Json)" + ) + .unwrap(); writeln!(output, " }}").unwrap(); } else { writeln!(output, " self.base.get_json(&path)").unwrap(); @@ -199,7 +223,10 @@ fn param_type_to_rust(param_type: &str) -> String { /// Build path template and extra format args for Index params. fn build_path_template(endpoint: &Endpoint) -> (String, &'static str) { - let has_index_param = endpoint.path_params.iter().any(|p| p.name == "index" && p.param_type == "Index"); + let has_index_param = endpoint + .path_params + .iter() + .any(|p| p.name == "index" && p.param_type == "Index"); if has_index_param { (endpoint.path.replace("{index}", "{}"), ", index.name()") } else { diff --git a/crates/brk_client/src/lib.rs b/crates/brk_client/src/lib.rs index b8d1911cc..7f2969da4 100644 --- a/crates/brk_client/src/lib.rs +++ b/crates/brk_client/src/lib.rs @@ -7,12 +7,11 @@ #![allow(clippy::useless_format)] #![allow(clippy::unnecessary_to_owned)] -use std::sync::Arc; -use std::ops::{Bound, RangeBounds}; -use serde::de::DeserializeOwned; pub use brk_cohort::*; pub use brk_types::*; - +use serde::de::DeserializeOwned; +use std::ops::{Bound, RangeBounds}; +use std::sync::Arc; /// Error type for BRK client operations. #[derive(Debug)] @@ -77,7 +76,9 @@ impl BrkClientBase { let response = minreq::get(&url) .with_timeout(self.timeout_secs) .send() - .map_err(|e| BrkError { message: e.to_string() })?; + .map_err(|e| BrkError { + message: e.to_string(), + })?; if response.status_code >= 400 { return Err(BrkError { @@ -90,9 +91,9 @@ impl BrkClientBase { /// Make a GET request and deserialize JSON response. pub fn get_json(&self, path: &str) -> Result { - self.get(path)? - .json() - .map_err(|e| BrkError { message: e.to_string() }) + self.get(path)?.json().map_err(|e| BrkError { + message: e.to_string(), + }) } /// Make a GET request and return raw text response. @@ -100,25 +101,34 @@ impl BrkClientBase { self.get(path)? .as_str() .map(|s| s.to_string()) - .map_err(|e| BrkError { message: e.to_string() }) + .map_err(|e| BrkError { + message: e.to_string(), + }) } } /// Build metric name with suffix. #[inline] fn _m(acc: &str, s: &str) -> String { - if s.is_empty() { acc.to_string() } - else if acc.is_empty() { s.to_string() } - else { format!("{acc}_{s}") } + if s.is_empty() { + acc.to_string() + } else if acc.is_empty() { + s.to_string() + } else { + format!("{acc}_{s}") + } } /// Build metric name with prefix. #[inline] fn _p(prefix: &str, acc: &str) -> String { - if acc.is_empty() { prefix.to_string() } else { format!("{prefix}_{acc}") } + if acc.is_empty() { + prefix.to_string() + } else { + format!("{prefix}_{acc}") + } } - /// Non-generic trait for metric patterns (usable in collections). pub trait AnyMetricPattern { /// Get the metric name. @@ -134,7 +144,6 @@ pub trait MetricPattern: AnyMetricPattern { fn get(&self, index: Index) -> Option>; } - /// Shared endpoint configuration. #[derive(Clone)] struct EndpointConfig { @@ -147,7 +156,13 @@ struct EndpointConfig { impl EndpointConfig { fn new(client: Arc, name: Arc, index: Index) -> Self { - Self { client, name, index, start: None, end: None } + Self { + client, + name, + index, + start: None, + end: None, + } } fn path(&self) -> String { @@ -156,11 +171,21 @@ impl EndpointConfig { fn build_path(&self, format: Option<&str>) -> String { let mut params = Vec::new(); - if let Some(s) = self.start { params.push(format!("start={}", s)); } - if let Some(e) = self.end { params.push(format!("end={}", e)); } - if let Some(fmt) = format { params.push(format!("format={}", fmt)); } + if let Some(s) = self.start { + params.push(format!("start={}", s)); + } + if let Some(e) = self.end { + params.push(format!("end={}", e)); + } + if let Some(fmt) = format { + params.push(format!("format={}", fmt)); + } let p = self.path(); - if params.is_empty() { p } else { format!("{}?{}", p, params.join("&")) } + if params.is_empty() { + p + } else { + format!("{}?{}", p, params.join("&")) + } } fn get_json(&self, format: Option<&str>) -> Result { @@ -200,14 +225,20 @@ pub type DateMetricEndpointBuilder = MetricEndpointBuilder MetricEndpointBuilder { pub fn new(client: Arc, name: Arc, index: Index) -> Self { - Self { config: EndpointConfig::new(client, name, index), _marker: std::marker::PhantomData } + Self { + config: EndpointConfig::new(client, name, index), + _marker: std::marker::PhantomData, + } } /// Select a specific index position. pub fn get(mut self, index: usize) -> SingleItemBuilder { self.config.start = Some(index as i64); self.config.end = Some(index as i64 + 1); - SingleItemBuilder { config: self.config, _marker: std::marker::PhantomData } + SingleItemBuilder { + config: self.config, + _marker: std::marker::PhantomData, + } } /// Select a range using Rust range syntax. @@ -229,7 +260,10 @@ impl MetricEndpointBuilder { Bound::Excluded(&n) => Some(n as i64), Bound::Unbounded => None, }; - RangeBuilder { config: self.config, _marker: std::marker::PhantomData } + RangeBuilder { + config: self.config, + _marker: std::marker::PhantomData, + } } /// Take the first n items. @@ -244,13 +278,19 @@ impl MetricEndpointBuilder { } else { self.config.start = Some(-(n as i64)); } - RangeBuilder { config: self.config, _marker: std::marker::PhantomData } + RangeBuilder { + config: self.config, + _marker: std::marker::PhantomData, + } } /// Skip the first n items. Chain with `take(n)` to get a range. pub fn skip(mut self, n: usize) -> SkippedBuilder { self.config.start = Some(n as i64); - SkippedBuilder { config: self.config, _marker: std::marker::PhantomData } + SkippedBuilder { + config: self.config, + _marker: std::marker::PhantomData, + } } /// Fetch all data as parsed JSON. @@ -291,7 +331,11 @@ impl MetricEndpointBuilder> { } /// Select a timestamp range (works for all date-based indexes including sub-daily). - pub fn timestamp_range(self, start: Timestamp, end: Timestamp) -> RangeBuilder> { + pub fn timestamp_range( + self, + start: Timestamp, + end: Timestamp, + ) -> RangeBuilder> { let s = self.config.index.timestamp_to_index(start).unwrap_or(0); let e = self.config.index.timestamp_to_index(end).unwrap_or(0); self.range(s..e) @@ -333,7 +377,10 @@ impl SkippedBuilder { pub fn take(mut self, n: usize) -> RangeBuilder { let start = self.config.start.unwrap_or(0); self.config.end = Some(start + n as i64); - RangeBuilder { config: self.config, _marker: std::marker::PhantomData } + RangeBuilder { + config: self.config, + _marker: std::marker::PhantomData, + } } /// Fetch from the skipped position to the end. @@ -368,10 +415,42 @@ impl RangeBuilder { } } - // Static index arrays -const _I1: &[Index] = &[Index::Minute10, Index::Minute30, Index::Hour1, Index::Hour4, Index::Hour12, Index::Day1, Index::Day3, Index::Week1, Index::Month1, Index::Month3, Index::Month6, Index::Year1, Index::Year10, Index::HalvingEpoch, Index::DifficultyEpoch, Index::Height]; -const _I2: &[Index] = &[Index::Minute10, Index::Minute30, Index::Hour1, Index::Hour4, Index::Hour12, Index::Day1, Index::Day3, Index::Week1, Index::Month1, Index::Month3, Index::Month6, Index::Year1, Index::Year10, Index::HalvingEpoch, Index::DifficultyEpoch]; +const _I1: &[Index] = &[ + Index::Minute10, + Index::Minute30, + Index::Hour1, + Index::Hour4, + Index::Hour12, + Index::Day1, + Index::Day3, + Index::Week1, + Index::Month1, + Index::Month3, + Index::Month6, + Index::Year1, + Index::Year10, + Index::HalvingEpoch, + Index::DifficultyEpoch, + Index::Height, +]; +const _I2: &[Index] = &[ + Index::Minute10, + Index::Minute30, + Index::Hour1, + Index::Hour4, + Index::Hour12, + Index::Day1, + Index::Day3, + Index::Week1, + Index::Month1, + Index::Month3, + Index::Month6, + Index::Year1, + Index::Year10, + Index::HalvingEpoch, + Index::DifficultyEpoch, +]; const _I3: &[Index] = &[Index::Minute10]; const _I4: &[Index] = &[Index::Minute30]; const _I5: &[Index] = &[Index::Hour1]; @@ -407,540 +486,1762 @@ const _I34: &[Index] = &[Index::FundedAddressIndex]; const _I35: &[Index] = &[Index::EmptyAddressIndex]; #[inline] -fn _ep(c: &Arc, n: &Arc, i: Index) -> MetricEndpointBuilder { +fn _ep( + c: &Arc, + n: &Arc, + i: Index, +) -> MetricEndpointBuilder { MetricEndpointBuilder::new(c.clone(), n.clone(), i) } #[inline] -fn _dep(c: &Arc, n: &Arc, i: Index) -> DateMetricEndpointBuilder { +fn _dep( + c: &Arc, + n: &Arc, + i: Index, +) -> DateMetricEndpointBuilder { DateMetricEndpointBuilder::new(c.clone(), n.clone(), i) } // Index accessor structs -pub struct MetricPattern1By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern1By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern1By { - pub fn minute10(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Minute10) } - pub fn minute30(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Minute30) } - pub fn hour1(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Hour1) } - pub fn hour4(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Hour4) } - pub fn hour12(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Hour12) } - pub fn day1(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Day1) } - pub fn day3(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Day3) } - pub fn week1(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Week1) } - pub fn month1(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Month1) } - pub fn month3(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Month3) } - pub fn month6(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Month6) } - pub fn year1(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Year1) } - pub fn year10(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Year10) } - pub fn halvingepoch(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::HalvingEpoch) } - pub fn difficultyepoch(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::DifficultyEpoch) } - pub fn height(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::Height) } + pub fn minute10(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Minute10) + } + pub fn minute30(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Minute30) + } + pub fn hour1(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Hour1) + } + pub fn hour4(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Hour4) + } + pub fn hour12(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Hour12) + } + pub fn day1(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Day1) + } + pub fn day3(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Day3) + } + pub fn week1(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Week1) + } + pub fn month1(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Month1) + } + pub fn month3(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Month3) + } + pub fn month6(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Month6) + } + pub fn year1(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Year1) + } + pub fn year10(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Year10) + } + pub fn halvingepoch(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::HalvingEpoch) + } + pub fn difficultyepoch(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::DifficultyEpoch) + } + pub fn height(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::Height) + } } -pub struct MetricPattern1 { name: Arc, pub by: MetricPattern1By } +pub struct MetricPattern1 { + name: Arc, + pub by: MetricPattern1By, +} impl MetricPattern1 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern1By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern1By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern1 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I1 } } -impl MetricPattern for MetricPattern1 { fn get(&self, index: Index) -> Option> { _I1.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern1 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I1 + } +} +impl MetricPattern for MetricPattern1 { + fn get(&self, index: Index) -> Option> { + _I1.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern2By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern2By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern2By { - pub fn minute10(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Minute10) } - pub fn minute30(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Minute30) } - pub fn hour1(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Hour1) } - pub fn hour4(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Hour4) } - pub fn hour12(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Hour12) } - pub fn day1(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Day1) } - pub fn day3(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Day3) } - pub fn week1(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Week1) } - pub fn month1(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Month1) } - pub fn month3(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Month3) } - pub fn month6(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Month6) } - pub fn year1(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Year1) } - pub fn year10(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Year10) } - pub fn halvingepoch(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::HalvingEpoch) } - pub fn difficultyepoch(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::DifficultyEpoch) } + pub fn minute10(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Minute10) + } + pub fn minute30(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Minute30) + } + pub fn hour1(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Hour1) + } + pub fn hour4(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Hour4) + } + pub fn hour12(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Hour12) + } + pub fn day1(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Day1) + } + pub fn day3(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Day3) + } + pub fn week1(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Week1) + } + pub fn month1(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Month1) + } + pub fn month3(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Month3) + } + pub fn month6(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Month6) + } + pub fn year1(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Year1) + } + pub fn year10(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Year10) + } + pub fn halvingepoch(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::HalvingEpoch) + } + pub fn difficultyepoch(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::DifficultyEpoch) + } } -pub struct MetricPattern2 { name: Arc, pub by: MetricPattern2By } +pub struct MetricPattern2 { + name: Arc, + pub by: MetricPattern2By, +} impl MetricPattern2 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern2By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern2By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern2 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I2 } } -impl MetricPattern for MetricPattern2 { fn get(&self, index: Index) -> Option> { _I2.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern2 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I2 + } +} +impl MetricPattern for MetricPattern2 { + fn get(&self, index: Index) -> Option> { + _I2.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern3By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern3By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern3By { - pub fn minute10(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Minute10) } + pub fn minute10(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Minute10) + } } -pub struct MetricPattern3 { name: Arc, pub by: MetricPattern3By } +pub struct MetricPattern3 { + name: Arc, + pub by: MetricPattern3By, +} impl MetricPattern3 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern3By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern3By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern3 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I3 } } -impl MetricPattern for MetricPattern3 { fn get(&self, index: Index) -> Option> { _I3.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern3 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I3 + } +} +impl MetricPattern for MetricPattern3 { + fn get(&self, index: Index) -> Option> { + _I3.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern4By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern4By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern4By { - pub fn minute30(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Minute30) } + pub fn minute30(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Minute30) + } } -pub struct MetricPattern4 { name: Arc, pub by: MetricPattern4By } +pub struct MetricPattern4 { + name: Arc, + pub by: MetricPattern4By, +} impl MetricPattern4 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern4By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern4By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern4 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I4 } } -impl MetricPattern for MetricPattern4 { fn get(&self, index: Index) -> Option> { _I4.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern4 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I4 + } +} +impl MetricPattern for MetricPattern4 { + fn get(&self, index: Index) -> Option> { + _I4.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern5By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern5By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern5By { - pub fn hour1(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Hour1) } + pub fn hour1(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Hour1) + } } -pub struct MetricPattern5 { name: Arc, pub by: MetricPattern5By } +pub struct MetricPattern5 { + name: Arc, + pub by: MetricPattern5By, +} impl MetricPattern5 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern5By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern5By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern5 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I5 } } -impl MetricPattern for MetricPattern5 { fn get(&self, index: Index) -> Option> { _I5.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern5 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I5 + } +} +impl MetricPattern for MetricPattern5 { + fn get(&self, index: Index) -> Option> { + _I5.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern6By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern6By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern6By { - pub fn hour4(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Hour4) } + pub fn hour4(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Hour4) + } } -pub struct MetricPattern6 { name: Arc, pub by: MetricPattern6By } +pub struct MetricPattern6 { + name: Arc, + pub by: MetricPattern6By, +} impl MetricPattern6 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern6By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern6By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern6 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I6 } } -impl MetricPattern for MetricPattern6 { fn get(&self, index: Index) -> Option> { _I6.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern6 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I6 + } +} +impl MetricPattern for MetricPattern6 { + fn get(&self, index: Index) -> Option> { + _I6.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern7By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern7By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern7By { - pub fn hour12(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Hour12) } + pub fn hour12(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Hour12) + } } -pub struct MetricPattern7 { name: Arc, pub by: MetricPattern7By } +pub struct MetricPattern7 { + name: Arc, + pub by: MetricPattern7By, +} impl MetricPattern7 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern7By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern7By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern7 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I7 } } -impl MetricPattern for MetricPattern7 { fn get(&self, index: Index) -> Option> { _I7.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern7 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I7 + } +} +impl MetricPattern for MetricPattern7 { + fn get(&self, index: Index) -> Option> { + _I7.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern8By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern8By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern8By { - pub fn day1(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Day1) } + pub fn day1(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Day1) + } } -pub struct MetricPattern8 { name: Arc, pub by: MetricPattern8By } +pub struct MetricPattern8 { + name: Arc, + pub by: MetricPattern8By, +} impl MetricPattern8 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern8By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern8By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern8 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I8 } } -impl MetricPattern for MetricPattern8 { fn get(&self, index: Index) -> Option> { _I8.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern8 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I8 + } +} +impl MetricPattern for MetricPattern8 { + fn get(&self, index: Index) -> Option> { + _I8.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern9By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern9By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern9By { - pub fn day3(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Day3) } + pub fn day3(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Day3) + } } -pub struct MetricPattern9 { name: Arc, pub by: MetricPattern9By } +pub struct MetricPattern9 { + name: Arc, + pub by: MetricPattern9By, +} impl MetricPattern9 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern9By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern9By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern9 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I9 } } -impl MetricPattern for MetricPattern9 { fn get(&self, index: Index) -> Option> { _I9.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern9 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I9 + } +} +impl MetricPattern for MetricPattern9 { + fn get(&self, index: Index) -> Option> { + _I9.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern10By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern10By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern10By { - pub fn week1(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Week1) } + pub fn week1(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Week1) + } } -pub struct MetricPattern10 { name: Arc, pub by: MetricPattern10By } +pub struct MetricPattern10 { + name: Arc, + pub by: MetricPattern10By, +} impl MetricPattern10 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern10By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern10By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern10 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I10 } } -impl MetricPattern for MetricPattern10 { fn get(&self, index: Index) -> Option> { _I10.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern10 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I10 + } +} +impl MetricPattern for MetricPattern10 { + fn get(&self, index: Index) -> Option> { + _I10.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern11By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern11By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern11By { - pub fn month1(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Month1) } + pub fn month1(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Month1) + } } -pub struct MetricPattern11 { name: Arc, pub by: MetricPattern11By } +pub struct MetricPattern11 { + name: Arc, + pub by: MetricPattern11By, +} impl MetricPattern11 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern11By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern11By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern11 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I11 } } -impl MetricPattern for MetricPattern11 { fn get(&self, index: Index) -> Option> { _I11.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern11 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I11 + } +} +impl MetricPattern for MetricPattern11 { + fn get(&self, index: Index) -> Option> { + _I11.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern12By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern12By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern12By { - pub fn month3(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Month3) } + pub fn month3(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Month3) + } } -pub struct MetricPattern12 { name: Arc, pub by: MetricPattern12By } +pub struct MetricPattern12 { + name: Arc, + pub by: MetricPattern12By, +} impl MetricPattern12 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern12By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern12By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern12 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I12 } } -impl MetricPattern for MetricPattern12 { fn get(&self, index: Index) -> Option> { _I12.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern12 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I12 + } +} +impl MetricPattern for MetricPattern12 { + fn get(&self, index: Index) -> Option> { + _I12.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern13By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern13By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern13By { - pub fn month6(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Month6) } + pub fn month6(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Month6) + } } -pub struct MetricPattern13 { name: Arc, pub by: MetricPattern13By } +pub struct MetricPattern13 { + name: Arc, + pub by: MetricPattern13By, +} impl MetricPattern13 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern13By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern13By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern13 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I13 } } -impl MetricPattern for MetricPattern13 { fn get(&self, index: Index) -> Option> { _I13.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern13 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I13 + } +} +impl MetricPattern for MetricPattern13 { + fn get(&self, index: Index) -> Option> { + _I13.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern14By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern14By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern14By { - pub fn year1(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Year1) } + pub fn year1(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Year1) + } } -pub struct MetricPattern14 { name: Arc, pub by: MetricPattern14By } +pub struct MetricPattern14 { + name: Arc, + pub by: MetricPattern14By, +} impl MetricPattern14 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern14By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern14By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern14 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I14 } } -impl MetricPattern for MetricPattern14 { fn get(&self, index: Index) -> Option> { _I14.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern14 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I14 + } +} +impl MetricPattern for MetricPattern14 { + fn get(&self, index: Index) -> Option> { + _I14.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern15By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern15By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern15By { - pub fn year10(&self) -> DateMetricEndpointBuilder { _dep(&self.client, &self.name, Index::Year10) } + pub fn year10(&self) -> DateMetricEndpointBuilder { + _dep(&self.client, &self.name, Index::Year10) + } } -pub struct MetricPattern15 { name: Arc, pub by: MetricPattern15By } +pub struct MetricPattern15 { + name: Arc, + pub by: MetricPattern15By, +} impl MetricPattern15 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern15By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern15By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern15 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I15 } } -impl MetricPattern for MetricPattern15 { fn get(&self, index: Index) -> Option> { _I15.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern15 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I15 + } +} +impl MetricPattern for MetricPattern15 { + fn get(&self, index: Index) -> Option> { + _I15.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern16By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern16By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern16By { - pub fn halvingepoch(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::HalvingEpoch) } + pub fn halvingepoch(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::HalvingEpoch) + } } -pub struct MetricPattern16 { name: Arc, pub by: MetricPattern16By } +pub struct MetricPattern16 { + name: Arc, + pub by: MetricPattern16By, +} impl MetricPattern16 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern16By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern16By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern16 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I16 } } -impl MetricPattern for MetricPattern16 { fn get(&self, index: Index) -> Option> { _I16.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern16 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I16 + } +} +impl MetricPattern for MetricPattern16 { + fn get(&self, index: Index) -> Option> { + _I16.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern17By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern17By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern17By { - pub fn difficultyepoch(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::DifficultyEpoch) } + pub fn difficultyepoch(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::DifficultyEpoch) + } } -pub struct MetricPattern17 { name: Arc, pub by: MetricPattern17By } +pub struct MetricPattern17 { + name: Arc, + pub by: MetricPattern17By, +} impl MetricPattern17 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern17By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern17By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern17 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I17 } } -impl MetricPattern for MetricPattern17 { fn get(&self, index: Index) -> Option> { _I17.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern17 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I17 + } +} +impl MetricPattern for MetricPattern17 { + fn get(&self, index: Index) -> Option> { + _I17.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern18By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern18By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern18By { - pub fn height(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::Height) } + pub fn height(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::Height) + } } -pub struct MetricPattern18 { name: Arc, pub by: MetricPattern18By } +pub struct MetricPattern18 { + name: Arc, + pub by: MetricPattern18By, +} impl MetricPattern18 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern18By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern18By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern18 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I18 } } -impl MetricPattern for MetricPattern18 { fn get(&self, index: Index) -> Option> { _I18.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern18 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I18 + } +} +impl MetricPattern for MetricPattern18 { + fn get(&self, index: Index) -> Option> { + _I18.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern19By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern19By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern19By { - pub fn txindex(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::TxIndex) } + pub fn txindex(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::TxIndex) + } } -pub struct MetricPattern19 { name: Arc, pub by: MetricPattern19By } +pub struct MetricPattern19 { + name: Arc, + pub by: MetricPattern19By, +} impl MetricPattern19 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern19By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern19By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern19 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I19 } } -impl MetricPattern for MetricPattern19 { fn get(&self, index: Index) -> Option> { _I19.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern19 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I19 + } +} +impl MetricPattern for MetricPattern19 { + fn get(&self, index: Index) -> Option> { + _I19.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern20By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern20By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern20By { - pub fn txinindex(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::TxInIndex) } + pub fn txinindex(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::TxInIndex) + } } -pub struct MetricPattern20 { name: Arc, pub by: MetricPattern20By } +pub struct MetricPattern20 { + name: Arc, + pub by: MetricPattern20By, +} impl MetricPattern20 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern20By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern20By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern20 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I20 } } -impl MetricPattern for MetricPattern20 { fn get(&self, index: Index) -> Option> { _I20.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern20 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I20 + } +} +impl MetricPattern for MetricPattern20 { + fn get(&self, index: Index) -> Option> { + _I20.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern21By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern21By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern21By { - pub fn txoutindex(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::TxOutIndex) } + pub fn txoutindex(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::TxOutIndex) + } } -pub struct MetricPattern21 { name: Arc, pub by: MetricPattern21By } +pub struct MetricPattern21 { + name: Arc, + pub by: MetricPattern21By, +} impl MetricPattern21 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern21By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern21By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern21 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I21 } } -impl MetricPattern for MetricPattern21 { fn get(&self, index: Index) -> Option> { _I21.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern21 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I21 + } +} +impl MetricPattern for MetricPattern21 { + fn get(&self, index: Index) -> Option> { + _I21.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern22By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern22By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern22By { - pub fn emptyoutputindex(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::EmptyOutputIndex) } + pub fn emptyoutputindex(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::EmptyOutputIndex) + } } -pub struct MetricPattern22 { name: Arc, pub by: MetricPattern22By } +pub struct MetricPattern22 { + name: Arc, + pub by: MetricPattern22By, +} impl MetricPattern22 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern22By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern22By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern22 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I22 } } -impl MetricPattern for MetricPattern22 { fn get(&self, index: Index) -> Option> { _I22.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern22 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I22 + } +} +impl MetricPattern for MetricPattern22 { + fn get(&self, index: Index) -> Option> { + _I22.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern23By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern23By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern23By { - pub fn opreturnindex(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::OpReturnIndex) } + pub fn opreturnindex(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::OpReturnIndex) + } } -pub struct MetricPattern23 { name: Arc, pub by: MetricPattern23By } +pub struct MetricPattern23 { + name: Arc, + pub by: MetricPattern23By, +} impl MetricPattern23 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern23By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern23By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern23 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I23 } } -impl MetricPattern for MetricPattern23 { fn get(&self, index: Index) -> Option> { _I23.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern23 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I23 + } +} +impl MetricPattern for MetricPattern23 { + fn get(&self, index: Index) -> Option> { + _I23.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern24By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern24By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern24By { - pub fn p2aaddressindex(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::P2AAddressIndex) } + pub fn p2aaddressindex(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::P2AAddressIndex) + } } -pub struct MetricPattern24 { name: Arc, pub by: MetricPattern24By } +pub struct MetricPattern24 { + name: Arc, + pub by: MetricPattern24By, +} impl MetricPattern24 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern24By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern24By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern24 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I24 } } -impl MetricPattern for MetricPattern24 { fn get(&self, index: Index) -> Option> { _I24.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern24 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I24 + } +} +impl MetricPattern for MetricPattern24 { + fn get(&self, index: Index) -> Option> { + _I24.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern25By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern25By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern25By { - pub fn p2msoutputindex(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::P2MSOutputIndex) } + pub fn p2msoutputindex(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::P2MSOutputIndex) + } } -pub struct MetricPattern25 { name: Arc, pub by: MetricPattern25By } +pub struct MetricPattern25 { + name: Arc, + pub by: MetricPattern25By, +} impl MetricPattern25 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern25By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern25By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern25 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I25 } } -impl MetricPattern for MetricPattern25 { fn get(&self, index: Index) -> Option> { _I25.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern25 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I25 + } +} +impl MetricPattern for MetricPattern25 { + fn get(&self, index: Index) -> Option> { + _I25.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern26By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern26By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern26By { - pub fn p2pk33addressindex(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::P2PK33AddressIndex) } + pub fn p2pk33addressindex(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::P2PK33AddressIndex) + } } -pub struct MetricPattern26 { name: Arc, pub by: MetricPattern26By } +pub struct MetricPattern26 { + name: Arc, + pub by: MetricPattern26By, +} impl MetricPattern26 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern26By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern26By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern26 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I26 } } -impl MetricPattern for MetricPattern26 { fn get(&self, index: Index) -> Option> { _I26.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern26 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I26 + } +} +impl MetricPattern for MetricPattern26 { + fn get(&self, index: Index) -> Option> { + _I26.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern27By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern27By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern27By { - pub fn p2pk65addressindex(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::P2PK65AddressIndex) } + pub fn p2pk65addressindex(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::P2PK65AddressIndex) + } } -pub struct MetricPattern27 { name: Arc, pub by: MetricPattern27By } +pub struct MetricPattern27 { + name: Arc, + pub by: MetricPattern27By, +} impl MetricPattern27 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern27By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern27By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern27 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I27 } } -impl MetricPattern for MetricPattern27 { fn get(&self, index: Index) -> Option> { _I27.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern27 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I27 + } +} +impl MetricPattern for MetricPattern27 { + fn get(&self, index: Index) -> Option> { + _I27.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern28By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern28By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern28By { - pub fn p2pkhaddressindex(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::P2PKHAddressIndex) } + pub fn p2pkhaddressindex(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::P2PKHAddressIndex) + } } -pub struct MetricPattern28 { name: Arc, pub by: MetricPattern28By } +pub struct MetricPattern28 { + name: Arc, + pub by: MetricPattern28By, +} impl MetricPattern28 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern28By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern28By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern28 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I28 } } -impl MetricPattern for MetricPattern28 { fn get(&self, index: Index) -> Option> { _I28.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern28 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I28 + } +} +impl MetricPattern for MetricPattern28 { + fn get(&self, index: Index) -> Option> { + _I28.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern29By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern29By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern29By { - pub fn p2shaddressindex(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::P2SHAddressIndex) } + pub fn p2shaddressindex(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::P2SHAddressIndex) + } } -pub struct MetricPattern29 { name: Arc, pub by: MetricPattern29By } +pub struct MetricPattern29 { + name: Arc, + pub by: MetricPattern29By, +} impl MetricPattern29 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern29By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern29By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern29 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I29 } } -impl MetricPattern for MetricPattern29 { fn get(&self, index: Index) -> Option> { _I29.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern29 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I29 + } +} +impl MetricPattern for MetricPattern29 { + fn get(&self, index: Index) -> Option> { + _I29.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern30By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern30By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern30By { - pub fn p2traddressindex(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::P2TRAddressIndex) } + pub fn p2traddressindex(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::P2TRAddressIndex) + } } -pub struct MetricPattern30 { name: Arc, pub by: MetricPattern30By } +pub struct MetricPattern30 { + name: Arc, + pub by: MetricPattern30By, +} impl MetricPattern30 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern30By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern30By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern30 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I30 } } -impl MetricPattern for MetricPattern30 { fn get(&self, index: Index) -> Option> { _I30.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern30 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I30 + } +} +impl MetricPattern for MetricPattern30 { + fn get(&self, index: Index) -> Option> { + _I30.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern31By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern31By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern31By { - pub fn p2wpkhaddressindex(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::P2WPKHAddressIndex) } + pub fn p2wpkhaddressindex(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::P2WPKHAddressIndex) + } } -pub struct MetricPattern31 { name: Arc, pub by: MetricPattern31By } +pub struct MetricPattern31 { + name: Arc, + pub by: MetricPattern31By, +} impl MetricPattern31 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern31By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern31By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern31 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I31 } } -impl MetricPattern for MetricPattern31 { fn get(&self, index: Index) -> Option> { _I31.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern31 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I31 + } +} +impl MetricPattern for MetricPattern31 { + fn get(&self, index: Index) -> Option> { + _I31.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern32By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern32By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern32By { - pub fn p2wshaddressindex(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::P2WSHAddressIndex) } + pub fn p2wshaddressindex(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::P2WSHAddressIndex) + } } -pub struct MetricPattern32 { name: Arc, pub by: MetricPattern32By } +pub struct MetricPattern32 { + name: Arc, + pub by: MetricPattern32By, +} impl MetricPattern32 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern32By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern32By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern32 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I32 } } -impl MetricPattern for MetricPattern32 { fn get(&self, index: Index) -> Option> { _I32.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern32 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I32 + } +} +impl MetricPattern for MetricPattern32 { + fn get(&self, index: Index) -> Option> { + _I32.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern33By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern33By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern33By { - pub fn unknownoutputindex(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::UnknownOutputIndex) } + pub fn unknownoutputindex(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::UnknownOutputIndex) + } } -pub struct MetricPattern33 { name: Arc, pub by: MetricPattern33By } +pub struct MetricPattern33 { + name: Arc, + pub by: MetricPattern33By, +} impl MetricPattern33 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern33By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern33By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern33 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I33 } } -impl MetricPattern for MetricPattern33 { fn get(&self, index: Index) -> Option> { _I33.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern33 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I33 + } +} +impl MetricPattern for MetricPattern33 { + fn get(&self, index: Index) -> Option> { + _I33.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern34By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern34By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern34By { - pub fn fundedaddressindex(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::FundedAddressIndex) } + pub fn fundedaddressindex(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::FundedAddressIndex) + } } -pub struct MetricPattern34 { name: Arc, pub by: MetricPattern34By } +pub struct MetricPattern34 { + name: Arc, + pub by: MetricPattern34By, +} impl MetricPattern34 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern34By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern34By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern34 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I34 } } -impl MetricPattern for MetricPattern34 { fn get(&self, index: Index) -> Option> { _I34.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern34 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I34 + } +} +impl MetricPattern for MetricPattern34 { + fn get(&self, index: Index) -> Option> { + _I34.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} -pub struct MetricPattern35By { client: Arc, name: Arc, _marker: std::marker::PhantomData } +pub struct MetricPattern35By { + client: Arc, + name: Arc, + _marker: std::marker::PhantomData, +} impl MetricPattern35By { - pub fn emptyaddressindex(&self) -> MetricEndpointBuilder { _ep(&self.client, &self.name, Index::EmptyAddressIndex) } + pub fn emptyaddressindex(&self) -> MetricEndpointBuilder { + _ep(&self.client, &self.name, Index::EmptyAddressIndex) + } } -pub struct MetricPattern35 { name: Arc, pub by: MetricPattern35By } +pub struct MetricPattern35 { + name: Arc, + pub by: MetricPattern35By, +} impl MetricPattern35 { - pub fn new(client: Arc, name: String) -> Self { let name: Arc = name.into(); Self { name: name.clone(), by: MetricPattern35By { client, name, _marker: std::marker::PhantomData } } } - pub fn name(&self) -> &str { &self.name } + pub fn new(client: Arc, name: String) -> Self { + let name: Arc = name.into(); + Self { + name: name.clone(), + by: MetricPattern35By { + client, + name, + _marker: std::marker::PhantomData, + }, + } + } + pub fn name(&self) -> &str { + &self.name + } } -impl AnyMetricPattern for MetricPattern35 { fn name(&self) -> &str { &self.name } fn indexes(&self) -> &'static [Index] { _I35 } } -impl MetricPattern for MetricPattern35 { fn get(&self, index: Index) -> Option> { _I35.contains(&index).then(|| _ep(&self.by.client, &self.by.name, index)) } } +impl AnyMetricPattern for MetricPattern35 { + fn name(&self) -> &str { + &self.name + } + fn indexes(&self) -> &'static [Index] { + _I35 + } +} +impl MetricPattern for MetricPattern35 { + fn get(&self, index: Index) -> Option> { + _I35.contains(&index) + .then(|| _ep(&self.by.client, &self.by.name, index)) + } +} // Reusable pattern structs /// Pattern struct for repeated tree structure. -pub struct AdjustedCapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern { +pub struct AdjustedCapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern +{ pub adjusted_sopr: _1m1w1y24hPattern, pub adjusted_sopr_ema: _1m1wPattern2, pub adjusted_value_created: MetricPattern1, @@ -1070,7 +2371,8 @@ impl AdjustedCapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSe } /// Pattern struct for repeated tree structure. -pub struct AdjustedCapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern2 { +pub struct AdjustedCapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern2 +{ pub adjusted_sopr: _1m1w1y24hPattern, pub adjusted_sopr_ema: _1m1wPattern2, pub adjusted_value_created: MetricPattern1, @@ -1188,7 +2490,8 @@ impl AdjustedCapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSe } /// Pattern struct for repeated tree structure. -pub struct CapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern2 { +pub struct CapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern2 +{ pub cap_raw: MetricPattern18, pub capitulation_flow: MetricPattern1, pub gross_pnl: CentsUsdPattern, @@ -1244,7 +2547,9 @@ pub struct CapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSell pub value_destroyed_sum: _1m1w1y24hPattern, } -impl CapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern2 { +impl + CapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern2 +{ /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { @@ -1254,59 +2559,144 @@ impl CapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSo gross_pnl_sum: _1m1w1y24hPattern::new(client.clone(), _m(&acc, "gross_pnl_sum")), investor_cap_raw: MetricPattern18::new(client.clone(), _m(&acc, "investor_cap_raw")), investor_price: CentsSatsUsdPattern::new(client.clone(), _m(&acc, "investor_price")), - investor_price_ratio: BpsRatioPattern::new(client.clone(), _m(&acc, "investor_price_ratio")), - investor_price_ratio_ext: RatioPattern::new(client.clone(), _m(&acc, "investor_price_ratio")), + investor_price_ratio: BpsRatioPattern::new( + client.clone(), + _m(&acc, "investor_price_ratio"), + ), + investor_price_ratio_ext: RatioPattern::new( + client.clone(), + _m(&acc, "investor_price_ratio"), + ), loss_value_created: MetricPattern1::new(client.clone(), _m(&acc, "loss_value_created")), - loss_value_destroyed: MetricPattern1::new(client.clone(), _m(&acc, "loss_value_destroyed")), - lower_price_band: CentsSatsUsdPattern::new(client.clone(), _m(&acc, "lower_price_band")), + loss_value_destroyed: MetricPattern1::new( + client.clone(), + _m(&acc, "loss_value_destroyed"), + ), + lower_price_band: CentsSatsUsdPattern::new( + client.clone(), + _m(&acc, "lower_price_band"), + ), mvrv: MetricPattern1::new(client.clone(), _m(&acc, "mvrv")), neg_realized_loss: MetricPattern1::new(client.clone(), _m(&acc, "neg_realized_loss")), net_pnl_change_1m: MetricPattern1::new(client.clone(), _m(&acc, "net_pnl_change_1m")), - net_pnl_change_1m_rel_to_market_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "net_pnl_change_1m_rel_to_market_cap")), - net_pnl_change_1m_rel_to_realized_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "net_pnl_change_1m_rel_to_realized_cap")), - net_realized_pnl: CumulativeHeightPattern::new(client.clone(), _m(&acc, "net_realized_pnl")), - net_realized_pnl_ema_1w: MetricPattern1::new(client.clone(), _m(&acc, "net_realized_pnl_ema_1w")), - net_realized_pnl_rel_to_realized_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "net_realized_pnl_rel_to_realized_cap")), - peak_regret: CumulativeHeightPattern::new(client.clone(), _m(&acc, "realized_peak_regret")), - peak_regret_rel_to_realized_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "realized_peak_regret_rel_to_realized_cap")), + net_pnl_change_1m_rel_to_market_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "net_pnl_change_1m_rel_to_market_cap"), + ), + net_pnl_change_1m_rel_to_realized_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "net_pnl_change_1m_rel_to_realized_cap"), + ), + net_realized_pnl: CumulativeHeightPattern::new( + client.clone(), + _m(&acc, "net_realized_pnl"), + ), + net_realized_pnl_ema_1w: MetricPattern1::new( + client.clone(), + _m(&acc, "net_realized_pnl_ema_1w"), + ), + net_realized_pnl_rel_to_realized_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "net_realized_pnl_rel_to_realized_cap"), + ), + peak_regret: CumulativeHeightPattern::new( + client.clone(), + _m(&acc, "realized_peak_regret"), + ), + peak_regret_rel_to_realized_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "realized_peak_regret_rel_to_realized_cap"), + ), profit_flow: MetricPattern1::new(client.clone(), _m(&acc, "profit_flow")), - profit_value_created: MetricPattern1::new(client.clone(), _m(&acc, "profit_value_created")), - profit_value_destroyed: MetricPattern1::new(client.clone(), _m(&acc, "profit_value_destroyed")), + profit_value_created: MetricPattern1::new( + client.clone(), + _m(&acc, "profit_value_created"), + ), + profit_value_destroyed: MetricPattern1::new( + client.clone(), + _m(&acc, "profit_value_destroyed"), + ), realized_cap: MetricPattern1::new(client.clone(), _m(&acc, "realized_cap")), realized_cap_cents: MetricPattern1::new(client.clone(), _m(&acc, "realized_cap_cents")), - realized_cap_change_1m: MetricPattern1::new(client.clone(), _m(&acc, "realized_cap_change_1m")), - realized_cap_rel_to_own_market_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "realized_cap_rel_to_own_market_cap")), + realized_cap_change_1m: MetricPattern1::new( + client.clone(), + _m(&acc, "realized_cap_change_1m"), + ), + realized_cap_rel_to_own_market_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "realized_cap_rel_to_own_market_cap"), + ), realized_loss: CumulativeHeightPattern::new(client.clone(), _m(&acc, "realized_loss")), - realized_loss_ema_1w: MetricPattern1::new(client.clone(), _m(&acc, "realized_loss_ema_1w")), - realized_loss_rel_to_realized_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "realized_loss_rel_to_realized_cap")), + realized_loss_ema_1w: MetricPattern1::new( + client.clone(), + _m(&acc, "realized_loss_ema_1w"), + ), + realized_loss_rel_to_realized_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "realized_loss_rel_to_realized_cap"), + ), realized_loss_sum: _1m1w1y24hPattern::new(client.clone(), _m(&acc, "realized_loss")), realized_price: CentsSatsUsdPattern::new(client.clone(), _m(&acc, "realized_price")), - realized_price_ratio: BpsRatioPattern::new(client.clone(), _m(&acc, "realized_price_ratio")), - realized_price_ratio_ext: RatioPattern::new(client.clone(), _m(&acc, "realized_price_ratio")), - realized_profit: CumulativeHeightPattern::new(client.clone(), _m(&acc, "realized_profit")), - realized_profit_ema_1w: MetricPattern1::new(client.clone(), _m(&acc, "realized_profit_ema_1w")), - realized_profit_rel_to_realized_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "realized_profit_rel_to_realized_cap")), - realized_profit_sum: _1m1w1y24hPattern::new(client.clone(), _m(&acc, "realized_profit")), - realized_profit_to_loss_ratio: _1m1w1y24hPattern::new(client.clone(), _m(&acc, "realized_profit_to_loss_ratio")), - sell_side_risk_ratio: _1m1w1y24hPattern2::new(client.clone(), _m(&acc, "sell_side_risk_ratio")), - sell_side_risk_ratio_24h_ema: _1m1wPattern::new(client.clone(), _m(&acc, "sell_side_risk_ratio_24h_ema")), + realized_price_ratio: BpsRatioPattern::new( + client.clone(), + _m(&acc, "realized_price_ratio"), + ), + realized_price_ratio_ext: RatioPattern::new( + client.clone(), + _m(&acc, "realized_price_ratio"), + ), + realized_profit: CumulativeHeightPattern::new( + client.clone(), + _m(&acc, "realized_profit"), + ), + realized_profit_ema_1w: MetricPattern1::new( + client.clone(), + _m(&acc, "realized_profit_ema_1w"), + ), + realized_profit_rel_to_realized_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "realized_profit_rel_to_realized_cap"), + ), + realized_profit_sum: _1m1w1y24hPattern::new( + client.clone(), + _m(&acc, "realized_profit"), + ), + realized_profit_to_loss_ratio: _1m1w1y24hPattern::new( + client.clone(), + _m(&acc, "realized_profit_to_loss_ratio"), + ), + sell_side_risk_ratio: _1m1w1y24hPattern2::new( + client.clone(), + _m(&acc, "sell_side_risk_ratio"), + ), + sell_side_risk_ratio_24h_ema: _1m1wPattern::new( + client.clone(), + _m(&acc, "sell_side_risk_ratio_24h_ema"), + ), sent_in_loss: BaseCumulativePattern::new(client.clone(), _m(&acc, "sent_in_loss")), sent_in_loss_ema: _2wPattern::new(client.clone(), _m(&acc, "sent_in_loss_ema_2w")), sent_in_profit: BaseCumulativePattern::new(client.clone(), _m(&acc, "sent_in_profit")), sent_in_profit_ema: _2wPattern::new(client.clone(), _m(&acc, "sent_in_profit_ema_2w")), sopr: _1m1w1y24hPattern::new(client.clone(), _m(&acc, "sopr")), sopr_24h_ema: _1m1wPattern2::new(client.clone(), _m(&acc, "sopr_24h_ema")), - upper_price_band: CentsSatsUsdPattern::new(client.clone(), _m(&acc, "upper_price_band")), + upper_price_band: CentsSatsUsdPattern::new( + client.clone(), + _m(&acc, "upper_price_band"), + ), value_created: MetricPattern1::new(client.clone(), _m(&acc, "value_created")), value_created_sum: _1m1w1y24hPattern::new(client.clone(), _m(&acc, "value_created")), value_destroyed: MetricPattern1::new(client.clone(), _m(&acc, "value_destroyed")), - value_destroyed_sum: _1m1w1y24hPattern::new(client.clone(), _m(&acc, "value_destroyed")), + value_destroyed_sum: _1m1w1y24hPattern::new( + client.clone(), + _m(&acc, "value_destroyed"), + ), } } } /// Pattern struct for repeated tree structure. -pub struct CapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern { +pub struct CapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern +{ pub cap_raw: MetricPattern18, pub capitulation_flow: MetricPattern1, pub gross_pnl: CentsUsdPattern, @@ -1356,7 +2746,9 @@ pub struct CapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSell pub value_destroyed_sum: _1m1w1y24hPattern, } -impl CapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern { +impl + CapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern +{ /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { @@ -1366,47 +2758,116 @@ impl CapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSo gross_pnl_sum: _1m1w1y24hPattern::new(client.clone(), _m(&acc, "gross_pnl_sum")), investor_cap_raw: MetricPattern18::new(client.clone(), _m(&acc, "investor_cap_raw")), investor_price: CentsSatsUsdPattern::new(client.clone(), _m(&acc, "investor_price")), - investor_price_ratio: BpsRatioPattern::new(client.clone(), _m(&acc, "investor_price_ratio")), + investor_price_ratio: BpsRatioPattern::new( + client.clone(), + _m(&acc, "investor_price_ratio"), + ), loss_value_created: MetricPattern1::new(client.clone(), _m(&acc, "loss_value_created")), - loss_value_destroyed: MetricPattern1::new(client.clone(), _m(&acc, "loss_value_destroyed")), - lower_price_band: CentsSatsUsdPattern::new(client.clone(), _m(&acc, "lower_price_band")), + loss_value_destroyed: MetricPattern1::new( + client.clone(), + _m(&acc, "loss_value_destroyed"), + ), + lower_price_band: CentsSatsUsdPattern::new( + client.clone(), + _m(&acc, "lower_price_band"), + ), mvrv: MetricPattern1::new(client.clone(), _m(&acc, "mvrv")), neg_realized_loss: MetricPattern1::new(client.clone(), _m(&acc, "neg_realized_loss")), net_pnl_change_1m: MetricPattern1::new(client.clone(), _m(&acc, "net_pnl_change_1m")), - net_pnl_change_1m_rel_to_market_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "net_pnl_change_1m_rel_to_market_cap")), - net_pnl_change_1m_rel_to_realized_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "net_pnl_change_1m_rel_to_realized_cap")), - net_realized_pnl: CumulativeHeightPattern::new(client.clone(), _m(&acc, "net_realized_pnl")), - net_realized_pnl_ema_1w: MetricPattern1::new(client.clone(), _m(&acc, "net_realized_pnl_ema_1w")), - net_realized_pnl_rel_to_realized_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "net_realized_pnl_rel_to_realized_cap")), - peak_regret: CumulativeHeightPattern::new(client.clone(), _m(&acc, "realized_peak_regret")), - peak_regret_rel_to_realized_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "realized_peak_regret_rel_to_realized_cap")), + net_pnl_change_1m_rel_to_market_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "net_pnl_change_1m_rel_to_market_cap"), + ), + net_pnl_change_1m_rel_to_realized_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "net_pnl_change_1m_rel_to_realized_cap"), + ), + net_realized_pnl: CumulativeHeightPattern::new( + client.clone(), + _m(&acc, "net_realized_pnl"), + ), + net_realized_pnl_ema_1w: MetricPattern1::new( + client.clone(), + _m(&acc, "net_realized_pnl_ema_1w"), + ), + net_realized_pnl_rel_to_realized_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "net_realized_pnl_rel_to_realized_cap"), + ), + peak_regret: CumulativeHeightPattern::new( + client.clone(), + _m(&acc, "realized_peak_regret"), + ), + peak_regret_rel_to_realized_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "realized_peak_regret_rel_to_realized_cap"), + ), profit_flow: MetricPattern1::new(client.clone(), _m(&acc, "profit_flow")), - profit_value_created: MetricPattern1::new(client.clone(), _m(&acc, "profit_value_created")), - profit_value_destroyed: MetricPattern1::new(client.clone(), _m(&acc, "profit_value_destroyed")), + profit_value_created: MetricPattern1::new( + client.clone(), + _m(&acc, "profit_value_created"), + ), + profit_value_destroyed: MetricPattern1::new( + client.clone(), + _m(&acc, "profit_value_destroyed"), + ), realized_cap: MetricPattern1::new(client.clone(), _m(&acc, "realized_cap")), realized_cap_cents: MetricPattern1::new(client.clone(), _m(&acc, "realized_cap_cents")), - realized_cap_change_1m: MetricPattern1::new(client.clone(), _m(&acc, "realized_cap_change_1m")), + realized_cap_change_1m: MetricPattern1::new( + client.clone(), + _m(&acc, "realized_cap_change_1m"), + ), realized_loss: CumulativeHeightPattern::new(client.clone(), _m(&acc, "realized_loss")), - realized_loss_ema_1w: MetricPattern1::new(client.clone(), _m(&acc, "realized_loss_ema_1w")), - realized_loss_rel_to_realized_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "realized_loss_rel_to_realized_cap")), + realized_loss_ema_1w: MetricPattern1::new( + client.clone(), + _m(&acc, "realized_loss_ema_1w"), + ), + realized_loss_rel_to_realized_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "realized_loss_rel_to_realized_cap"), + ), realized_price: CentsSatsUsdPattern::new(client.clone(), _m(&acc, "realized_price")), - realized_price_ratio: BpsRatioPattern::new(client.clone(), _m(&acc, "realized_price_ratio")), - realized_profit: CumulativeHeightPattern::new(client.clone(), _m(&acc, "realized_profit")), - realized_profit_ema_1w: MetricPattern1::new(client.clone(), _m(&acc, "realized_profit_ema_1w")), - realized_profit_rel_to_realized_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "realized_profit_rel_to_realized_cap")), - sell_side_risk_ratio: _1m1w1y24hPattern2::new(client.clone(), _m(&acc, "sell_side_risk_ratio")), - sell_side_risk_ratio_24h_ema: _1m1wPattern::new(client.clone(), _m(&acc, "sell_side_risk_ratio_24h_ema")), + realized_price_ratio: BpsRatioPattern::new( + client.clone(), + _m(&acc, "realized_price_ratio"), + ), + realized_profit: CumulativeHeightPattern::new( + client.clone(), + _m(&acc, "realized_profit"), + ), + realized_profit_ema_1w: MetricPattern1::new( + client.clone(), + _m(&acc, "realized_profit_ema_1w"), + ), + realized_profit_rel_to_realized_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "realized_profit_rel_to_realized_cap"), + ), + sell_side_risk_ratio: _1m1w1y24hPattern2::new( + client.clone(), + _m(&acc, "sell_side_risk_ratio"), + ), + sell_side_risk_ratio_24h_ema: _1m1wPattern::new( + client.clone(), + _m(&acc, "sell_side_risk_ratio_24h_ema"), + ), sent_in_loss: BaseCumulativePattern::new(client.clone(), _m(&acc, "sent_in_loss")), sent_in_loss_ema: _2wPattern::new(client.clone(), _m(&acc, "sent_in_loss_ema_2w")), sent_in_profit: BaseCumulativePattern::new(client.clone(), _m(&acc, "sent_in_profit")), sent_in_profit_ema: _2wPattern::new(client.clone(), _m(&acc, "sent_in_profit_ema_2w")), sopr: _1m1w1y24hPattern::new(client.clone(), _m(&acc, "sopr")), sopr_24h_ema: _1m1wPattern2::new(client.clone(), _m(&acc, "sopr_24h_ema")), - upper_price_band: CentsSatsUsdPattern::new(client.clone(), _m(&acc, "upper_price_band")), + upper_price_band: CentsSatsUsdPattern::new( + client.clone(), + _m(&acc, "upper_price_band"), + ), value_created: MetricPattern1::new(client.clone(), _m(&acc, "value_created")), value_created_sum: _1m1w1y24hPattern::new(client.clone(), _m(&acc, "value_created")), value_destroyed: MetricPattern1::new(client.clone(), _m(&acc, "value_destroyed")), - value_destroyed_sum: _1m1w1y24hPattern::new(client.clone(), _m(&acc, "value_destroyed")), + value_destroyed_sum: _1m1w1y24hPattern::new( + client.clone(), + _m(&acc, "value_destroyed"), + ), } } } @@ -1523,10 +2984,22 @@ impl BpsPriceRatioPattern { ratio_pct98_price: CentsSatsUsdPattern::new(client.clone(), _m(&acc, "ratio_pct98")), ratio_pct99: BpsRatioPattern::new(client.clone(), _m(&acc, "ratio_pct99")), ratio_pct99_price: CentsSatsUsdPattern::new(client.clone(), _m(&acc, "ratio_pct99")), - ratio_sd: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new(client.clone(), _m(&acc, "ratio")), - ratio_sd_1y: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new(client.clone(), _m(&acc, "ratio")), - ratio_sd_2y: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new(client.clone(), _m(&acc, "ratio")), - ratio_sd_4y: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new(client.clone(), _m(&acc, "ratio")), + ratio_sd: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new( + client.clone(), + _m(&acc, "ratio"), + ), + ratio_sd_1y: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new( + client.clone(), + _m(&acc, "ratio"), + ), + ratio_sd_2y: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new( + client.clone(), + _m(&acc, "ratio"), + ), + ratio_sd_4y: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new( + client.clone(), + _m(&acc, "ratio"), + ), ratio_sma_1m: BpsRatioPattern::new(client.clone(), _m(&acc, "ratio_sma_1m")), ratio_sma_1w: BpsRatioPattern::new(client.clone(), _m(&acc, "ratio_sma_1w")), } @@ -1575,10 +3048,22 @@ impl BpsRatioPattern2 { ratio_pct98_price: CentsSatsUsdPattern::new(client.clone(), _m(&acc, "pct98")), ratio_pct99: BpsRatioPattern::new(client.clone(), _m(&acc, "pct99")), ratio_pct99_price: CentsSatsUsdPattern::new(client.clone(), _m(&acc, "pct99")), - ratio_sd: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new(client.clone(), acc.clone()), - ratio_sd_1y: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new(client.clone(), acc.clone()), - ratio_sd_2y: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new(client.clone(), acc.clone()), - ratio_sd_4y: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new(client.clone(), acc.clone()), + ratio_sd: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new( + client.clone(), + acc.clone(), + ), + ratio_sd_1y: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new( + client.clone(), + acc.clone(), + ), + ratio_sd_2y: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new( + client.clone(), + acc.clone(), + ), + ratio_sd_4y: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new( + client.clone(), + acc.clone(), + ), ratio_sma_1m: BpsRatioPattern::new(client.clone(), _m(&acc, "sma_1m")), ratio_sma_1w: BpsRatioPattern::new(client.clone(), _m(&acc, "sma_1w")), } @@ -1613,32 +3098,90 @@ impl InvestedNegNetNuplSupplyUnrealizedPattern2 { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - invested_capital_in_loss_rel_to_realized_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "invested_capital_in_loss_rel_to_realized_cap")), - invested_capital_in_profit_rel_to_realized_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "invested_capital_in_profit_rel_to_realized_cap")), - neg_unrealized_loss_rel_to_market_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_market_cap")), - neg_unrealized_loss_rel_to_own_gross_pnl: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_own_gross_pnl")), - neg_unrealized_loss_rel_to_own_market_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_own_market_cap")), - net_unrealized_pnl_rel_to_market_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "net_unrealized_pnl_rel_to_market_cap")), - net_unrealized_pnl_rel_to_own_gross_pnl: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "net_unrealized_pnl_rel_to_own_gross_pnl")), - net_unrealized_pnl_rel_to_own_market_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "net_unrealized_pnl_rel_to_own_market_cap")), + invested_capital_in_loss_rel_to_realized_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "invested_capital_in_loss_rel_to_realized_cap"), + ), + invested_capital_in_profit_rel_to_realized_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "invested_capital_in_profit_rel_to_realized_cap"), + ), + neg_unrealized_loss_rel_to_market_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "neg_unrealized_loss_rel_to_market_cap"), + ), + neg_unrealized_loss_rel_to_own_gross_pnl: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "neg_unrealized_loss_rel_to_own_gross_pnl"), + ), + neg_unrealized_loss_rel_to_own_market_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "neg_unrealized_loss_rel_to_own_market_cap"), + ), + net_unrealized_pnl_rel_to_market_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "net_unrealized_pnl_rel_to_market_cap"), + ), + net_unrealized_pnl_rel_to_own_gross_pnl: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "net_unrealized_pnl_rel_to_own_gross_pnl"), + ), + net_unrealized_pnl_rel_to_own_market_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "net_unrealized_pnl_rel_to_own_market_cap"), + ), nupl: MetricPattern1::new(client.clone(), _m(&acc, "nupl")), - supply_in_loss_rel_to_circulating_supply: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_circulating_supply")), - supply_in_loss_rel_to_own_supply: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_own_supply")), - supply_in_profit_rel_to_circulating_supply: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_circulating_supply")), - supply_in_profit_rel_to_own_supply: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_own_supply")), - supply_rel_to_circulating_supply: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "supply_rel_to_circulating_supply")), - unrealized_loss_rel_to_market_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_market_cap")), - unrealized_loss_rel_to_own_gross_pnl: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_own_gross_pnl")), - unrealized_loss_rel_to_own_market_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_own_market_cap")), - unrealized_profit_rel_to_market_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_market_cap")), - unrealized_profit_rel_to_own_gross_pnl: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_own_gross_pnl")), - unrealized_profit_rel_to_own_market_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_own_market_cap")), + supply_in_loss_rel_to_circulating_supply: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "supply_in_loss_rel_to_circulating_supply"), + ), + supply_in_loss_rel_to_own_supply: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "supply_in_loss_rel_to_own_supply"), + ), + supply_in_profit_rel_to_circulating_supply: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "supply_in_profit_rel_to_circulating_supply"), + ), + supply_in_profit_rel_to_own_supply: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "supply_in_profit_rel_to_own_supply"), + ), + supply_rel_to_circulating_supply: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "supply_rel_to_circulating_supply"), + ), + unrealized_loss_rel_to_market_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "unrealized_loss_rel_to_market_cap"), + ), + unrealized_loss_rel_to_own_gross_pnl: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "unrealized_loss_rel_to_own_gross_pnl"), + ), + unrealized_loss_rel_to_own_market_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "unrealized_loss_rel_to_own_market_cap"), + ), + unrealized_profit_rel_to_market_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "unrealized_profit_rel_to_market_cap"), + ), + unrealized_profit_rel_to_own_gross_pnl: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "unrealized_profit_rel_to_own_gross_pnl"), + ), + unrealized_profit_rel_to_own_market_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "unrealized_profit_rel_to_own_market_cap"), + ), } } } /// Pattern struct for repeated tree structure. -pub struct Pct05Pct10Pct15Pct20Pct25Pct30Pct35Pct40Pct45Pct50Pct55Pct60Pct65Pct70Pct75Pct80Pct85Pct90Pct95Pattern { +pub struct Pct05Pct10Pct15Pct20Pct25Pct30Pct35Pct40Pct45Pct50Pct55Pct60Pct65Pct70Pct75Pct80Pct85Pct90Pct95Pattern +{ pub pct05: CentsSatsUsdPattern, pub pct10: CentsSatsUsdPattern, pub pct15: CentsSatsUsdPattern, @@ -1725,10 +3268,22 @@ impl RatioPattern { ratio_pct98_price: CentsSatsUsdPattern::new(client.clone(), _m(&acc, "pct98")), ratio_pct99: BpsRatioPattern::new(client.clone(), _m(&acc, "pct99")), ratio_pct99_price: CentsSatsUsdPattern::new(client.clone(), _m(&acc, "pct99")), - ratio_sd: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new(client.clone(), acc.clone()), - ratio_sd_1y: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new(client.clone(), acc.clone()), - ratio_sd_2y: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new(client.clone(), acc.clone()), - ratio_sd_4y: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new(client.clone(), acc.clone()), + ratio_sd: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new( + client.clone(), + acc.clone(), + ), + ratio_sd_1y: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new( + client.clone(), + acc.clone(), + ), + ratio_sd_2y: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new( + client.clone(), + acc.clone(), + ), + ratio_sd_4y: _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern::new( + client.clone(), + acc.clone(), + ), ratio_sma_1m: BpsRatioPattern::new(client.clone(), _m(&acc, "sma_1m")), ratio_sma_1w: BpsRatioPattern::new(client.clone(), _m(&acc, "sma_1w")), } @@ -1761,18 +3316,45 @@ impl GreedGrossInvestedInvestorNegNetPainSupplyUnrealizedPattern { Self { greed_index: CentsUsdPattern::new(client.clone(), _m(&acc, "greed_index")), gross_pnl: CentsUsdPattern::new(client.clone(), _m(&acc, "unrealized_gross_pnl")), - invested_capital_in_loss: CentsUsdPattern::new(client.clone(), _m(&acc, "invested_capital_in_loss")), - invested_capital_in_loss_raw: MetricPattern18::new(client.clone(), _m(&acc, "invested_capital_in_loss_raw")), - invested_capital_in_profit: CentsUsdPattern::new(client.clone(), _m(&acc, "invested_capital_in_profit")), - invested_capital_in_profit_raw: MetricPattern18::new(client.clone(), _m(&acc, "invested_capital_in_profit_raw")), - investor_cap_in_loss_raw: MetricPattern18::new(client.clone(), _m(&acc, "investor_cap_in_loss_raw")), - investor_cap_in_profit_raw: MetricPattern18::new(client.clone(), _m(&acc, "investor_cap_in_profit_raw")), - neg_unrealized_loss: MetricPattern1::new(client.clone(), _m(&acc, "neg_unrealized_loss")), + invested_capital_in_loss: CentsUsdPattern::new( + client.clone(), + _m(&acc, "invested_capital_in_loss"), + ), + invested_capital_in_loss_raw: MetricPattern18::new( + client.clone(), + _m(&acc, "invested_capital_in_loss_raw"), + ), + invested_capital_in_profit: CentsUsdPattern::new( + client.clone(), + _m(&acc, "invested_capital_in_profit"), + ), + invested_capital_in_profit_raw: MetricPattern18::new( + client.clone(), + _m(&acc, "invested_capital_in_profit_raw"), + ), + investor_cap_in_loss_raw: MetricPattern18::new( + client.clone(), + _m(&acc, "investor_cap_in_loss_raw"), + ), + investor_cap_in_profit_raw: MetricPattern18::new( + client.clone(), + _m(&acc, "investor_cap_in_profit_raw"), + ), + neg_unrealized_loss: MetricPattern1::new( + client.clone(), + _m(&acc, "neg_unrealized_loss"), + ), net_sentiment: CentsUsdPattern::new(client.clone(), _m(&acc, "net_sentiment")), - net_unrealized_pnl: CentsUsdPattern::new(client.clone(), _m(&acc, "net_unrealized_pnl")), + net_unrealized_pnl: CentsUsdPattern::new( + client.clone(), + _m(&acc, "net_unrealized_pnl"), + ), pain_index: CentsUsdPattern::new(client.clone(), _m(&acc, "pain_index")), supply_in_loss: BtcCentsSatsUsdPattern::new(client.clone(), _m(&acc, "supply_in_loss")), - supply_in_profit: BtcCentsSatsUsdPattern::new(client.clone(), _m(&acc, "supply_in_profit")), + supply_in_profit: BtcCentsSatsUsdPattern::new( + client.clone(), + _m(&acc, "supply_in_profit"), + ), unrealized_loss: CentsUsdPattern::new(client.clone(), _m(&acc, "unrealized_loss")), unrealized_profit: CentsUsdPattern::new(client.clone(), _m(&acc, "unrealized_profit")), } @@ -1871,18 +3453,51 @@ impl InvestedNegNetNuplSupplyUnrealizedPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - invested_capital_in_loss_rel_to_realized_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "invested_capital_in_loss_rel_to_realized_cap")), - invested_capital_in_profit_rel_to_realized_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "invested_capital_in_profit_rel_to_realized_cap")), - neg_unrealized_loss_rel_to_market_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_market_cap")), - net_unrealized_pnl_rel_to_market_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "net_unrealized_pnl_rel_to_market_cap")), + invested_capital_in_loss_rel_to_realized_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "invested_capital_in_loss_rel_to_realized_cap"), + ), + invested_capital_in_profit_rel_to_realized_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "invested_capital_in_profit_rel_to_realized_cap"), + ), + neg_unrealized_loss_rel_to_market_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "neg_unrealized_loss_rel_to_market_cap"), + ), + net_unrealized_pnl_rel_to_market_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "net_unrealized_pnl_rel_to_market_cap"), + ), nupl: MetricPattern1::new(client.clone(), _m(&acc, "nupl")), - supply_in_loss_rel_to_circulating_supply: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_circulating_supply")), - supply_in_loss_rel_to_own_supply: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_own_supply")), - supply_in_profit_rel_to_circulating_supply: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_circulating_supply")), - supply_in_profit_rel_to_own_supply: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_own_supply")), - supply_rel_to_circulating_supply: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "supply_rel_to_circulating_supply")), - unrealized_loss_rel_to_market_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_market_cap")), - unrealized_profit_rel_to_market_cap: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_market_cap")), + supply_in_loss_rel_to_circulating_supply: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "supply_in_loss_rel_to_circulating_supply"), + ), + supply_in_loss_rel_to_own_supply: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "supply_in_loss_rel_to_own_supply"), + ), + supply_in_profit_rel_to_circulating_supply: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "supply_in_profit_rel_to_circulating_supply"), + ), + supply_in_profit_rel_to_own_supply: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "supply_in_profit_rel_to_own_supply"), + ), + supply_rel_to_circulating_supply: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "supply_rel_to_circulating_supply"), + ), + unrealized_loss_rel_to_market_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "unrealized_loss_rel_to_market_cap"), + ), + unrealized_profit_rel_to_market_cap: BpsPercentRatioPattern::new( + client.clone(), + _m(&acc, "unrealized_profit_rel_to_market_cap"), + ), } } } @@ -1915,7 +3530,10 @@ impl AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern { pct25: MetricPattern18::new(client.clone(), _m(&acc, "pct25")), pct75: MetricPattern18::new(client.clone(), _m(&acc, "pct75")), pct90: MetricPattern18::new(client.clone(), _m(&acc, "pct90")), - rolling: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new(client.clone(), acc.clone()), + rolling: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new( + client.clone(), + acc.clone(), + ), sum: MetricPattern18::new(client.clone(), _m(&acc, "sum")), } } @@ -2183,7 +3801,10 @@ impl BlocksCoinbaseDominanceFeeSubsidyPattern { Self { blocks_mined: CumulativeHeightSumPattern::new(client.clone(), _m(&acc, "blocks_mined")), blocks_mined_sum: _1m1w1y24hPattern::new(client.clone(), _m(&acc, "blocks_mined_sum")), - blocks_since_last_mined: MetricPattern1::new(client.clone(), _m(&acc, "blocks_since_last_mined")), + blocks_since_last_mined: MetricPattern1::new( + client.clone(), + _m(&acc, "blocks_since_last_mined"), + ), coinbase: BaseCumulativeSumPattern::new(client.clone(), _m(&acc, "coinbase")), dominance: BpsPercentRatioPattern::new(client.clone(), _m(&acc, "dominance")), dominance_rolling: _1m1w1y24hPattern2::new(client.clone(), _m(&acc, "dominance")), @@ -2339,10 +3960,22 @@ impl _1m1w1y24hBaseCumulativePattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - _1m: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern2::new(client.clone(), _m(&acc, "1m")), - _1w: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern2::new(client.clone(), _m(&acc, "1w")), - _1y: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern2::new(client.clone(), _m(&acc, "1y")), - _24h: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern2::new(client.clone(), _m(&acc, "24h")), + _1m: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern2::new( + client.clone(), + _m(&acc, "1m"), + ), + _1w: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern2::new( + client.clone(), + _m(&acc, "1w"), + ), + _1y: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern2::new( + client.clone(), + _m(&acc, "1y"), + ), + _24h: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern2::new( + client.clone(), + _m(&acc, "24h"), + ), base: BtcCentsSatsUsdPattern::new(client.clone(), acc.clone()), cumulative: BtcCentsSatsUsdPattern::new(client.clone(), _m(&acc, "cumulative")), } @@ -2363,12 +3996,30 @@ impl BalanceBothReactivatedReceivingSendingPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - balance_decreased: AverageHeightMaxMedianMinPct10Pct25Pct75Pct90Pattern::new(client.clone(), _m(&acc, "balance_decreased")), - balance_increased: AverageHeightMaxMedianMinPct10Pct25Pct75Pct90Pattern::new(client.clone(), _m(&acc, "balance_increased")), - both: AverageHeightMaxMedianMinPct10Pct25Pct75Pct90Pattern::new(client.clone(), _m(&acc, "both")), - reactivated: AverageHeightMaxMedianMinPct10Pct25Pct75Pct90Pattern::new(client.clone(), _m(&acc, "reactivated")), - receiving: AverageHeightMaxMedianMinPct10Pct25Pct75Pct90Pattern::new(client.clone(), _m(&acc, "receiving")), - sending: AverageHeightMaxMedianMinPct10Pct25Pct75Pct90Pattern::new(client.clone(), _m(&acc, "sending")), + balance_decreased: AverageHeightMaxMedianMinPct10Pct25Pct75Pct90Pattern::new( + client.clone(), + _m(&acc, "balance_decreased"), + ), + balance_increased: AverageHeightMaxMedianMinPct10Pct25Pct75Pct90Pattern::new( + client.clone(), + _m(&acc, "balance_increased"), + ), + both: AverageHeightMaxMedianMinPct10Pct25Pct75Pct90Pattern::new( + client.clone(), + _m(&acc, "both"), + ), + reactivated: AverageHeightMaxMedianMinPct10Pct25Pct75Pct90Pattern::new( + client.clone(), + _m(&acc, "reactivated"), + ), + receiving: AverageHeightMaxMedianMinPct10Pct25Pct75Pct90Pattern::new( + client.clone(), + _m(&acc, "receiving"), + ), + sending: AverageHeightMaxMedianMinPct10Pct25Pct75Pct90Pattern::new( + client.clone(), + _m(&acc, "sending"), + ), } } } @@ -2387,9 +4038,18 @@ impl CoinblocksCoindaysSatblocksSatdaysSentPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - coinblocks_destroyed: CumulativeHeightSumPattern::new(client.clone(), _m(&acc, "coinblocks_destroyed")), - coindays_destroyed: CumulativeHeightSumPattern::new(client.clone(), _m(&acc, "coindays_destroyed")), - satblocks_destroyed: MetricPattern18::new(client.clone(), _m(&acc, "satblocks_destroyed")), + coinblocks_destroyed: CumulativeHeightSumPattern::new( + client.clone(), + _m(&acc, "coinblocks_destroyed"), + ), + coindays_destroyed: CumulativeHeightSumPattern::new( + client.clone(), + _m(&acc, "coindays_destroyed"), + ), + satblocks_destroyed: MetricPattern18::new( + client.clone(), + _m(&acc, "satblocks_destroyed"), + ), satdays_destroyed: MetricPattern18::new(client.clone(), _m(&acc, "satdays_destroyed")), sent: BaseCumulativePattern::new(client.clone(), _m(&acc, "sent")), sent_ema: _2wPattern::new(client.clone(), _m(&acc, "sent_ema_2w")), @@ -2552,7 +4212,10 @@ impl BpsPercentRatioPattern2 { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - bps: AverageHeightMaxMedianMinPct10Pct25Pct75Pct90Pattern::new(client.clone(), _m(&acc, "bps")), + bps: AverageHeightMaxMedianMinPct10Pct25Pct75Pct90Pattern::new( + client.clone(), + _m(&acc, "bps"), + ), percent: MetricPattern1::new(client.clone(), acc.clone()), ratio: MetricPattern1::new(client.clone(), _m(&acc, "ratio")), } @@ -2642,7 +4305,10 @@ impl _6bBlockTxindexPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - _6b: AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern::new(client.clone(), _m(&acc, "6b")), + _6b: AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern::new( + client.clone(), + _m(&acc, "6b"), + ), block: AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern::new(client.clone(), acc.clone()), txindex: MetricPattern19::new(client.clone(), acc.clone()), } @@ -2867,7 +4533,10 @@ impl MetricsTree { pub fn new(client: Arc, base_path: String) -> Self { Self { blocks: MetricsTree_Blocks::new(client.clone(), format!("{base_path}_blocks")), - transactions: MetricsTree_Transactions::new(client.clone(), format!("{base_path}_transactions")), + transactions: MetricsTree_Transactions::new( + client.clone(), + format!("{base_path}_transactions"), + ), inputs: MetricsTree_Inputs::new(client.clone(), format!("{base_path}_inputs")), outputs: MetricsTree_Outputs::new(client.clone(), format!("{base_path}_outputs")), addresses: MetricsTree_Addresses::new(client.clone(), format!("{base_path}_addresses")), @@ -2880,7 +4549,10 @@ impl MetricsTree { market: MetricsTree_Market::new(client.clone(), format!("{base_path}_market")), pools: MetricsTree_Pools::new(client.clone(), format!("{base_path}_pools")), prices: MetricsTree_Prices::new(client.clone(), format!("{base_path}_prices")), - distribution: MetricsTree_Distribution::new(client.clone(), format!("{base_path}_distribution")), + distribution: MetricsTree_Distribution::new( + client.clone(), + format!("{base_path}_distribution"), + ), supply: MetricsTree_Supply::new(client.clone(), format!("{base_path}_supply")), } } @@ -2905,14 +4577,26 @@ impl MetricsTree_Blocks { pub fn new(client: Arc, base_path: String) -> Self { Self { blockhash: MetricPattern18::new(client.clone(), "blockhash".to_string()), - difficulty: MetricsTree_Blocks_Difficulty::new(client.clone(), format!("{base_path}_difficulty")), + difficulty: MetricsTree_Blocks_Difficulty::new( + client.clone(), + format!("{base_path}_difficulty"), + ), time: MetricsTree_Blocks_Time::new(client.clone(), format!("{base_path}_time")), total_size: MetricPattern18::new(client.clone(), "total_size".to_string()), weight: MetricsTree_Blocks_Weight::new(client.clone(), format!("{base_path}_weight")), count: MetricsTree_Blocks_Count::new(client.clone(), format!("{base_path}_count")), - interval: AverageHeightMaxMedianMinPct10Pct25Pct75Pct90Pattern::new(client.clone(), "block_interval".to_string()), - halving: MetricsTree_Blocks_Halving::new(client.clone(), format!("{base_path}_halving")), - vbytes: AverageCumulativeHeightMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new(client.clone(), "block_vbytes".to_string()), + interval: AverageHeightMaxMedianMinPct10Pct25Pct75Pct90Pattern::new( + client.clone(), + "block_interval".to_string(), + ), + halving: MetricsTree_Blocks_Halving::new( + client.clone(), + format!("{base_path}_halving"), + ), + vbytes: AverageCumulativeHeightMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new( + client.clone(), + "block_vbytes".to_string(), + ), size: MetricsTree_Blocks_Size::new(client.clone(), format!("{base_path}_size")), fullness: BpsPercentRatioPattern2::new(client.clone(), "block_fullness".to_string()), } @@ -2934,10 +4618,19 @@ impl MetricsTree_Blocks_Difficulty { Self { raw: MetricPattern1::new(client.clone(), "difficulty".to_string()), as_hash: MetricPattern1::new(client.clone(), "difficulty_as_hash".to_string()), - adjustment: BpsPercentRatioPattern::new(client.clone(), "difficulty_adjustment".to_string()), + adjustment: BpsPercentRatioPattern::new( + client.clone(), + "difficulty_adjustment".to_string(), + ), epoch: MetricPattern1::new(client.clone(), "difficulty_epoch".to_string()), - blocks_before_next_adjustment: MetricPattern1::new(client.clone(), "blocks_before_next_difficulty_adjustment".to_string()), - days_before_next_adjustment: MetricPattern1::new(client.clone(), "days_before_next_difficulty_adjustment".to_string()), + blocks_before_next_adjustment: MetricPattern1::new( + client.clone(), + "blocks_before_next_difficulty_adjustment".to_string(), + ), + days_before_next_adjustment: MetricPattern1::new( + client.clone(), + "days_before_next_difficulty_adjustment".to_string(), + ), } } } @@ -2954,7 +4647,10 @@ impl MetricsTree_Blocks_Time { Self { timestamp: MetricPattern1::new(client.clone(), "timestamp".to_string()), date: MetricPattern18::new(client.clone(), "date".to_string()), - timestamp_monotonic: MetricPattern18::new(client.clone(), "timestamp_monotonic".to_string()), + timestamp_monotonic: MetricPattern18::new( + client.clone(), + "timestamp_monotonic".to_string(), + ), } } } @@ -3045,7 +4741,10 @@ pub struct MetricsTree_Blocks_Count { impl MetricsTree_Blocks_Count { pub fn new(client: Arc, base_path: String) -> Self { Self { - block_count_target: MetricPattern1::new(client.clone(), "block_count_target".to_string()), + block_count_target: MetricPattern1::new( + client.clone(), + "block_count_target".to_string(), + ), block_count: CumulativeHeightSumPattern::new(client.clone(), "block_count".to_string()), block_count_sum: _1m1w1y24hPattern::new(client.clone(), "block_count_sum".to_string()), height_1h_ago: MetricPattern18::new(client.clone(), "height_1h_ago".to_string()), @@ -3106,8 +4805,14 @@ impl MetricsTree_Blocks_Halving { pub fn new(client: Arc, base_path: String) -> Self { Self { epoch: MetricPattern1::new(client.clone(), "halving_epoch".to_string()), - blocks_before_next_halving: MetricPattern1::new(client.clone(), "blocks_before_next_halving".to_string()), - days_before_next_halving: MetricPattern1::new(client.clone(), "days_before_next_halving".to_string()), + blocks_before_next_halving: MetricPattern1::new( + client.clone(), + "blocks_before_next_halving".to_string(), + ), + days_before_next_halving: MetricPattern1::new( + client.clone(), + "days_before_next_halving".to_string(), + ), } } } @@ -3172,14 +4877,26 @@ impl MetricsTree_Transactions { rawlocktime: MetricPattern19::new(client.clone(), "rawlocktime".to_string()), base_size: MetricPattern19::new(client.clone(), "base_size".to_string()), total_size: MetricPattern19::new(client.clone(), "total_size".to_string()), - is_explicitly_rbf: MetricPattern19::new(client.clone(), "is_explicitly_rbf".to_string()), + is_explicitly_rbf: MetricPattern19::new( + client.clone(), + "is_explicitly_rbf".to_string(), + ), first_txinindex: MetricPattern19::new(client.clone(), "first_txinindex".to_string()), first_txoutindex: MetricPattern19::new(client.clone(), "first_txoutindex".to_string()), - count: MetricsTree_Transactions_Count::new(client.clone(), format!("{base_path}_count")), + count: MetricsTree_Transactions_Count::new( + client.clone(), + format!("{base_path}_count"), + ), size: MetricsTree_Transactions_Size::new(client.clone(), format!("{base_path}_size")), fees: MetricsTree_Transactions_Fees::new(client.clone(), format!("{base_path}_fees")), - versions: MetricsTree_Transactions_Versions::new(client.clone(), format!("{base_path}_versions")), - volume: MetricsTree_Transactions_Volume::new(client.clone(), format!("{base_path}_volume")), + versions: MetricsTree_Transactions_Versions::new( + client.clone(), + format!("{base_path}_versions"), + ), + volume: MetricsTree_Transactions_Volume::new( + client.clone(), + format!("{base_path}_volume"), + ), } } } @@ -3193,7 +4910,10 @@ pub struct MetricsTree_Transactions_Count { impl MetricsTree_Transactions_Count { pub fn new(client: Arc, base_path: String) -> Self { Self { - tx_count: AverageCumulativeHeightMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new(client.clone(), "tx_count".to_string()), + tx_count: AverageCumulativeHeightMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new( + client.clone(), + "tx_count".to_string(), + ), is_coinbase: MetricPattern19::new(client.clone(), "is_coinbase".to_string()), } } @@ -3264,8 +4984,14 @@ impl MetricsTree_Transactions_Volume { pub fn new(client: Arc, base_path: String) -> Self { Self { sent_sum: _1m1w1y24hBtcCentsSatsUsdPattern::new(client.clone(), "sent_sum".to_string()), - received_sum: _1m1w1y24hBtcCentsSatsUsdPattern::new(client.clone(), "received_sum".to_string()), - annualized_volume: BtcCentsSatsUsdPattern::new(client.clone(), "annualized_volume".to_string()), + received_sum: _1m1w1y24hBtcCentsSatsUsdPattern::new( + client.clone(), + "received_sum".to_string(), + ), + annualized_volume: BtcCentsSatsUsdPattern::new( + client.clone(), + "annualized_volume".to_string(), + ), tx_per_sec: MetricPattern1::new(client.clone(), "tx_per_sec".to_string()), outputs_per_sec: MetricPattern1::new(client.clone(), "outputs_per_sec".to_string()), inputs_per_sec: MetricPattern1::new(client.clone(), "inputs_per_sec".to_string()), @@ -3293,7 +5019,10 @@ impl MetricsTree_Inputs { outputtype: MetricPattern20::new(client.clone(), "outputtype".to_string()), typeindex: MetricPattern20::new(client.clone(), "typeindex".to_string()), spent: MetricsTree_Inputs_Spent::new(client.clone(), format!("{base_path}_spent")), - count: AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern::new(client.clone(), "input_count".to_string()), + count: AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern::new( + client.clone(), + "input_count".to_string(), + ), } } } @@ -3360,7 +5089,10 @@ pub struct MetricsTree_Outputs_Count { impl MetricsTree_Outputs_Count { pub fn new(client: Arc, base_path: String) -> Self { Self { - total_count: AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern::new(client.clone(), "output_count".to_string()), + total_count: AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern::new( + client.clone(), + "output_count".to_string(), + ), utxo_count: MetricPattern1::new(client.clone(), "exact_utxo_count".to_string()), } } @@ -3389,14 +5121,38 @@ pub struct MetricsTree_Addresses { impl MetricsTree_Addresses { pub fn new(client: Arc, base_path: String) -> Self { Self { - first_p2pk65addressindex: MetricPattern18::new(client.clone(), "first_p2pk65addressindex".to_string()), - first_p2pk33addressindex: MetricPattern18::new(client.clone(), "first_p2pk33addressindex".to_string()), - first_p2pkhaddressindex: MetricPattern18::new(client.clone(), "first_p2pkhaddressindex".to_string()), - first_p2shaddressindex: MetricPattern18::new(client.clone(), "first_p2shaddressindex".to_string()), - first_p2wpkhaddressindex: MetricPattern18::new(client.clone(), "first_p2wpkhaddressindex".to_string()), - first_p2wshaddressindex: MetricPattern18::new(client.clone(), "first_p2wshaddressindex".to_string()), - first_p2traddressindex: MetricPattern18::new(client.clone(), "first_p2traddressindex".to_string()), - first_p2aaddressindex: MetricPattern18::new(client.clone(), "first_p2aaddressindex".to_string()), + first_p2pk65addressindex: MetricPattern18::new( + client.clone(), + "first_p2pk65addressindex".to_string(), + ), + first_p2pk33addressindex: MetricPattern18::new( + client.clone(), + "first_p2pk33addressindex".to_string(), + ), + first_p2pkhaddressindex: MetricPattern18::new( + client.clone(), + "first_p2pkhaddressindex".to_string(), + ), + first_p2shaddressindex: MetricPattern18::new( + client.clone(), + "first_p2shaddressindex".to_string(), + ), + first_p2wpkhaddressindex: MetricPattern18::new( + client.clone(), + "first_p2wpkhaddressindex".to_string(), + ), + first_p2wshaddressindex: MetricPattern18::new( + client.clone(), + "first_p2wshaddressindex".to_string(), + ), + first_p2traddressindex: MetricPattern18::new( + client.clone(), + "first_p2traddressindex".to_string(), + ), + first_p2aaddressindex: MetricPattern18::new( + client.clone(), + "first_p2aaddressindex".to_string(), + ), p2pk65bytes: MetricPattern27::new(client.clone(), "p2pk65bytes".to_string()), p2pk33bytes: MetricPattern26::new(client.clone(), "p2pk33bytes".to_string()), p2pkhbytes: MetricPattern28::new(client.clone(), "p2pkhbytes".to_string()), @@ -3427,17 +5183,32 @@ pub struct MetricsTree_Scripts { impl MetricsTree_Scripts { pub fn new(client: Arc, base_path: String) -> Self { Self { - first_emptyoutputindex: MetricPattern18::new(client.clone(), "first_emptyoutputindex".to_string()), - first_opreturnindex: MetricPattern18::new(client.clone(), "first_opreturnindex".to_string()), - first_p2msoutputindex: MetricPattern18::new(client.clone(), "first_p2msoutputindex".to_string()), - first_unknownoutputindex: MetricPattern18::new(client.clone(), "first_unknownoutputindex".to_string()), + first_emptyoutputindex: MetricPattern18::new( + client.clone(), + "first_emptyoutputindex".to_string(), + ), + first_opreturnindex: MetricPattern18::new( + client.clone(), + "first_opreturnindex".to_string(), + ), + first_p2msoutputindex: MetricPattern18::new( + client.clone(), + "first_p2msoutputindex".to_string(), + ), + first_unknownoutputindex: MetricPattern18::new( + client.clone(), + "first_unknownoutputindex".to_string(), + ), empty_to_txindex: MetricPattern22::new(client.clone(), "txindex".to_string()), opreturn_to_txindex: MetricPattern23::new(client.clone(), "txindex".to_string()), p2ms_to_txindex: MetricPattern25::new(client.clone(), "txindex".to_string()), unknown_to_txindex: MetricPattern33::new(client.clone(), "txindex".to_string()), count: MetricsTree_Scripts_Count::new(client.clone(), format!("{base_path}_count")), value: MetricsTree_Scripts_Value::new(client.clone(), format!("{base_path}_value")), - adoption: MetricsTree_Scripts_Adoption::new(client.clone(), format!("{base_path}_adoption")), + adoption: MetricsTree_Scripts_Adoption::new( + client.clone(), + format!("{base_path}_adoption"), + ), } } } @@ -3472,8 +5243,14 @@ impl MetricsTree_Scripts_Count { p2wpkh: CumulativeHeightSumPattern::new(client.clone(), "p2wpkh_count".to_string()), p2wsh: CumulativeHeightSumPattern::new(client.clone(), "p2wsh_count".to_string()), opreturn: CumulativeHeightSumPattern::new(client.clone(), "opreturn_count".to_string()), - emptyoutput: CumulativeHeightSumPattern::new(client.clone(), "emptyoutput_count".to_string()), - unknownoutput: CumulativeHeightSumPattern::new(client.clone(), "unknownoutput_count".to_string()), + emptyoutput: CumulativeHeightSumPattern::new( + client.clone(), + "emptyoutput_count".to_string(), + ), + unknownoutput: CumulativeHeightSumPattern::new( + client.clone(), + "unknownoutput_count".to_string(), + ), segwit: CumulativeHeightSumPattern::new(client.clone(), "segwit_count".to_string()), } } @@ -3487,7 +5264,10 @@ pub struct MetricsTree_Scripts_Value { impl MetricsTree_Scripts_Value { pub fn new(client: Arc, base_path: String) -> Self { Self { - opreturn: _1m1w1y24hBaseCumulativePattern::new(client.clone(), "opreturn_value".to_string()), + opreturn: _1m1w1y24hBaseCumulativePattern::new( + client.clone(), + "opreturn_value".to_string(), + ), } } } @@ -3516,8 +5296,14 @@ pub struct MetricsTree_Mining { impl MetricsTree_Mining { pub fn new(client: Arc, base_path: String) -> Self { Self { - rewards: MetricsTree_Mining_Rewards::new(client.clone(), format!("{base_path}_rewards")), - hashrate: MetricsTree_Mining_Hashrate::new(client.clone(), format!("{base_path}_hashrate")), + rewards: MetricsTree_Mining_Rewards::new( + client.clone(), + format!("{base_path}_rewards"), + ), + hashrate: MetricsTree_Mining_Hashrate::new( + client.clone(), + format!("{base_path}_hashrate"), + ), } } } @@ -3541,11 +5327,23 @@ impl MetricsTree_Mining_Rewards { coinbase: _1m1w1y24hBaseCumulativePattern::new(client.clone(), "coinbase".to_string()), subsidy: _1m1w1y24hBaseCumulativePattern::new(client.clone(), "subsidy".to_string()), fees: _1m1w1y24hBaseCumulativePattern::new(client.clone(), "fees".to_string()), - unclaimed_rewards: BaseCumulativeSumPattern::new(client.clone(), "unclaimed_rewards".to_string()), + unclaimed_rewards: BaseCumulativeSumPattern::new( + client.clone(), + "unclaimed_rewards".to_string(), + ), fee_dominance: BpsPercentRatioPattern::new(client.clone(), "fee_dominance".to_string()), - fee_dominance_rolling: _1m1w1y24hPattern2::new(client.clone(), "fee_dominance".to_string()), - subsidy_dominance: BpsPercentRatioPattern::new(client.clone(), "subsidy_dominance".to_string()), - subsidy_dominance_rolling: _1m1w1y24hPattern2::new(client.clone(), "subsidy_dominance".to_string()), + fee_dominance_rolling: _1m1w1y24hPattern2::new( + client.clone(), + "fee_dominance".to_string(), + ), + subsidy_dominance: BpsPercentRatioPattern::new( + client.clone(), + "subsidy_dominance".to_string(), + ), + subsidy_dominance_rolling: _1m1w1y24hPattern2::new( + client.clone(), + "subsidy_dominance".to_string(), + ), subsidy_sma_1y: CentsUsdPattern::new(client.clone(), "subsidy_sma_1y".to_string()), } } @@ -3581,17 +5379,38 @@ impl MetricsTree_Mining_Hashrate { hash_rate_sma_2m: MetricPattern1::new(client.clone(), "hash_rate_sma_2m".to_string()), hash_rate_sma_1y: MetricPattern1::new(client.clone(), "hash_rate_sma_1y".to_string()), hash_rate_ath: MetricPattern1::new(client.clone(), "hash_rate_ath".to_string()), - hash_rate_drawdown: BpsPercentRatioPattern::new(client.clone(), "hash_rate_drawdown".to_string()), + hash_rate_drawdown: BpsPercentRatioPattern::new( + client.clone(), + "hash_rate_drawdown".to_string(), + ), hash_price_ths: MetricPattern1::new(client.clone(), "hash_price_ths".to_string()), - hash_price_ths_min: MetricPattern1::new(client.clone(), "hash_price_ths_min".to_string()), + hash_price_ths_min: MetricPattern1::new( + client.clone(), + "hash_price_ths_min".to_string(), + ), hash_price_phs: MetricPattern1::new(client.clone(), "hash_price_phs".to_string()), - hash_price_phs_min: MetricPattern1::new(client.clone(), "hash_price_phs_min".to_string()), - hash_price_rebound: BpsPercentRatioPattern::new(client.clone(), "hash_price_rebound".to_string()), + hash_price_phs_min: MetricPattern1::new( + client.clone(), + "hash_price_phs_min".to_string(), + ), + hash_price_rebound: BpsPercentRatioPattern::new( + client.clone(), + "hash_price_rebound".to_string(), + ), hash_value_ths: MetricPattern1::new(client.clone(), "hash_value_ths".to_string()), - hash_value_ths_min: MetricPattern1::new(client.clone(), "hash_value_ths_min".to_string()), + hash_value_ths_min: MetricPattern1::new( + client.clone(), + "hash_value_ths_min".to_string(), + ), hash_value_phs: MetricPattern1::new(client.clone(), "hash_value_phs".to_string()), - hash_value_phs_min: MetricPattern1::new(client.clone(), "hash_value_phs_min".to_string()), - hash_value_rebound: BpsPercentRatioPattern::new(client.clone(), "hash_value_rebound".to_string()), + hash_value_phs_min: MetricPattern1::new( + client.clone(), + "hash_value_phs_min".to_string(), + ), + hash_value_rebound: BpsPercentRatioPattern::new( + client.clone(), + "hash_value_rebound".to_string(), + ), } } } @@ -3625,13 +5444,25 @@ pub struct MetricsTree_Cointime { impl MetricsTree_Cointime { pub fn new(client: Arc, base_path: String) -> Self { Self { - activity: MetricsTree_Cointime_Activity::new(client.clone(), format!("{base_path}_activity")), + activity: MetricsTree_Cointime_Activity::new( + client.clone(), + format!("{base_path}_activity"), + ), supply: MetricsTree_Cointime_Supply::new(client.clone(), format!("{base_path}_supply")), value: MetricsTree_Cointime_Value::new(client.clone(), format!("{base_path}_value")), cap: MetricsTree_Cointime_Cap::new(client.clone(), format!("{base_path}_cap")), - pricing: MetricsTree_Cointime_Pricing::new(client.clone(), format!("{base_path}_pricing")), - adjusted: MetricsTree_Cointime_Adjusted::new(client.clone(), format!("{base_path}_adjusted")), - reserve_risk: MetricsTree_Cointime_ReserveRisk::new(client.clone(), format!("{base_path}_reserve_risk")), + pricing: MetricsTree_Cointime_Pricing::new( + client.clone(), + format!("{base_path}_pricing"), + ), + adjusted: MetricsTree_Cointime_Adjusted::new( + client.clone(), + format!("{base_path}_adjusted"), + ), + reserve_risk: MetricsTree_Cointime_ReserveRisk::new( + client.clone(), + format!("{base_path}_reserve_risk"), + ), } } } @@ -3648,11 +5479,20 @@ pub struct MetricsTree_Cointime_Activity { impl MetricsTree_Cointime_Activity { pub fn new(client: Arc, base_path: String) -> Self { Self { - coinblocks_created: CumulativeHeightSumPattern::new(client.clone(), "coinblocks_created".to_string()), - coinblocks_stored: CumulativeHeightSumPattern::new(client.clone(), "coinblocks_stored".to_string()), + coinblocks_created: CumulativeHeightSumPattern::new( + client.clone(), + "coinblocks_created".to_string(), + ), + coinblocks_stored: CumulativeHeightSumPattern::new( + client.clone(), + "coinblocks_stored".to_string(), + ), liveliness: MetricPattern1::new(client.clone(), "liveliness".to_string()), vaultedness: MetricPattern1::new(client.clone(), "vaultedness".to_string()), - activity_to_vaultedness_ratio: MetricPattern1::new(client.clone(), "activity_to_vaultedness_ratio".to_string()), + activity_to_vaultedness_ratio: MetricPattern1::new( + client.clone(), + "activity_to_vaultedness_ratio".to_string(), + ), } } } @@ -3666,7 +5506,10 @@ pub struct MetricsTree_Cointime_Supply { impl MetricsTree_Cointime_Supply { pub fn new(client: Arc, base_path: String) -> Self { Self { - vaulted_supply: BtcCentsSatsUsdPattern::new(client.clone(), "vaulted_supply".to_string()), + vaulted_supply: BtcCentsSatsUsdPattern::new( + client.clone(), + "vaulted_supply".to_string(), + ), active_supply: BtcCentsSatsUsdPattern::new(client.clone(), "active_supply".to_string()), } } @@ -3683,9 +5526,18 @@ pub struct MetricsTree_Cointime_Value { impl MetricsTree_Cointime_Value { pub fn new(client: Arc, base_path: String) -> Self { Self { - cointime_value_destroyed: CumulativeHeightSumPattern::new(client.clone(), "cointime_value_destroyed".to_string()), - cointime_value_created: CumulativeHeightSumPattern::new(client.clone(), "cointime_value_created".to_string()), - cointime_value_stored: CumulativeHeightSumPattern::new(client.clone(), "cointime_value_stored".to_string()), + cointime_value_destroyed: CumulativeHeightSumPattern::new( + client.clone(), + "cointime_value_destroyed".to_string(), + ), + cointime_value_created: CumulativeHeightSumPattern::new( + client.clone(), + "cointime_value_created".to_string(), + ), + cointime_value_stored: CumulativeHeightSumPattern::new( + client.clone(), + "cointime_value_stored".to_string(), + ), vocdd: CumulativeHeightSumPattern::new(client.clone(), "vocdd".to_string()), } } @@ -3728,13 +5580,28 @@ impl MetricsTree_Cointime_Pricing { pub fn new(client: Arc, base_path: String) -> Self { Self { vaulted_price: CentsSatsUsdPattern::new(client.clone(), "vaulted_price".to_string()), - vaulted_price_ratio: BpsRatioPattern2::new(client.clone(), "vaulted_price_ratio".to_string()), + vaulted_price_ratio: BpsRatioPattern2::new( + client.clone(), + "vaulted_price_ratio".to_string(), + ), active_price: CentsSatsUsdPattern::new(client.clone(), "active_price".to_string()), - active_price_ratio: BpsRatioPattern2::new(client.clone(), "active_price_ratio".to_string()), - true_market_mean: CentsSatsUsdPattern::new(client.clone(), "true_market_mean".to_string()), - true_market_mean_ratio: BpsRatioPattern2::new(client.clone(), "true_market_mean_ratio".to_string()), + active_price_ratio: BpsRatioPattern2::new( + client.clone(), + "active_price_ratio".to_string(), + ), + true_market_mean: CentsSatsUsdPattern::new( + client.clone(), + "true_market_mean".to_string(), + ), + true_market_mean_ratio: BpsRatioPattern2::new( + client.clone(), + "true_market_mean_ratio".to_string(), + ), cointime_price: CentsSatsUsdPattern::new(client.clone(), "cointime_price".to_string()), - cointime_price_ratio: BpsRatioPattern2::new(client.clone(), "cointime_price_ratio".to_string()), + cointime_price_ratio: BpsRatioPattern2::new( + client.clone(), + "cointime_price_ratio".to_string(), + ), } } } @@ -3749,9 +5616,18 @@ pub struct MetricsTree_Cointime_Adjusted { impl MetricsTree_Cointime_Adjusted { pub fn new(client: Arc, base_path: String) -> Self { Self { - cointime_adj_inflation_rate: BpsPercentRatioPattern::new(client.clone(), "cointime_adj_inflation_rate".to_string()), - cointime_adj_tx_velocity_btc: MetricPattern1::new(client.clone(), "cointime_adj_tx_velocity_btc".to_string()), - cointime_adj_tx_velocity_usd: MetricPattern1::new(client.clone(), "cointime_adj_tx_velocity_usd".to_string()), + cointime_adj_inflation_rate: BpsPercentRatioPattern::new( + client.clone(), + "cointime_adj_inflation_rate".to_string(), + ), + cointime_adj_tx_velocity_btc: MetricPattern1::new( + client.clone(), + "cointime_adj_tx_velocity_btc".to_string(), + ), + cointime_adj_tx_velocity_usd: MetricPattern1::new( + client.clone(), + "cointime_adj_tx_velocity_usd".to_string(), + ), } } } @@ -3847,12 +5723,27 @@ pub struct MetricsTree_Indexes { impl MetricsTree_Indexes { pub fn new(client: Arc, base_path: String) -> Self { Self { - address: MetricsTree_Indexes_Address::new(client.clone(), format!("{base_path}_address")), + address: MetricsTree_Indexes_Address::new( + client.clone(), + format!("{base_path}_address"), + ), height: MetricsTree_Indexes_Height::new(client.clone(), format!("{base_path}_height")), - difficultyepoch: MetricsTree_Indexes_Difficultyepoch::new(client.clone(), format!("{base_path}_difficultyepoch")), - halvingepoch: MetricsTree_Indexes_Halvingepoch::new(client.clone(), format!("{base_path}_halvingepoch")), - minute10: MetricsTree_Indexes_Minute10::new(client.clone(), format!("{base_path}_minute10")), - minute30: MetricsTree_Indexes_Minute30::new(client.clone(), format!("{base_path}_minute30")), + difficultyepoch: MetricsTree_Indexes_Difficultyepoch::new( + client.clone(), + format!("{base_path}_difficultyepoch"), + ), + halvingepoch: MetricsTree_Indexes_Halvingepoch::new( + client.clone(), + format!("{base_path}_halvingepoch"), + ), + minute10: MetricsTree_Indexes_Minute10::new( + client.clone(), + format!("{base_path}_minute10"), + ), + minute30: MetricsTree_Indexes_Minute30::new( + client.clone(), + format!("{base_path}_minute30"), + ), hour1: MetricsTree_Indexes_Hour1::new(client.clone(), format!("{base_path}_hour1")), hour4: MetricsTree_Indexes_Hour4::new(client.clone(), format!("{base_path}_hour4")), hour12: MetricsTree_Indexes_Hour12::new(client.clone(), format!("{base_path}_hour12")), @@ -3864,9 +5755,18 @@ impl MetricsTree_Indexes { month6: MetricsTree_Indexes_Month6::new(client.clone(), format!("{base_path}_month6")), year1: MetricsTree_Indexes_Year1::new(client.clone(), format!("{base_path}_year1")), year10: MetricsTree_Indexes_Year10::new(client.clone(), format!("{base_path}_year10")), - txindex: MetricsTree_Indexes_Txindex::new(client.clone(), format!("{base_path}_txindex")), - txinindex: MetricsTree_Indexes_Txinindex::new(client.clone(), format!("{base_path}_txinindex")), - txoutindex: MetricsTree_Indexes_Txoutindex::new(client.clone(), format!("{base_path}_txoutindex")), + txindex: MetricsTree_Indexes_Txindex::new( + client.clone(), + format!("{base_path}_txindex"), + ), + txinindex: MetricsTree_Indexes_Txinindex::new( + client.clone(), + format!("{base_path}_txinindex"), + ), + txoutindex: MetricsTree_Indexes_Txoutindex::new( + client.clone(), + format!("{base_path}_txoutindex"), + ), } } } @@ -3890,18 +5790,51 @@ pub struct MetricsTree_Indexes_Address { impl MetricsTree_Indexes_Address { pub fn new(client: Arc, base_path: String) -> Self { Self { - p2pk33: MetricsTree_Indexes_Address_P2pk33::new(client.clone(), format!("{base_path}_p2pk33")), - p2pk65: MetricsTree_Indexes_Address_P2pk65::new(client.clone(), format!("{base_path}_p2pk65")), - p2pkh: MetricsTree_Indexes_Address_P2pkh::new(client.clone(), format!("{base_path}_p2pkh")), - p2sh: MetricsTree_Indexes_Address_P2sh::new(client.clone(), format!("{base_path}_p2sh")), - p2tr: MetricsTree_Indexes_Address_P2tr::new(client.clone(), format!("{base_path}_p2tr")), - p2wpkh: MetricsTree_Indexes_Address_P2wpkh::new(client.clone(), format!("{base_path}_p2wpkh")), - p2wsh: MetricsTree_Indexes_Address_P2wsh::new(client.clone(), format!("{base_path}_p2wsh")), + p2pk33: MetricsTree_Indexes_Address_P2pk33::new( + client.clone(), + format!("{base_path}_p2pk33"), + ), + p2pk65: MetricsTree_Indexes_Address_P2pk65::new( + client.clone(), + format!("{base_path}_p2pk65"), + ), + p2pkh: MetricsTree_Indexes_Address_P2pkh::new( + client.clone(), + format!("{base_path}_p2pkh"), + ), + p2sh: MetricsTree_Indexes_Address_P2sh::new( + client.clone(), + format!("{base_path}_p2sh"), + ), + p2tr: MetricsTree_Indexes_Address_P2tr::new( + client.clone(), + format!("{base_path}_p2tr"), + ), + p2wpkh: MetricsTree_Indexes_Address_P2wpkh::new( + client.clone(), + format!("{base_path}_p2wpkh"), + ), + p2wsh: MetricsTree_Indexes_Address_P2wsh::new( + client.clone(), + format!("{base_path}_p2wsh"), + ), p2a: MetricsTree_Indexes_Address_P2a::new(client.clone(), format!("{base_path}_p2a")), - p2ms: MetricsTree_Indexes_Address_P2ms::new(client.clone(), format!("{base_path}_p2ms")), - empty: MetricsTree_Indexes_Address_Empty::new(client.clone(), format!("{base_path}_empty")), - unknown: MetricsTree_Indexes_Address_Unknown::new(client.clone(), format!("{base_path}_unknown")), - opreturn: MetricsTree_Indexes_Address_Opreturn::new(client.clone(), format!("{base_path}_opreturn")), + p2ms: MetricsTree_Indexes_Address_P2ms::new( + client.clone(), + format!("{base_path}_p2ms"), + ), + empty: MetricsTree_Indexes_Address_Empty::new( + client.clone(), + format!("{base_path}_empty"), + ), + unknown: MetricsTree_Indexes_Address_Unknown::new( + client.clone(), + format!("{base_path}_unknown"), + ), + opreturn: MetricsTree_Indexes_Address_Opreturn::new( + client.clone(), + format!("{base_path}_opreturn"), + ), } } } @@ -4409,13 +6342,28 @@ impl MetricsTree_Market { pub fn new(client: Arc, base_path: String) -> Self { Self { ath: MetricsTree_Market_Ath::new(client.clone(), format!("{base_path}_ath")), - lookback: MetricsTree_Market_Lookback::new(client.clone(), format!("{base_path}_lookback")), - returns: MetricsTree_Market_Returns::new(client.clone(), format!("{base_path}_returns")), - volatility: MetricsTree_Market_Volatility::new(client.clone(), format!("{base_path}_volatility")), + lookback: MetricsTree_Market_Lookback::new( + client.clone(), + format!("{base_path}_lookback"), + ), + returns: MetricsTree_Market_Returns::new( + client.clone(), + format!("{base_path}_returns"), + ), + volatility: MetricsTree_Market_Volatility::new( + client.clone(), + format!("{base_path}_volatility"), + ), range: MetricsTree_Market_Range::new(client.clone(), format!("{base_path}_range")), - moving_average: MetricsTree_Market_MovingAverage::new(client.clone(), format!("{base_path}_moving_average")), + moving_average: MetricsTree_Market_MovingAverage::new( + client.clone(), + format!("{base_path}_moving_average"), + ), dca: MetricsTree_Market_Dca::new(client.clone(), format!("{base_path}_dca")), - indicators: MetricsTree_Market_Indicators::new(client.clone(), format!("{base_path}_indicators")), + indicators: MetricsTree_Market_Indicators::new( + client.clone(), + format!("{base_path}_indicators"), + ), } } } @@ -4434,11 +6382,26 @@ impl MetricsTree_Market_Ath { pub fn new(client: Arc, base_path: String) -> Self { Self { price_ath: CentsSatsUsdPattern::new(client.clone(), "price_ath".to_string()), - price_drawdown: BpsPercentRatioPattern::new(client.clone(), "price_drawdown".to_string()), - days_since_price_ath: MetricPattern1::new(client.clone(), "days_since_price_ath".to_string()), - years_since_price_ath: MetricPattern2::new(client.clone(), "years_since_price_ath".to_string()), - max_days_between_price_ath: MetricPattern1::new(client.clone(), "max_days_between_price_ath".to_string()), - max_years_between_price_ath: MetricPattern2::new(client.clone(), "max_years_between_price_ath".to_string()), + price_drawdown: BpsPercentRatioPattern::new( + client.clone(), + "price_drawdown".to_string(), + ), + days_since_price_ath: MetricPattern1::new( + client.clone(), + "days_since_price_ath".to_string(), + ), + years_since_price_ath: MetricPattern2::new( + client.clone(), + "years_since_price_ath".to_string(), + ), + max_days_between_price_ath: MetricPattern1::new( + client.clone(), + "max_days_between_price_ath".to_string(), + ), + max_years_between_price_ath: MetricPattern2::new( + client.clone(), + "max_years_between_price_ath".to_string(), + ), } } } @@ -4496,15 +6459,39 @@ pub struct MetricsTree_Market_Returns { impl MetricsTree_Market_Returns { pub fn new(client: Arc, base_path: String) -> Self { Self { - price_return: MetricsTree_Market_Returns_PriceReturn::new(client.clone(), format!("{base_path}_price_return")), + price_return: MetricsTree_Market_Returns_PriceReturn::new( + client.clone(), + format!("{base_path}_price_return"), + ), price_cagr: _10y2y3y4y5y6y8yPattern::new(client.clone(), "price_cagr".to_string()), - price_return_24h_sd_1w: MetricsTree_Market_Returns_PriceReturn24hSd1w::new(client.clone(), format!("{base_path}_price_return_24h_sd_1w")), - price_return_24h_sd_1m: MetricsTree_Market_Returns_PriceReturn24hSd1m::new(client.clone(), format!("{base_path}_price_return_24h_sd_1m")), - price_return_24h_sd_1y: SdSmaPattern::new(client.clone(), "price_return_24h".to_string()), - price_downside_24h: MetricPattern18::new(client.clone(), "price_downside_24h".to_string()), - price_downside_24h_sd_1w: MetricsTree_Market_Returns_PriceDownside24hSd1w::new(client.clone(), format!("{base_path}_price_downside_24h_sd_1w")), - price_downside_24h_sd_1m: MetricsTree_Market_Returns_PriceDownside24hSd1m::new(client.clone(), format!("{base_path}_price_downside_24h_sd_1m")), - price_downside_24h_sd_1y: SdSmaPattern::new(client.clone(), "price_downside_24h".to_string()), + price_return_24h_sd_1w: MetricsTree_Market_Returns_PriceReturn24hSd1w::new( + client.clone(), + format!("{base_path}_price_return_24h_sd_1w"), + ), + price_return_24h_sd_1m: MetricsTree_Market_Returns_PriceReturn24hSd1m::new( + client.clone(), + format!("{base_path}_price_return_24h_sd_1m"), + ), + price_return_24h_sd_1y: SdSmaPattern::new( + client.clone(), + "price_return_24h".to_string(), + ), + price_downside_24h: MetricPattern18::new( + client.clone(), + "price_downside_24h".to_string(), + ), + price_downside_24h_sd_1w: MetricsTree_Market_Returns_PriceDownside24hSd1w::new( + client.clone(), + format!("{base_path}_price_downside_24h_sd_1w"), + ), + price_downside_24h_sd_1m: MetricsTree_Market_Returns_PriceDownside24hSd1m::new( + client.clone(), + format!("{base_path}_price_downside_24h_sd_1m"), + ), + price_downside_24h_sd_1y: SdSmaPattern::new( + client.clone(), + "price_downside_24h".to_string(), + ), } } } @@ -4622,9 +6609,18 @@ pub struct MetricsTree_Market_Volatility { impl MetricsTree_Market_Volatility { pub fn new(client: Arc, base_path: String) -> Self { Self { - price_volatility_1w: MetricPattern1::new(client.clone(), "price_volatility_1w".to_string()), - price_volatility_1m: MetricPattern1::new(client.clone(), "price_volatility_1m".to_string()), - price_volatility_1y: MetricPattern1::new(client.clone(), "price_volatility_1y".to_string()), + price_volatility_1w: MetricPattern1::new( + client.clone(), + "price_volatility_1w".to_string(), + ), + price_volatility_1m: MetricPattern1::new( + client.clone(), + "price_volatility_1m".to_string(), + ), + price_volatility_1y: MetricPattern1::new( + client.clone(), + "price_volatility_1y".to_string(), + ), price_sharpe_1w: MetricPattern1::new(client.clone(), "price_sharpe_1w".to_string()), price_sharpe_1m: MetricPattern1::new(client.clone(), "price_sharpe_1m".to_string()), price_sharpe_1y: MetricPattern1::new(client.clone(), "price_sharpe_1y".to_string()), @@ -4662,8 +6658,14 @@ impl MetricsTree_Market_Range { price_min_1y: CentsSatsUsdPattern::new(client.clone(), "price_min_1y".to_string()), price_max_1y: CentsSatsUsdPattern::new(client.clone(), "price_max_1y".to_string()), price_true_range: MetricPattern1::new(client.clone(), "price_true_range".to_string()), - price_true_range_sum_2w: MetricPattern1::new(client.clone(), "price_true_range_sum_2w".to_string()), - price_choppiness_index_2w: BpsPercentRatioPattern::new(client.clone(), "price_choppiness_index_2w".to_string()), + price_true_range_sum_2w: MetricPattern1::new( + client.clone(), + "price_true_range_sum_2w".to_string(), + ), + price_choppiness_index_2w: BpsPercentRatioPattern::new( + client.clone(), + "price_choppiness_index_2w".to_string(), + ), } } } @@ -4742,9 +6744,18 @@ impl MetricsTree_Market_MovingAverage { price_ema_2y: BpsPriceRatioPattern::new(client.clone(), "price_ema_2y".to_string()), price_ema_200w: BpsPriceRatioPattern::new(client.clone(), "price_ema_200w".to_string()), price_ema_4y: BpsPriceRatioPattern::new(client.clone(), "price_ema_4y".to_string()), - price_sma_200d_x2_4: CentsSatsUsdPattern::new(client.clone(), "price_sma_200d_x2_4".to_string()), - price_sma_200d_x0_8: CentsSatsUsdPattern::new(client.clone(), "price_sma_200d_x0_8".to_string()), - price_sma_350d_x2: CentsSatsUsdPattern::new(client.clone(), "price_sma_350d_x2".to_string()), + price_sma_200d_x2_4: CentsSatsUsdPattern::new( + client.clone(), + "price_sma_200d_x2_4".to_string(), + ), + price_sma_200d_x0_8: CentsSatsUsdPattern::new( + client.clone(), + "price_sma_200d_x0_8".to_string(), + ), + price_sma_350d_x2: CentsSatsUsdPattern::new( + client.clone(), + "price_sma_350d_x2".to_string(), + ), } } } @@ -4767,15 +6778,39 @@ impl MetricsTree_Market_Dca { pub fn new(client: Arc, base_path: String) -> Self { Self { dca_sats_per_day: MetricPattern18::new(client.clone(), "dca_sats_per_day".to_string()), - period_stack: _10y1m1w1y2y3m3y4y5y6m6y8yPattern3::new(client.clone(), "dca_stack".to_string()), - period_cost_basis: MetricsTree_Market_Dca_PeriodCostBasis::new(client.clone(), format!("{base_path}_period_cost_basis")), - period_return: _10y1m1w1y2y3m3y4y5y6m6y8yPattern2::new(client.clone(), "dca_return".to_string()), + period_stack: _10y1m1w1y2y3m3y4y5y6m6y8yPattern3::new( + client.clone(), + "dca_stack".to_string(), + ), + period_cost_basis: MetricsTree_Market_Dca_PeriodCostBasis::new( + client.clone(), + format!("{base_path}_period_cost_basis"), + ), + period_return: _10y1m1w1y2y3m3y4y5y6m6y8yPattern2::new( + client.clone(), + "dca_return".to_string(), + ), period_cagr: _10y2y3y4y5y6y8yPattern::new(client.clone(), "dca_cagr".to_string()), - period_lump_sum_stack: _10y1m1w1y2y3m3y4y5y6m6y8yPattern3::new(client.clone(), "lump_sum_stack".to_string()), - period_lump_sum_return: _10y1m1w1y2y3m3y4y5y6m6y8yPattern2::new(client.clone(), "lump_sum_return".to_string()), - class_stack: MetricsTree_Market_Dca_ClassStack::new(client.clone(), format!("{base_path}_class_stack")), - class_cost_basis: MetricsTree_Market_Dca_ClassCostBasis::new(client.clone(), format!("{base_path}_class_cost_basis")), - class_return: MetricsTree_Market_Dca_ClassReturn::new(client.clone(), format!("{base_path}_class_return")), + period_lump_sum_stack: _10y1m1w1y2y3m3y4y5y6m6y8yPattern3::new( + client.clone(), + "lump_sum_stack".to_string(), + ), + period_lump_sum_return: _10y1m1w1y2y3m3y4y5y6m6y8yPattern2::new( + client.clone(), + "lump_sum_return".to_string(), + ), + class_stack: MetricsTree_Market_Dca_ClassStack::new( + client.clone(), + format!("{base_path}_class_stack"), + ), + class_cost_basis: MetricsTree_Market_Dca_ClassCostBasis::new( + client.clone(), + format!("{base_path}_class_cost_basis"), + ), + class_return: MetricsTree_Market_Dca_ClassReturn::new( + client.clone(), + format!("{base_path}_class_return"), + ), } } } @@ -4834,18 +6869,54 @@ pub struct MetricsTree_Market_Dca_ClassStack { impl MetricsTree_Market_Dca_ClassStack { pub fn new(client: Arc, base_path: String) -> Self { Self { - from_2015: BtcCentsSatsUsdPattern::new(client.clone(), "dca_stack_from_2015".to_string()), - from_2016: BtcCentsSatsUsdPattern::new(client.clone(), "dca_stack_from_2016".to_string()), - from_2017: BtcCentsSatsUsdPattern::new(client.clone(), "dca_stack_from_2017".to_string()), - from_2018: BtcCentsSatsUsdPattern::new(client.clone(), "dca_stack_from_2018".to_string()), - from_2019: BtcCentsSatsUsdPattern::new(client.clone(), "dca_stack_from_2019".to_string()), - from_2020: BtcCentsSatsUsdPattern::new(client.clone(), "dca_stack_from_2020".to_string()), - from_2021: BtcCentsSatsUsdPattern::new(client.clone(), "dca_stack_from_2021".to_string()), - from_2022: BtcCentsSatsUsdPattern::new(client.clone(), "dca_stack_from_2022".to_string()), - from_2023: BtcCentsSatsUsdPattern::new(client.clone(), "dca_stack_from_2023".to_string()), - from_2024: BtcCentsSatsUsdPattern::new(client.clone(), "dca_stack_from_2024".to_string()), - from_2025: BtcCentsSatsUsdPattern::new(client.clone(), "dca_stack_from_2025".to_string()), - from_2026: BtcCentsSatsUsdPattern::new(client.clone(), "dca_stack_from_2026".to_string()), + from_2015: BtcCentsSatsUsdPattern::new( + client.clone(), + "dca_stack_from_2015".to_string(), + ), + from_2016: BtcCentsSatsUsdPattern::new( + client.clone(), + "dca_stack_from_2016".to_string(), + ), + from_2017: BtcCentsSatsUsdPattern::new( + client.clone(), + "dca_stack_from_2017".to_string(), + ), + from_2018: BtcCentsSatsUsdPattern::new( + client.clone(), + "dca_stack_from_2018".to_string(), + ), + from_2019: BtcCentsSatsUsdPattern::new( + client.clone(), + "dca_stack_from_2019".to_string(), + ), + from_2020: BtcCentsSatsUsdPattern::new( + client.clone(), + "dca_stack_from_2020".to_string(), + ), + from_2021: BtcCentsSatsUsdPattern::new( + client.clone(), + "dca_stack_from_2021".to_string(), + ), + from_2022: BtcCentsSatsUsdPattern::new( + client.clone(), + "dca_stack_from_2022".to_string(), + ), + from_2023: BtcCentsSatsUsdPattern::new( + client.clone(), + "dca_stack_from_2023".to_string(), + ), + from_2024: BtcCentsSatsUsdPattern::new( + client.clone(), + "dca_stack_from_2024".to_string(), + ), + from_2025: BtcCentsSatsUsdPattern::new( + client.clone(), + "dca_stack_from_2025".to_string(), + ), + from_2026: BtcCentsSatsUsdPattern::new( + client.clone(), + "dca_stack_from_2026".to_string(), + ), } } } @@ -4869,18 +6940,54 @@ pub struct MetricsTree_Market_Dca_ClassCostBasis { impl MetricsTree_Market_Dca_ClassCostBasis { pub fn new(client: Arc, base_path: String) -> Self { Self { - from_2015: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2015".to_string()), - from_2016: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2016".to_string()), - from_2017: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2017".to_string()), - from_2018: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2018".to_string()), - from_2019: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2019".to_string()), - from_2020: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2020".to_string()), - from_2021: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2021".to_string()), - from_2022: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2022".to_string()), - from_2023: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2023".to_string()), - from_2024: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2024".to_string()), - from_2025: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2025".to_string()), - from_2026: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2026".to_string()), + from_2015: CentsSatsUsdPattern::new( + client.clone(), + "dca_cost_basis_from_2015".to_string(), + ), + from_2016: CentsSatsUsdPattern::new( + client.clone(), + "dca_cost_basis_from_2016".to_string(), + ), + from_2017: CentsSatsUsdPattern::new( + client.clone(), + "dca_cost_basis_from_2017".to_string(), + ), + from_2018: CentsSatsUsdPattern::new( + client.clone(), + "dca_cost_basis_from_2018".to_string(), + ), + from_2019: CentsSatsUsdPattern::new( + client.clone(), + "dca_cost_basis_from_2019".to_string(), + ), + from_2020: CentsSatsUsdPattern::new( + client.clone(), + "dca_cost_basis_from_2020".to_string(), + ), + from_2021: CentsSatsUsdPattern::new( + client.clone(), + "dca_cost_basis_from_2021".to_string(), + ), + from_2022: CentsSatsUsdPattern::new( + client.clone(), + "dca_cost_basis_from_2022".to_string(), + ), + from_2023: CentsSatsUsdPattern::new( + client.clone(), + "dca_cost_basis_from_2023".to_string(), + ), + from_2024: CentsSatsUsdPattern::new( + client.clone(), + "dca_cost_basis_from_2024".to_string(), + ), + from_2025: CentsSatsUsdPattern::new( + client.clone(), + "dca_cost_basis_from_2025".to_string(), + ), + from_2026: CentsSatsUsdPattern::new( + client.clone(), + "dca_cost_basis_from_2026".to_string(), + ), } } } @@ -4904,18 +7011,54 @@ pub struct MetricsTree_Market_Dca_ClassReturn { impl MetricsTree_Market_Dca_ClassReturn { pub fn new(client: Arc, base_path: String) -> Self { Self { - from_2015: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2015".to_string()), - from_2016: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2016".to_string()), - from_2017: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2017".to_string()), - from_2018: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2018".to_string()), - from_2019: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2019".to_string()), - from_2020: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2020".to_string()), - from_2021: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2021".to_string()), - from_2022: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2022".to_string()), - from_2023: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2023".to_string()), - from_2024: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2024".to_string()), - from_2025: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2025".to_string()), - from_2026: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2026".to_string()), + from_2015: BpsPercentRatioPattern::new( + client.clone(), + "dca_return_from_2015".to_string(), + ), + from_2016: BpsPercentRatioPattern::new( + client.clone(), + "dca_return_from_2016".to_string(), + ), + from_2017: BpsPercentRatioPattern::new( + client.clone(), + "dca_return_from_2017".to_string(), + ), + from_2018: BpsPercentRatioPattern::new( + client.clone(), + "dca_return_from_2018".to_string(), + ), + from_2019: BpsPercentRatioPattern::new( + client.clone(), + "dca_return_from_2019".to_string(), + ), + from_2020: BpsPercentRatioPattern::new( + client.clone(), + "dca_return_from_2020".to_string(), + ), + from_2021: BpsPercentRatioPattern::new( + client.clone(), + "dca_return_from_2021".to_string(), + ), + from_2022: BpsPercentRatioPattern::new( + client.clone(), + "dca_return_from_2022".to_string(), + ), + from_2023: BpsPercentRatioPattern::new( + client.clone(), + "dca_return_from_2023".to_string(), + ), + from_2024: BpsPercentRatioPattern::new( + client.clone(), + "dca_return_from_2024".to_string(), + ), + from_2025: BpsPercentRatioPattern::new( + client.clone(), + "dca_return_from_2025".to_string(), + ), + from_2026: BpsPercentRatioPattern::new( + client.clone(), + "dca_return_from_2026".to_string(), + ), } } } @@ -4941,7 +7084,10 @@ impl MetricsTree_Market_Indicators { stoch_k: BpsPercentRatioPattern::new(client.clone(), "stoch_k".to_string()), stoch_d: BpsPercentRatioPattern::new(client.clone(), "stoch_d".to_string()), pi_cycle: BpsRatioPattern::new(client.clone(), "pi_cycle".to_string()), - macd: MetricsTree_Market_Indicators_Macd::new(client.clone(), format!("{base_path}_macd")), + macd: MetricsTree_Market_Indicators_Macd::new( + client.clone(), + format!("{base_path}_macd"), + ), gini: BpsPercentRatioPattern::new(client.clone(), "gini".to_string()), } } @@ -4959,9 +7105,18 @@ impl MetricsTree_Market_Indicators_Rsi { pub fn new(client: Arc, base_path: String) -> Self { Self { _24h: AverageGainsLossesRsiStochPattern::new(client.clone(), "rsi".to_string()), - _1w: MetricsTree_Market_Indicators_Rsi_1w::new(client.clone(), format!("{base_path}_1w")), - _1m: MetricsTree_Market_Indicators_Rsi_1m::new(client.clone(), format!("{base_path}_1m")), - _1y: MetricsTree_Market_Indicators_Rsi_1y::new(client.clone(), format!("{base_path}_1y")), + _1w: MetricsTree_Market_Indicators_Rsi_1w::new( + client.clone(), + format!("{base_path}_1w"), + ), + _1m: MetricsTree_Market_Indicators_Rsi_1m::new( + client.clone(), + format!("{base_path}_1m"), + ), + _1y: MetricsTree_Market_Indicators_Rsi_1y::new( + client.clone(), + format!("{base_path}_1y"), + ), } } } @@ -5071,9 +7226,18 @@ impl MetricsTree_Market_Indicators_Macd { pub fn new(client: Arc, base_path: String) -> Self { Self { _24h: EmaHistogramLineSignalPattern::new(client.clone(), "macd".to_string()), - _1w: MetricsTree_Market_Indicators_Macd_1w::new(client.clone(), format!("{base_path}_1w")), - _1m: MetricsTree_Market_Indicators_Macd_1m::new(client.clone(), format!("{base_path}_1m")), - _1y: MetricsTree_Market_Indicators_Macd_1y::new(client.clone(), format!("{base_path}_1y")), + _1w: MetricsTree_Market_Indicators_Macd_1w::new( + client.clone(), + format!("{base_path}_1w"), + ), + _1m: MetricsTree_Market_Indicators_Macd_1m::new( + client.clone(), + format!("{base_path}_1m"), + ), + _1y: MetricsTree_Market_Indicators_Macd_1y::new( + client.clone(), + format!("{base_path}_1y"), + ), } } } @@ -5325,168 +7489,639 @@ pub struct MetricsTree_Pools_Vecs { impl MetricsTree_Pools_Vecs { pub fn new(client: Arc, base_path: String) -> Self { Self { - unknown: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "unknown".to_string()), - blockfills: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "blockfills".to_string()), - ultimuspool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "ultimuspool".to_string()), - terrapool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "terrapool".to_string()), - luxor: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "luxor".to_string()), - onethash: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "onethash".to_string()), - btccom: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "btccom".to_string()), - bitfarms: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "bitfarms".to_string()), - huobipool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "huobipool".to_string()), - wayicn: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "wayicn".to_string()), - canoepool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "canoepool".to_string()), - btctop: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "btctop".to_string()), - bitcoincom: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "bitcoincom".to_string()), - pool175btc: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "pool175btc".to_string()), - gbminers: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "gbminers".to_string()), + unknown: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "unknown".to_string(), + ), + blockfills: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "blockfills".to_string(), + ), + ultimuspool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "ultimuspool".to_string(), + ), + terrapool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "terrapool".to_string(), + ), + luxor: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "luxor".to_string(), + ), + onethash: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "onethash".to_string(), + ), + btccom: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "btccom".to_string(), + ), + bitfarms: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "bitfarms".to_string(), + ), + huobipool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "huobipool".to_string(), + ), + wayicn: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "wayicn".to_string(), + ), + canoepool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "canoepool".to_string(), + ), + btctop: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "btctop".to_string(), + ), + bitcoincom: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "bitcoincom".to_string(), + ), + pool175btc: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "pool175btc".to_string(), + ), + gbminers: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "gbminers".to_string(), + ), axbt: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "axbt".to_string()), - asicminer: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "asicminer".to_string()), - bitminter: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "bitminter".to_string()), - bitcoinrussia: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "bitcoinrussia".to_string()), - btcserv: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "btcserv".to_string()), - simplecoinus: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "simplecoinus".to_string()), - btcguild: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "btcguild".to_string()), - eligius: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "eligius".to_string()), - ozcoin: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "ozcoin".to_string()), - eclipsemc: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "eclipsemc".to_string()), - maxbtc: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "maxbtc".to_string()), - triplemining: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "triplemining".to_string()), - coinlab: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "coinlab".to_string()), - pool50btc: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "pool50btc".to_string()), - ghashio: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "ghashio".to_string()), - stminingcorp: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "stminingcorp".to_string()), - bitparking: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "bitparking".to_string()), - mmpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "mmpool".to_string()), - polmine: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "polmine".to_string()), - kncminer: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "kncminer".to_string()), - bitalo: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "bitalo".to_string()), - f2pool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "f2pool".to_string()), + asicminer: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "asicminer".to_string(), + ), + bitminter: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "bitminter".to_string(), + ), + bitcoinrussia: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "bitcoinrussia".to_string(), + ), + btcserv: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "btcserv".to_string(), + ), + simplecoinus: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "simplecoinus".to_string(), + ), + btcguild: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "btcguild".to_string(), + ), + eligius: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "eligius".to_string(), + ), + ozcoin: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "ozcoin".to_string(), + ), + eclipsemc: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "eclipsemc".to_string(), + ), + maxbtc: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "maxbtc".to_string(), + ), + triplemining: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "triplemining".to_string(), + ), + coinlab: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "coinlab".to_string(), + ), + pool50btc: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "pool50btc".to_string(), + ), + ghashio: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "ghashio".to_string(), + ), + stminingcorp: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "stminingcorp".to_string(), + ), + bitparking: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "bitparking".to_string(), + ), + mmpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "mmpool".to_string(), + ), + polmine: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "polmine".to_string(), + ), + kncminer: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "kncminer".to_string(), + ), + bitalo: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "bitalo".to_string(), + ), + f2pool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "f2pool".to_string(), + ), hhtt: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "hhtt".to_string()), - megabigpower: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "megabigpower".to_string()), - mtred: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "mtred".to_string()), - nmcbit: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "nmcbit".to_string()), - yourbtcnet: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "yourbtcnet".to_string()), - givemecoins: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "givemecoins".to_string()), - braiinspool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "braiinspool".to_string()), - antpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "antpool".to_string()), - multicoinco: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "multicoinco".to_string()), - bcpoolio: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "bcpoolio".to_string()), - cointerra: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "cointerra".to_string()), - kanopool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "kanopool".to_string()), - solock: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "solock".to_string()), - ckpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "ckpool".to_string()), - nicehash: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "nicehash".to_string()), - bitclub: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "bitclub".to_string()), - bitcoinaffiliatenetwork: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "bitcoinaffiliatenetwork".to_string()), + megabigpower: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "megabigpower".to_string(), + ), + mtred: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "mtred".to_string(), + ), + nmcbit: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "nmcbit".to_string(), + ), + yourbtcnet: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "yourbtcnet".to_string(), + ), + givemecoins: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "givemecoins".to_string(), + ), + braiinspool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "braiinspool".to_string(), + ), + antpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "antpool".to_string(), + ), + multicoinco: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "multicoinco".to_string(), + ), + bcpoolio: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "bcpoolio".to_string(), + ), + cointerra: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "cointerra".to_string(), + ), + kanopool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "kanopool".to_string(), + ), + solock: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "solock".to_string(), + ), + ckpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "ckpool".to_string(), + ), + nicehash: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "nicehash".to_string(), + ), + bitclub: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "bitclub".to_string(), + ), + bitcoinaffiliatenetwork: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "bitcoinaffiliatenetwork".to_string(), + ), btcc: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "btcc".to_string()), - bwpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "bwpool".to_string()), - exxbw: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "exxbw".to_string()), - bitsolo: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "bitsolo".to_string()), - bitfury: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "bitfury".to_string()), - twentyoneinc: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "twentyoneinc".to_string()), - digitalbtc: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "digitalbtc".to_string()), - eightbaochi: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "eightbaochi".to_string()), - mybtccoinpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "mybtccoinpool".to_string()), - tbdice: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "tbdice".to_string()), - hashpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "hashpool".to_string()), - nexious: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "nexious".to_string()), - bravomining: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "bravomining".to_string()), - hotpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "hotpool".to_string()), - okexpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "okexpool".to_string()), - bcmonster: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "bcmonster".to_string()), - onehash: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "onehash".to_string()), - bixin: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "bixin".to_string()), - tatmaspool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "tatmaspool".to_string()), - viabtc: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "viabtc".to_string()), - connectbtc: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "connectbtc".to_string()), - batpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "batpool".to_string()), - waterhole: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "waterhole".to_string()), - dcexploration: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "dcexploration".to_string()), + bwpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "bwpool".to_string(), + ), + exxbw: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "exxbw".to_string(), + ), + bitsolo: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "bitsolo".to_string(), + ), + bitfury: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "bitfury".to_string(), + ), + twentyoneinc: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "twentyoneinc".to_string(), + ), + digitalbtc: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "digitalbtc".to_string(), + ), + eightbaochi: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "eightbaochi".to_string(), + ), + mybtccoinpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "mybtccoinpool".to_string(), + ), + tbdice: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "tbdice".to_string(), + ), + hashpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "hashpool".to_string(), + ), + nexious: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "nexious".to_string(), + ), + bravomining: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "bravomining".to_string(), + ), + hotpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "hotpool".to_string(), + ), + okexpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "okexpool".to_string(), + ), + bcmonster: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "bcmonster".to_string(), + ), + onehash: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "onehash".to_string(), + ), + bixin: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "bixin".to_string(), + ), + tatmaspool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "tatmaspool".to_string(), + ), + viabtc: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "viabtc".to_string(), + ), + connectbtc: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "connectbtc".to_string(), + ), + batpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "batpool".to_string(), + ), + waterhole: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "waterhole".to_string(), + ), + dcexploration: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "dcexploration".to_string(), + ), dcex: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "dcex".to_string()), - btpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "btpool".to_string()), - fiftyeightcoin: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "fiftyeightcoin".to_string()), - bitcoinindia: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "bitcoinindia".to_string()), - shawnp0wers: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "shawnp0wers".to_string()), - phashio: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "phashio".to_string()), - rigpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "rigpool".to_string()), - haozhuzhu: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "haozhuzhu".to_string()), - sevenpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "sevenpool".to_string()), - miningkings: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "miningkings".to_string()), - hashbx: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "hashbx".to_string()), - dpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "dpool".to_string()), - rawpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "rawpool".to_string()), - haominer: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "haominer".to_string()), - helix: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "helix".to_string()), - bitcoinukraine: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "bitcoinukraine".to_string()), - poolin: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "poolin".to_string()), - secretsuperstar: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "secretsuperstar".to_string()), - tigerpoolnet: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "tigerpoolnet".to_string()), - sigmapoolcom: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "sigmapoolcom".to_string()), - okpooltop: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "okpooltop".to_string()), - hummerpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "hummerpool".to_string()), - tangpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "tangpool".to_string()), - bytepool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "bytepool".to_string()), - spiderpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "spiderpool".to_string()), - novablock: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "novablock".to_string()), - miningcity: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "miningcity".to_string()), - binancepool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "binancepool".to_string()), - minerium: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "minerium".to_string()), - lubiancom: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "lubiancom".to_string()), - okkong: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "okkong".to_string()), - aaopool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "aaopool".to_string()), - emcdpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "emcdpool".to_string()), - foundryusa: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "foundryusa".to_string()), - sbicrypto: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "sbicrypto".to_string()), - arkpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "arkpool".to_string()), - purebtccom: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "purebtccom".to_string()), - marapool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "marapool".to_string()), - kucoinpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "kucoinpool".to_string()), - entrustcharitypool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "entrustcharitypool".to_string()), - okminer: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "okminer".to_string()), - titan: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "titan".to_string()), - pegapool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "pegapool".to_string()), - btcnuggets: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "btcnuggets".to_string()), - cloudhashing: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "cloudhashing".to_string()), - digitalxmintsy: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "digitalxmintsy".to_string()), - telco214: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "telco214".to_string()), - btcpoolparty: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "btcpoolparty".to_string()), - multipool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "multipool".to_string()), - transactioncoinmining: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "transactioncoinmining".to_string()), - btcdig: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "btcdig".to_string()), - trickysbtcpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "trickysbtcpool".to_string()), - btcmp: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "btcmp".to_string()), - eobot: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "eobot".to_string()), - unomp: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "unomp".to_string()), - patels: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "patels".to_string()), - gogreenlight: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "gogreenlight".to_string()), - bitcoinindiapool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "bitcoinindiapool".to_string()), - ekanembtc: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "ekanembtc".to_string()), - canoe: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "canoe".to_string()), - tiger: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "tiger".to_string()), - onem1x: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "onem1x".to_string()), - zulupool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "zulupool".to_string()), - secpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "secpool".to_string()), - ocean: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "ocean".to_string()), - whitepool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "whitepool".to_string()), + btpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "btpool".to_string(), + ), + fiftyeightcoin: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "fiftyeightcoin".to_string(), + ), + bitcoinindia: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "bitcoinindia".to_string(), + ), + shawnp0wers: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "shawnp0wers".to_string(), + ), + phashio: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "phashio".to_string(), + ), + rigpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "rigpool".to_string(), + ), + haozhuzhu: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "haozhuzhu".to_string(), + ), + sevenpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "sevenpool".to_string(), + ), + miningkings: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "miningkings".to_string(), + ), + hashbx: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "hashbx".to_string(), + ), + dpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "dpool".to_string(), + ), + rawpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "rawpool".to_string(), + ), + haominer: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "haominer".to_string(), + ), + helix: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "helix".to_string(), + ), + bitcoinukraine: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "bitcoinukraine".to_string(), + ), + poolin: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "poolin".to_string(), + ), + secretsuperstar: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "secretsuperstar".to_string(), + ), + tigerpoolnet: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "tigerpoolnet".to_string(), + ), + sigmapoolcom: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "sigmapoolcom".to_string(), + ), + okpooltop: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "okpooltop".to_string(), + ), + hummerpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "hummerpool".to_string(), + ), + tangpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "tangpool".to_string(), + ), + bytepool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "bytepool".to_string(), + ), + spiderpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "spiderpool".to_string(), + ), + novablock: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "novablock".to_string(), + ), + miningcity: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "miningcity".to_string(), + ), + binancepool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "binancepool".to_string(), + ), + minerium: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "minerium".to_string(), + ), + lubiancom: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "lubiancom".to_string(), + ), + okkong: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "okkong".to_string(), + ), + aaopool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "aaopool".to_string(), + ), + emcdpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "emcdpool".to_string(), + ), + foundryusa: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "foundryusa".to_string(), + ), + sbicrypto: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "sbicrypto".to_string(), + ), + arkpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "arkpool".to_string(), + ), + purebtccom: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "purebtccom".to_string(), + ), + marapool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "marapool".to_string(), + ), + kucoinpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "kucoinpool".to_string(), + ), + entrustcharitypool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "entrustcharitypool".to_string(), + ), + okminer: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "okminer".to_string(), + ), + titan: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "titan".to_string(), + ), + pegapool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "pegapool".to_string(), + ), + btcnuggets: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "btcnuggets".to_string(), + ), + cloudhashing: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "cloudhashing".to_string(), + ), + digitalxmintsy: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "digitalxmintsy".to_string(), + ), + telco214: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "telco214".to_string(), + ), + btcpoolparty: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "btcpoolparty".to_string(), + ), + multipool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "multipool".to_string(), + ), + transactioncoinmining: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "transactioncoinmining".to_string(), + ), + btcdig: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "btcdig".to_string(), + ), + trickysbtcpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "trickysbtcpool".to_string(), + ), + btcmp: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "btcmp".to_string(), + ), + eobot: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "eobot".to_string(), + ), + unomp: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "unomp".to_string(), + ), + patels: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "patels".to_string(), + ), + gogreenlight: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "gogreenlight".to_string(), + ), + bitcoinindiapool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "bitcoinindiapool".to_string(), + ), + ekanembtc: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "ekanembtc".to_string(), + ), + canoe: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "canoe".to_string(), + ), + tiger: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "tiger".to_string(), + ), + onem1x: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "onem1x".to_string(), + ), + zulupool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "zulupool".to_string(), + ), + secpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "secpool".to_string(), + ), + ocean: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "ocean".to_string(), + ), + whitepool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "whitepool".to_string(), + ), wiz: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "wiz".to_string()), - wk057: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "wk057".to_string()), - futurebitapollosolo: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "futurebitapollosolo".to_string()), - carbonnegative: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "carbonnegative".to_string()), - portlandhodl: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "portlandhodl".to_string()), - phoenix: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "phoenix".to_string()), - neopool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "neopool".to_string()), - maxipool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "maxipool".to_string()), - bitfufupool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "bitfufupool".to_string()), - gdpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "gdpool".to_string()), - miningdutch: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "miningdutch".to_string()), - publicpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "publicpool".to_string()), - miningsquared: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "miningsquared".to_string()), - innopolistech: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "innopolistech".to_string()), - btclab: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "btclab".to_string()), - parasite: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "parasite".to_string()), - redrockpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "redrockpool".to_string()), - est3lar: BlocksCoinbaseDominanceFeeSubsidyPattern::new(client.clone(), "est3lar".to_string()), + wk057: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "wk057".to_string(), + ), + futurebitapollosolo: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "futurebitapollosolo".to_string(), + ), + carbonnegative: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "carbonnegative".to_string(), + ), + portlandhodl: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "portlandhodl".to_string(), + ), + phoenix: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "phoenix".to_string(), + ), + neopool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "neopool".to_string(), + ), + maxipool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "maxipool".to_string(), + ), + bitfufupool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "bitfufupool".to_string(), + ), + gdpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "gdpool".to_string(), + ), + miningdutch: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "miningdutch".to_string(), + ), + publicpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "publicpool".to_string(), + ), + miningsquared: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "miningsquared".to_string(), + ), + innopolistech: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "innopolistech".to_string(), + ), + btclab: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "btclab".to_string(), + ), + parasite: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "parasite".to_string(), + ), + redrockpool: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "redrockpool".to_string(), + ), + est3lar: BlocksCoinbaseDominanceFeeSubsidyPattern::new( + client.clone(), + "est3lar".to_string(), + ), } } } @@ -5522,7 +8157,10 @@ impl MetricsTree_Prices_Split { open: CentsSatsUsdPattern2::new(client.clone(), "price_open".to_string()), high: CentsSatsUsdPattern2::new(client.clone(), "price_high".to_string()), low: CentsSatsUsdPattern2::new(client.clone(), "price_low".to_string()), - close: MetricsTree_Prices_Split_Close::new(client.clone(), format!("{base_path}_close")), + close: MetricsTree_Prices_Split_Close::new( + client.clone(), + format!("{base_path}_close"), + ), } } } @@ -5599,18 +8237,54 @@ impl MetricsTree_Distribution { pub fn new(client: Arc, base_path: String) -> Self { Self { supply_state: MetricPattern18::new(client.clone(), "supply_state".to_string()), - any_address_indexes: MetricsTree_Distribution_AnyAddressIndexes::new(client.clone(), format!("{base_path}_any_address_indexes")), - addresses_data: MetricsTree_Distribution_AddressesData::new(client.clone(), format!("{base_path}_addresses_data")), - utxo_cohorts: MetricsTree_Distribution_UtxoCohorts::new(client.clone(), format!("{base_path}_utxo_cohorts")), - address_cohorts: MetricsTree_Distribution_AddressCohorts::new(client.clone(), format!("{base_path}_address_cohorts")), - addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern::new(client.clone(), "addr_count".to_string()), - empty_addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern::new(client.clone(), "empty_addr_count".to_string()), - address_activity: MetricsTree_Distribution_AddressActivity::new(client.clone(), format!("{base_path}_address_activity")), - total_addr_count: MetricsTree_Distribution_TotalAddrCount::new(client.clone(), format!("{base_path}_total_addr_count")), - new_addr_count: MetricsTree_Distribution_NewAddrCount::new(client.clone(), format!("{base_path}_new_addr_count")), - growth_rate: MetricsTree_Distribution_GrowthRate::new(client.clone(), format!("{base_path}_growth_rate")), - fundedaddressindex: MetricPattern34::new(client.clone(), "fundedaddressindex".to_string()), - emptyaddressindex: MetricPattern35::new(client.clone(), "emptyaddressindex".to_string()), + any_address_indexes: MetricsTree_Distribution_AnyAddressIndexes::new( + client.clone(), + format!("{base_path}_any_address_indexes"), + ), + addresses_data: MetricsTree_Distribution_AddressesData::new( + client.clone(), + format!("{base_path}_addresses_data"), + ), + utxo_cohorts: MetricsTree_Distribution_UtxoCohorts::new( + client.clone(), + format!("{base_path}_utxo_cohorts"), + ), + address_cohorts: MetricsTree_Distribution_AddressCohorts::new( + client.clone(), + format!("{base_path}_address_cohorts"), + ), + addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern::new( + client.clone(), + "addr_count".to_string(), + ), + empty_addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern::new( + client.clone(), + "empty_addr_count".to_string(), + ), + address_activity: MetricsTree_Distribution_AddressActivity::new( + client.clone(), + format!("{base_path}_address_activity"), + ), + total_addr_count: MetricsTree_Distribution_TotalAddrCount::new( + client.clone(), + format!("{base_path}_total_addr_count"), + ), + new_addr_count: MetricsTree_Distribution_NewAddrCount::new( + client.clone(), + format!("{base_path}_new_addr_count"), + ), + growth_rate: MetricsTree_Distribution_GrowthRate::new( + client.clone(), + format!("{base_path}_growth_rate"), + ), + fundedaddressindex: MetricPattern34::new( + client.clone(), + "fundedaddressindex".to_string(), + ), + emptyaddressindex: MetricPattern35::new( + client.clone(), + "emptyaddressindex".to_string(), + ), } } } @@ -5676,18 +8350,54 @@ pub struct MetricsTree_Distribution_UtxoCohorts { impl MetricsTree_Distribution_UtxoCohorts { pub fn new(client: Arc, base_path: String) -> Self { Self { - all: MetricsTree_Distribution_UtxoCohorts_All::new(client.clone(), format!("{base_path}_all")), - sth: MetricsTree_Distribution_UtxoCohorts_Sth::new(client.clone(), format!("{base_path}_sth")), - lth: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "lth".to_string()), - age_range: MetricsTree_Distribution_UtxoCohorts_AgeRange::new(client.clone(), format!("{base_path}_age_range")), - max_age: MetricsTree_Distribution_UtxoCohorts_MaxAge::new(client.clone(), format!("{base_path}_max_age")), - min_age: MetricsTree_Distribution_UtxoCohorts_MinAge::new(client.clone(), format!("{base_path}_min_age")), - ge_amount: MetricsTree_Distribution_UtxoCohorts_GeAmount::new(client.clone(), format!("{base_path}_ge_amount")), - amount_range: MetricsTree_Distribution_UtxoCohorts_AmountRange::new(client.clone(), format!("{base_path}_amount_range")), - lt_amount: MetricsTree_Distribution_UtxoCohorts_LtAmount::new(client.clone(), format!("{base_path}_lt_amount")), - epoch: MetricsTree_Distribution_UtxoCohorts_Epoch::new(client.clone(), format!("{base_path}_epoch")), - year: MetricsTree_Distribution_UtxoCohorts_Year::new(client.clone(), format!("{base_path}_year")), - type_: MetricsTree_Distribution_UtxoCohorts_Type::new(client.clone(), format!("{base_path}_type_")), + all: MetricsTree_Distribution_UtxoCohorts_All::new( + client.clone(), + format!("{base_path}_all"), + ), + sth: MetricsTree_Distribution_UtxoCohorts_Sth::new( + client.clone(), + format!("{base_path}_sth"), + ), + lth: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "lth".to_string(), + ), + age_range: MetricsTree_Distribution_UtxoCohorts_AgeRange::new( + client.clone(), + format!("{base_path}_age_range"), + ), + max_age: MetricsTree_Distribution_UtxoCohorts_MaxAge::new( + client.clone(), + format!("{base_path}_max_age"), + ), + min_age: MetricsTree_Distribution_UtxoCohorts_MinAge::new( + client.clone(), + format!("{base_path}_min_age"), + ), + ge_amount: MetricsTree_Distribution_UtxoCohorts_GeAmount::new( + client.clone(), + format!("{base_path}_ge_amount"), + ), + amount_range: MetricsTree_Distribution_UtxoCohorts_AmountRange::new( + client.clone(), + format!("{base_path}_amount_range"), + ), + lt_amount: MetricsTree_Distribution_UtxoCohorts_LtAmount::new( + client.clone(), + format!("{base_path}_lt_amount"), + ), + epoch: MetricsTree_Distribution_UtxoCohorts_Epoch::new( + client.clone(), + format!("{base_path}_epoch"), + ), + year: MetricsTree_Distribution_UtxoCohorts_Year::new( + client.clone(), + format!("{base_path}_year"), + ), + type_: MetricsTree_Distribution_UtxoCohorts_Type::new( + client.clone(), + format!("{base_path}_type_"), + ), } } } @@ -5737,19 +8447,55 @@ pub struct MetricsTree_Distribution_UtxoCohorts_All_Relative { impl MetricsTree_Distribution_UtxoCohorts_All_Relative { pub fn new(client: Arc, base_path: String) -> Self { Self { - supply_in_profit_rel_to_own_supply: BpsPercentRatioPattern::new(client.clone(), "supply_in_profit_rel_to_own_supply".to_string()), - supply_in_loss_rel_to_own_supply: BpsPercentRatioPattern::new(client.clone(), "supply_in_loss_rel_to_own_supply".to_string()), - unrealized_profit_rel_to_market_cap: BpsPercentRatioPattern::new(client.clone(), "unrealized_profit_rel_to_market_cap".to_string()), - unrealized_loss_rel_to_market_cap: BpsPercentRatioPattern::new(client.clone(), "unrealized_loss_rel_to_market_cap".to_string()), - neg_unrealized_loss_rel_to_market_cap: BpsPercentRatioPattern::new(client.clone(), "neg_unrealized_loss_rel_to_market_cap".to_string()), - net_unrealized_pnl_rel_to_market_cap: BpsPercentRatioPattern::new(client.clone(), "net_unrealized_pnl_rel_to_market_cap".to_string()), + supply_in_profit_rel_to_own_supply: BpsPercentRatioPattern::new( + client.clone(), + "supply_in_profit_rel_to_own_supply".to_string(), + ), + supply_in_loss_rel_to_own_supply: BpsPercentRatioPattern::new( + client.clone(), + "supply_in_loss_rel_to_own_supply".to_string(), + ), + unrealized_profit_rel_to_market_cap: BpsPercentRatioPattern::new( + client.clone(), + "unrealized_profit_rel_to_market_cap".to_string(), + ), + unrealized_loss_rel_to_market_cap: BpsPercentRatioPattern::new( + client.clone(), + "unrealized_loss_rel_to_market_cap".to_string(), + ), + neg_unrealized_loss_rel_to_market_cap: BpsPercentRatioPattern::new( + client.clone(), + "neg_unrealized_loss_rel_to_market_cap".to_string(), + ), + net_unrealized_pnl_rel_to_market_cap: BpsPercentRatioPattern::new( + client.clone(), + "net_unrealized_pnl_rel_to_market_cap".to_string(), + ), nupl: MetricPattern1::new(client.clone(), "nupl".to_string()), - invested_capital_in_profit_rel_to_realized_cap: BpsPercentRatioPattern::new(client.clone(), "invested_capital_in_profit_rel_to_realized_cap".to_string()), - invested_capital_in_loss_rel_to_realized_cap: BpsPercentRatioPattern::new(client.clone(), "invested_capital_in_loss_rel_to_realized_cap".to_string()), - unrealized_profit_rel_to_own_gross_pnl: BpsPercentRatioPattern::new(client.clone(), "unrealized_profit_rel_to_own_gross_pnl".to_string()), - unrealized_loss_rel_to_own_gross_pnl: BpsPercentRatioPattern::new(client.clone(), "unrealized_loss_rel_to_own_gross_pnl".to_string()), - neg_unrealized_loss_rel_to_own_gross_pnl: BpsPercentRatioPattern::new(client.clone(), "neg_unrealized_loss_rel_to_own_gross_pnl".to_string()), - net_unrealized_pnl_rel_to_own_gross_pnl: BpsPercentRatioPattern::new(client.clone(), "net_unrealized_pnl_rel_to_own_gross_pnl".to_string()), + invested_capital_in_profit_rel_to_realized_cap: BpsPercentRatioPattern::new( + client.clone(), + "invested_capital_in_profit_rel_to_realized_cap".to_string(), + ), + invested_capital_in_loss_rel_to_realized_cap: BpsPercentRatioPattern::new( + client.clone(), + "invested_capital_in_loss_rel_to_realized_cap".to_string(), + ), + unrealized_profit_rel_to_own_gross_pnl: BpsPercentRatioPattern::new( + client.clone(), + "unrealized_profit_rel_to_own_gross_pnl".to_string(), + ), + unrealized_loss_rel_to_own_gross_pnl: BpsPercentRatioPattern::new( + client.clone(), + "unrealized_loss_rel_to_own_gross_pnl".to_string(), + ), + neg_unrealized_loss_rel_to_own_gross_pnl: BpsPercentRatioPattern::new( + client.clone(), + "neg_unrealized_loss_rel_to_own_gross_pnl".to_string(), + ), + net_unrealized_pnl_rel_to_own_gross_pnl: BpsPercentRatioPattern::new( + client.clone(), + "net_unrealized_pnl_rel_to_own_gross_pnl".to_string(), + ), } } } @@ -5807,27 +8553,90 @@ pub struct MetricsTree_Distribution_UtxoCohorts_AgeRange { impl MetricsTree_Distribution_UtxoCohorts_AgeRange { pub fn new(client: Arc, base_path: String) -> Self { Self { - up_to_1h: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "utxos_under_1h_old".to_string()), - _1h_to_1d: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "utxos_1h_to_1d_old".to_string()), - _1d_to_1w: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "utxos_1d_to_1w_old".to_string()), - _1w_to_1m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "utxos_1w_to_1m_old".to_string()), - _1m_to_2m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "utxos_1m_to_2m_old".to_string()), - _2m_to_3m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "utxos_2m_to_3m_old".to_string()), - _3m_to_4m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "utxos_3m_to_4m_old".to_string()), - _4m_to_5m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "utxos_4m_to_5m_old".to_string()), - _5m_to_6m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "utxos_5m_to_6m_old".to_string()), - _6m_to_1y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "utxos_6m_to_1y_old".to_string()), - _1y_to_2y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "utxos_1y_to_2y_old".to_string()), - _2y_to_3y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "utxos_2y_to_3y_old".to_string()), - _3y_to_4y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "utxos_3y_to_4y_old".to_string()), - _4y_to_5y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "utxos_4y_to_5y_old".to_string()), - _5y_to_6y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "utxos_5y_to_6y_old".to_string()), - _6y_to_7y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "utxos_6y_to_7y_old".to_string()), - _7y_to_8y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "utxos_7y_to_8y_old".to_string()), - _8y_to_10y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "utxos_8y_to_10y_old".to_string()), - _10y_to_12y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "utxos_10y_to_12y_old".to_string()), - _12y_to_15y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "utxos_12y_to_15y_old".to_string()), - from_15y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "utxos_over_15y_old".to_string()), + up_to_1h: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "utxos_under_1h_old".to_string(), + ), + _1h_to_1d: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "utxos_1h_to_1d_old".to_string(), + ), + _1d_to_1w: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "utxos_1d_to_1w_old".to_string(), + ), + _1w_to_1m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "utxos_1w_to_1m_old".to_string(), + ), + _1m_to_2m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "utxos_1m_to_2m_old".to_string(), + ), + _2m_to_3m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "utxos_2m_to_3m_old".to_string(), + ), + _3m_to_4m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "utxos_3m_to_4m_old".to_string(), + ), + _4m_to_5m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "utxos_4m_to_5m_old".to_string(), + ), + _5m_to_6m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "utxos_5m_to_6m_old".to_string(), + ), + _6m_to_1y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "utxos_6m_to_1y_old".to_string(), + ), + _1y_to_2y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "utxos_1y_to_2y_old".to_string(), + ), + _2y_to_3y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "utxos_2y_to_3y_old".to_string(), + ), + _3y_to_4y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "utxos_3y_to_4y_old".to_string(), + ), + _4y_to_5y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "utxos_4y_to_5y_old".to_string(), + ), + _5y_to_6y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "utxos_5y_to_6y_old".to_string(), + ), + _6y_to_7y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "utxos_6y_to_7y_old".to_string(), + ), + _7y_to_8y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "utxos_7y_to_8y_old".to_string(), + ), + _8y_to_10y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "utxos_8y_to_10y_old".to_string(), + ), + _10y_to_12y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "utxos_10y_to_12y_old".to_string(), + ), + _12y_to_15y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "utxos_12y_to_15y_old".to_string(), + ), + from_15y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "utxos_over_15y_old".to_string(), + ), } } } @@ -5857,24 +8666,78 @@ pub struct MetricsTree_Distribution_UtxoCohorts_MaxAge { impl MetricsTree_Distribution_UtxoCohorts_MaxAge { pub fn new(client: Arc, base_path: String) -> Self { Self { - _1w: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_under_1w_old".to_string()), - _1m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_under_1m_old".to_string()), - _2m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_under_2m_old".to_string()), - _3m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_under_3m_old".to_string()), - _4m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_under_4m_old".to_string()), - _5m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_under_5m_old".to_string()), - _6m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_under_6m_old".to_string()), - _1y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_under_1y_old".to_string()), - _2y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_under_2y_old".to_string()), - _3y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_under_3y_old".to_string()), - _4y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_under_4y_old".to_string()), - _5y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_under_5y_old".to_string()), - _6y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_under_6y_old".to_string()), - _7y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_under_7y_old".to_string()), - _8y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_under_8y_old".to_string()), - _10y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_under_10y_old".to_string()), - _12y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_under_12y_old".to_string()), - _15y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new(client.clone(), "utxos_under_15y_old".to_string()), + _1w: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new( + client.clone(), + "utxos_under_1w_old".to_string(), + ), + _1m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new( + client.clone(), + "utxos_under_1m_old".to_string(), + ), + _2m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new( + client.clone(), + "utxos_under_2m_old".to_string(), + ), + _3m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new( + client.clone(), + "utxos_under_3m_old".to_string(), + ), + _4m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new( + client.clone(), + "utxos_under_4m_old".to_string(), + ), + _5m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new( + client.clone(), + "utxos_under_5m_old".to_string(), + ), + _6m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new( + client.clone(), + "utxos_under_6m_old".to_string(), + ), + _1y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new( + client.clone(), + "utxos_under_1y_old".to_string(), + ), + _2y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new( + client.clone(), + "utxos_under_2y_old".to_string(), + ), + _3y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new( + client.clone(), + "utxos_under_3y_old".to_string(), + ), + _4y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new( + client.clone(), + "utxos_under_4y_old".to_string(), + ), + _5y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new( + client.clone(), + "utxos_under_5y_old".to_string(), + ), + _6y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new( + client.clone(), + "utxos_under_6y_old".to_string(), + ), + _7y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new( + client.clone(), + "utxos_under_7y_old".to_string(), + ), + _8y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new( + client.clone(), + "utxos_under_8y_old".to_string(), + ), + _10y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new( + client.clone(), + "utxos_under_10y_old".to_string(), + ), + _12y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new( + client.clone(), + "utxos_under_12y_old".to_string(), + ), + _15y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4::new( + client.clone(), + "utxos_under_15y_old".to_string(), + ), } } } @@ -5904,24 +8767,78 @@ pub struct MetricsTree_Distribution_UtxoCohorts_MinAge { impl MetricsTree_Distribution_UtxoCohorts_MinAge { pub fn new(client: Arc, base_path: String) -> Self { Self { - _1d: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_1d_old".to_string()), - _1w: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_1w_old".to_string()), - _1m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_1m_old".to_string()), - _2m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_2m_old".to_string()), - _3m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_3m_old".to_string()), - _4m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_4m_old".to_string()), - _5m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_5m_old".to_string()), - _6m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_6m_old".to_string()), - _1y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_1y_old".to_string()), - _2y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_2y_old".to_string()), - _3y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_3y_old".to_string()), - _4y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_4y_old".to_string()), - _5y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_5y_old".to_string()), - _6y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_6y_old".to_string()), - _7y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_7y_old".to_string()), - _8y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_8y_old".to_string()), - _10y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_10y_old".to_string()), - _12y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_12y_old".to_string()), + _1d: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_1d_old".to_string(), + ), + _1w: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_1w_old".to_string(), + ), + _1m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_1m_old".to_string(), + ), + _2m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_2m_old".to_string(), + ), + _3m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_3m_old".to_string(), + ), + _4m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_4m_old".to_string(), + ), + _5m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_5m_old".to_string(), + ), + _6m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_6m_old".to_string(), + ), + _1y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_1y_old".to_string(), + ), + _2y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_2y_old".to_string(), + ), + _3y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_3y_old".to_string(), + ), + _4y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_4y_old".to_string(), + ), + _5y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_5y_old".to_string(), + ), + _6y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_6y_old".to_string(), + ), + _7y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_7y_old".to_string(), + ), + _8y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_8y_old".to_string(), + ), + _10y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_10y_old".to_string(), + ), + _12y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_12y_old".to_string(), + ), } } } @@ -5946,19 +8863,58 @@ pub struct MetricsTree_Distribution_UtxoCohorts_GeAmount { impl MetricsTree_Distribution_UtxoCohorts_GeAmount { pub fn new(client: Arc, base_path: String) -> Self { Self { - _1sat: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_1sat".to_string()), - _10sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_10sats".to_string()), - _100sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_100sats".to_string()), - _1k_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_1k_sats".to_string()), - _10k_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_10k_sats".to_string()), - _100k_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_100k_sats".to_string()), - _1m_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_1m_sats".to_string()), - _10m_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_10m_sats".to_string()), - _1btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_1btc".to_string()), - _10btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_10btc".to_string()), - _100btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_100btc".to_string()), - _1k_btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_1k_btc".to_string()), - _10k_btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_over_10k_btc".to_string()), + _1sat: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_1sat".to_string(), + ), + _10sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_10sats".to_string(), + ), + _100sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_100sats".to_string(), + ), + _1k_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_1k_sats".to_string(), + ), + _10k_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_10k_sats".to_string(), + ), + _100k_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_100k_sats".to_string(), + ), + _1m_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_1m_sats".to_string(), + ), + _10m_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_10m_sats".to_string(), + ), + _1btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_1btc".to_string(), + ), + _10btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_10btc".to_string(), + ), + _100btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_100btc".to_string(), + ), + _1k_btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_1k_btc".to_string(), + ), + _10k_btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_over_10k_btc".to_string(), + ), } } } @@ -5985,21 +8941,67 @@ pub struct MetricsTree_Distribution_UtxoCohorts_AmountRange { impl MetricsTree_Distribution_UtxoCohorts_AmountRange { pub fn new(client: Arc, base_path: String) -> Self { Self { - _0sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_with_0sats".to_string()), - _1sat_to_10sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_above_1sat_under_10sats".to_string()), - _10sats_to_100sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_above_10sats_under_100sats".to_string()), - _100sats_to_1k_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_above_100sats_under_1k_sats".to_string()), - _1k_sats_to_10k_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_above_1k_sats_under_10k_sats".to_string()), - _10k_sats_to_100k_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_above_10k_sats_under_100k_sats".to_string()), - _100k_sats_to_1m_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_above_100k_sats_under_1m_sats".to_string()), - _1m_sats_to_10m_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_above_1m_sats_under_10m_sats".to_string()), - _10m_sats_to_1btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_above_10m_sats_under_1btc".to_string()), - _1btc_to_10btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_above_1btc_under_10btc".to_string()), - _10btc_to_100btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_above_10btc_under_100btc".to_string()), - _100btc_to_1k_btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_above_100btc_under_1k_btc".to_string()), - _1k_btc_to_10k_btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_above_1k_btc_under_10k_btc".to_string()), - _10k_btc_to_100k_btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_above_10k_btc_under_100k_btc".to_string()), - _100k_btc_or_more: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_above_100k_btc".to_string()), + _0sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_with_0sats".to_string(), + ), + _1sat_to_10sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_above_1sat_under_10sats".to_string(), + ), + _10sats_to_100sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_above_10sats_under_100sats".to_string(), + ), + _100sats_to_1k_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_above_100sats_under_1k_sats".to_string(), + ), + _1k_sats_to_10k_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_above_1k_sats_under_10k_sats".to_string(), + ), + _10k_sats_to_100k_sats: + ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_above_10k_sats_under_100k_sats".to_string(), + ), + _100k_sats_to_1m_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_above_100k_sats_under_1m_sats".to_string(), + ), + _1m_sats_to_10m_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_above_1m_sats_under_10m_sats".to_string(), + ), + _10m_sats_to_1btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_above_10m_sats_under_1btc".to_string(), + ), + _1btc_to_10btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_above_1btc_under_10btc".to_string(), + ), + _10btc_to_100btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_above_10btc_under_100btc".to_string(), + ), + _100btc_to_1k_btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_above_100btc_under_1k_btc".to_string(), + ), + _1k_btc_to_10k_btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_above_1k_btc_under_10k_btc".to_string(), + ), + _10k_btc_to_100k_btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_above_10k_btc_under_100k_btc".to_string(), + ), + _100k_btc_or_more: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_above_100k_btc".to_string(), + ), } } } @@ -6024,19 +9026,58 @@ pub struct MetricsTree_Distribution_UtxoCohorts_LtAmount { impl MetricsTree_Distribution_UtxoCohorts_LtAmount { pub fn new(client: Arc, base_path: String) -> Self { Self { - _10sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_under_10sats".to_string()), - _100sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_under_100sats".to_string()), - _1k_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_under_1k_sats".to_string()), - _10k_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_under_10k_sats".to_string()), - _100k_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_under_100k_sats".to_string()), - _1m_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_under_1m_sats".to_string()), - _10m_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_under_10m_sats".to_string()), - _1btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_under_1btc".to_string()), - _10btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_under_10btc".to_string()), - _100btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_under_100btc".to_string()), - _1k_btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_under_1k_btc".to_string()), - _10k_btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_under_10k_btc".to_string()), - _100k_btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "utxos_under_100k_btc".to_string()), + _10sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_under_10sats".to_string(), + ), + _100sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_under_100sats".to_string(), + ), + _1k_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_under_1k_sats".to_string(), + ), + _10k_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_under_10k_sats".to_string(), + ), + _100k_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_under_100k_sats".to_string(), + ), + _1m_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_under_1m_sats".to_string(), + ), + _10m_sats: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_under_10m_sats".to_string(), + ), + _1btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_under_1btc".to_string(), + ), + _10btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_under_10btc".to_string(), + ), + _100btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_under_100btc".to_string(), + ), + _1k_btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_under_1k_btc".to_string(), + ), + _10k_btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_under_10k_btc".to_string(), + ), + _100k_btc: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "utxos_under_100k_btc".to_string(), + ), } } } @@ -6053,11 +9094,26 @@ pub struct MetricsTree_Distribution_UtxoCohorts_Epoch { impl MetricsTree_Distribution_UtxoCohorts_Epoch { pub fn new(client: Arc, base_path: String) -> Self { Self { - _0: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "epoch_0".to_string()), - _1: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "epoch_1".to_string()), - _2: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "epoch_2".to_string()), - _3: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "epoch_3".to_string()), - _4: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "epoch_4".to_string()), + _0: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "epoch_0".to_string(), + ), + _1: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "epoch_1".to_string(), + ), + _2: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "epoch_2".to_string(), + ), + _3: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "epoch_3".to_string(), + ), + _4: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "epoch_4".to_string(), + ), } } } @@ -6087,24 +9143,78 @@ pub struct MetricsTree_Distribution_UtxoCohorts_Year { impl MetricsTree_Distribution_UtxoCohorts_Year { pub fn new(client: Arc, base_path: String) -> Self { Self { - _2009: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "year_2009".to_string()), - _2010: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "year_2010".to_string()), - _2011: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "year_2011".to_string()), - _2012: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "year_2012".to_string()), - _2013: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "year_2013".to_string()), - _2014: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "year_2014".to_string()), - _2015: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "year_2015".to_string()), - _2016: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "year_2016".to_string()), - _2017: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "year_2017".to_string()), - _2018: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "year_2018".to_string()), - _2019: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "year_2019".to_string()), - _2020: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "year_2020".to_string()), - _2021: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "year_2021".to_string()), - _2022: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "year_2022".to_string()), - _2023: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "year_2023".to_string()), - _2024: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "year_2024".to_string()), - _2025: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "year_2025".to_string()), - _2026: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "year_2026".to_string()), + _2009: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "year_2009".to_string(), + ), + _2010: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "year_2010".to_string(), + ), + _2011: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "year_2011".to_string(), + ), + _2012: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "year_2012".to_string(), + ), + _2013: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "year_2013".to_string(), + ), + _2014: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "year_2014".to_string(), + ), + _2015: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "year_2015".to_string(), + ), + _2016: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "year_2016".to_string(), + ), + _2017: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "year_2017".to_string(), + ), + _2018: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "year_2018".to_string(), + ), + _2019: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "year_2019".to_string(), + ), + _2020: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "year_2020".to_string(), + ), + _2021: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "year_2021".to_string(), + ), + _2022: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "year_2022".to_string(), + ), + _2023: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "year_2023".to_string(), + ), + _2024: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "year_2024".to_string(), + ), + _2025: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "year_2025".to_string(), + ), + _2026: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "year_2026".to_string(), + ), } } } @@ -6127,17 +9237,50 @@ pub struct MetricsTree_Distribution_UtxoCohorts_Type { impl MetricsTree_Distribution_UtxoCohorts_Type { pub fn new(client: Arc, base_path: String) -> Self { Self { - p2pk65: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "p2pk65".to_string()), - p2pk33: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "p2pk33".to_string()), - p2pkh: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "p2pkh".to_string()), - p2ms: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "p2ms".to_string()), - p2sh: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "p2sh".to_string()), - p2wpkh: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "p2wpkh".to_string()), - p2wsh: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "p2wsh".to_string()), - p2tr: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "p2tr".to_string()), - p2a: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "p2a".to_string()), - unknown: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "unknown_outputs".to_string()), - empty: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new(client.clone(), "empty_outputs".to_string()), + p2pk65: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "p2pk65".to_string(), + ), + p2pk33: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "p2pk33".to_string(), + ), + p2pkh: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "p2pkh".to_string(), + ), + p2ms: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "p2ms".to_string(), + ), + p2sh: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "p2sh".to_string(), + ), + p2wpkh: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "p2wpkh".to_string(), + ), + p2wsh: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "p2wsh".to_string(), + ), + p2tr: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "p2tr".to_string(), + ), + p2a: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "p2a".to_string(), + ), + unknown: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "unknown_outputs".to_string(), + ), + empty: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern3::new( + client.clone(), + "empty_outputs".to_string(), + ), } } } @@ -6152,9 +9295,18 @@ pub struct MetricsTree_Distribution_AddressCohorts { impl MetricsTree_Distribution_AddressCohorts { pub fn new(client: Arc, base_path: String) -> Self { Self { - ge_amount: MetricsTree_Distribution_AddressCohorts_GeAmount::new(client.clone(), format!("{base_path}_ge_amount")), - amount_range: MetricsTree_Distribution_AddressCohorts_AmountRange::new(client.clone(), format!("{base_path}_amount_range")), - lt_amount: MetricsTree_Distribution_AddressCohorts_LtAmount::new(client.clone(), format!("{base_path}_lt_amount")), + ge_amount: MetricsTree_Distribution_AddressCohorts_GeAmount::new( + client.clone(), + format!("{base_path}_ge_amount"), + ), + amount_range: MetricsTree_Distribution_AddressCohorts_AmountRange::new( + client.clone(), + format!("{base_path}_amount_range"), + ), + lt_amount: MetricsTree_Distribution_AddressCohorts_LtAmount::new( + client.clone(), + format!("{base_path}_lt_amount"), + ), } } } @@ -6179,19 +9331,58 @@ pub struct MetricsTree_Distribution_AddressCohorts_GeAmount { impl MetricsTree_Distribution_AddressCohorts_GeAmount { pub fn new(client: Arc, base_path: String) -> Self { Self { - _1sat: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_over_1sat".to_string()), - _10sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_over_10sats".to_string()), - _100sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_over_100sats".to_string()), - _1k_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_over_1k_sats".to_string()), - _10k_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_over_10k_sats".to_string()), - _100k_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_over_100k_sats".to_string()), - _1m_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_over_1m_sats".to_string()), - _10m_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_over_10m_sats".to_string()), - _1btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_over_1btc".to_string()), - _10btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_over_10btc".to_string()), - _100btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_over_100btc".to_string()), - _1k_btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_over_1k_btc".to_string()), - _10k_btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_over_10k_btc".to_string()), + _1sat: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_over_1sat".to_string(), + ), + _10sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_over_10sats".to_string(), + ), + _100sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_over_100sats".to_string(), + ), + _1k_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_over_1k_sats".to_string(), + ), + _10k_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_over_10k_sats".to_string(), + ), + _100k_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_over_100k_sats".to_string(), + ), + _1m_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_over_1m_sats".to_string(), + ), + _10m_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_over_10m_sats".to_string(), + ), + _1btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_over_1btc".to_string(), + ), + _10btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_over_10btc".to_string(), + ), + _100btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_over_100btc".to_string(), + ), + _1k_btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_over_1k_btc".to_string(), + ), + _10k_btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_over_10k_btc".to_string(), + ), } } } @@ -6218,21 +9409,72 @@ pub struct MetricsTree_Distribution_AddressCohorts_AmountRange { impl MetricsTree_Distribution_AddressCohorts_AmountRange { pub fn new(client: Arc, base_path: String) -> Self { Self { - _0sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_with_0sats".to_string()), - _1sat_to_10sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_above_1sat_under_10sats".to_string()), - _10sats_to_100sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_above_10sats_under_100sats".to_string()), - _100sats_to_1k_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_above_100sats_under_1k_sats".to_string()), - _1k_sats_to_10k_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_above_1k_sats_under_10k_sats".to_string()), - _10k_sats_to_100k_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_above_10k_sats_under_100k_sats".to_string()), - _100k_sats_to_1m_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_above_100k_sats_under_1m_sats".to_string()), - _1m_sats_to_10m_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_above_1m_sats_under_10m_sats".to_string()), - _10m_sats_to_1btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_above_10m_sats_under_1btc".to_string()), - _1btc_to_10btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_above_1btc_under_10btc".to_string()), - _10btc_to_100btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_above_10btc_under_100btc".to_string()), - _100btc_to_1k_btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_above_100btc_under_1k_btc".to_string()), - _1k_btc_to_10k_btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_above_1k_btc_under_10k_btc".to_string()), - _10k_btc_to_100k_btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_above_10k_btc_under_100k_btc".to_string()), - _100k_btc_or_more: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_above_100k_btc".to_string()), + _0sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_with_0sats".to_string(), + ), + _1sat_to_10sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_above_1sat_under_10sats".to_string(), + ), + _10sats_to_100sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_above_10sats_under_100sats".to_string(), + ), + _100sats_to_1k_sats: + ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_above_100sats_under_1k_sats".to_string(), + ), + _1k_sats_to_10k_sats: + ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_above_1k_sats_under_10k_sats".to_string(), + ), + _10k_sats_to_100k_sats: + ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_above_10k_sats_under_100k_sats".to_string(), + ), + _100k_sats_to_1m_sats: + ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_above_100k_sats_under_1m_sats".to_string(), + ), + _1m_sats_to_10m_sats: + ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_above_1m_sats_under_10m_sats".to_string(), + ), + _10m_sats_to_1btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_above_10m_sats_under_1btc".to_string(), + ), + _1btc_to_10btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_above_1btc_under_10btc".to_string(), + ), + _10btc_to_100btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_above_10btc_under_100btc".to_string(), + ), + _100btc_to_1k_btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_above_100btc_under_1k_btc".to_string(), + ), + _1k_btc_to_10k_btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_above_1k_btc_under_10k_btc".to_string(), + ), + _10k_btc_to_100k_btc: + ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_above_10k_btc_under_100k_btc".to_string(), + ), + _100k_btc_or_more: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_above_100k_btc".to_string(), + ), } } } @@ -6257,19 +9499,58 @@ pub struct MetricsTree_Distribution_AddressCohorts_LtAmount { impl MetricsTree_Distribution_AddressCohorts_LtAmount { pub fn new(client: Arc, base_path: String) -> Self { Self { - _10sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_under_10sats".to_string()), - _100sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_under_100sats".to_string()), - _1k_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_under_1k_sats".to_string()), - _10k_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_under_10k_sats".to_string()), - _100k_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_under_100k_sats".to_string()), - _1m_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_under_1m_sats".to_string()), - _10m_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_under_10m_sats".to_string()), - _1btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_under_1btc".to_string()), - _10btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_under_10btc".to_string()), - _100btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_under_100btc".to_string()), - _1k_btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_under_1k_btc".to_string()), - _10k_btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_under_10k_btc".to_string()), - _100k_btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new(client.clone(), "addrs_under_100k_btc".to_string()), + _10sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_under_10sats".to_string(), + ), + _100sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_under_100sats".to_string(), + ), + _1k_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_under_1k_sats".to_string(), + ), + _10k_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_under_10k_sats".to_string(), + ), + _100k_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_under_100k_sats".to_string(), + ), + _1m_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_under_1m_sats".to_string(), + ), + _10m_sats: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_under_10m_sats".to_string(), + ), + _1btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_under_1btc".to_string(), + ), + _10btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_under_10btc".to_string(), + ), + _100btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_under_100btc".to_string(), + ), + _1k_btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_under_1k_btc".to_string(), + ), + _10k_btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_under_10k_btc".to_string(), + ), + _100k_btc: ActivityAddrCostOutputsRealizedRelativeSupplyUnrealizedPattern::new( + client.clone(), + "addrs_under_100k_btc".to_string(), + ), } } } @@ -6290,15 +9571,42 @@ pub struct MetricsTree_Distribution_AddressActivity { impl MetricsTree_Distribution_AddressActivity { pub fn new(client: Arc, base_path: String) -> Self { Self { - all: BalanceBothReactivatedReceivingSendingPattern::new(client.clone(), "address_activity".to_string()), - p2pk65: BalanceBothReactivatedReceivingSendingPattern::new(client.clone(), "p2pk65_address_activity".to_string()), - p2pk33: BalanceBothReactivatedReceivingSendingPattern::new(client.clone(), "p2pk33_address_activity".to_string()), - p2pkh: BalanceBothReactivatedReceivingSendingPattern::new(client.clone(), "p2pkh_address_activity".to_string()), - p2sh: BalanceBothReactivatedReceivingSendingPattern::new(client.clone(), "p2sh_address_activity".to_string()), - p2wpkh: BalanceBothReactivatedReceivingSendingPattern::new(client.clone(), "p2wpkh_address_activity".to_string()), - p2wsh: BalanceBothReactivatedReceivingSendingPattern::new(client.clone(), "p2wsh_address_activity".to_string()), - p2tr: BalanceBothReactivatedReceivingSendingPattern::new(client.clone(), "p2tr_address_activity".to_string()), - p2a: BalanceBothReactivatedReceivingSendingPattern::new(client.clone(), "p2a_address_activity".to_string()), + all: BalanceBothReactivatedReceivingSendingPattern::new( + client.clone(), + "address_activity".to_string(), + ), + p2pk65: BalanceBothReactivatedReceivingSendingPattern::new( + client.clone(), + "p2pk65_address_activity".to_string(), + ), + p2pk33: BalanceBothReactivatedReceivingSendingPattern::new( + client.clone(), + "p2pk33_address_activity".to_string(), + ), + p2pkh: BalanceBothReactivatedReceivingSendingPattern::new( + client.clone(), + "p2pkh_address_activity".to_string(), + ), + p2sh: BalanceBothReactivatedReceivingSendingPattern::new( + client.clone(), + "p2sh_address_activity".to_string(), + ), + p2wpkh: BalanceBothReactivatedReceivingSendingPattern::new( + client.clone(), + "p2wpkh_address_activity".to_string(), + ), + p2wsh: BalanceBothReactivatedReceivingSendingPattern::new( + client.clone(), + "p2wsh_address_activity".to_string(), + ), + p2tr: BalanceBothReactivatedReceivingSendingPattern::new( + client.clone(), + "p2tr_address_activity".to_string(), + ), + p2a: BalanceBothReactivatedReceivingSendingPattern::new( + client.clone(), + "p2a_address_activity".to_string(), + ), } } } @@ -6348,15 +9656,42 @@ pub struct MetricsTree_Distribution_NewAddrCount { impl MetricsTree_Distribution_NewAddrCount { pub fn new(client: Arc, base_path: String) -> Self { Self { - all: AverageCumulativeHeightMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new(client.clone(), "new_addr_count".to_string()), - p2pk65: AverageCumulativeHeightMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new(client.clone(), "p2pk65_new_addr_count".to_string()), - p2pk33: AverageCumulativeHeightMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new(client.clone(), "p2pk33_new_addr_count".to_string()), - p2pkh: AverageCumulativeHeightMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new(client.clone(), "p2pkh_new_addr_count".to_string()), - p2sh: AverageCumulativeHeightMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new(client.clone(), "p2sh_new_addr_count".to_string()), - p2wpkh: AverageCumulativeHeightMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new(client.clone(), "p2wpkh_new_addr_count".to_string()), - p2wsh: AverageCumulativeHeightMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new(client.clone(), "p2wsh_new_addr_count".to_string()), - p2tr: AverageCumulativeHeightMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new(client.clone(), "p2tr_new_addr_count".to_string()), - p2a: AverageCumulativeHeightMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new(client.clone(), "p2a_new_addr_count".to_string()), + all: AverageCumulativeHeightMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new( + client.clone(), + "new_addr_count".to_string(), + ), + p2pk65: AverageCumulativeHeightMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new( + client.clone(), + "p2pk65_new_addr_count".to_string(), + ), + p2pk33: AverageCumulativeHeightMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new( + client.clone(), + "p2pk33_new_addr_count".to_string(), + ), + p2pkh: AverageCumulativeHeightMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new( + client.clone(), + "p2pkh_new_addr_count".to_string(), + ), + p2sh: AverageCumulativeHeightMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new( + client.clone(), + "p2sh_new_addr_count".to_string(), + ), + p2wpkh: AverageCumulativeHeightMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new( + client.clone(), + "p2wpkh_new_addr_count".to_string(), + ), + p2wsh: AverageCumulativeHeightMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new( + client.clone(), + "p2wsh_new_addr_count".to_string(), + ), + p2tr: AverageCumulativeHeightMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new( + client.clone(), + "p2tr_new_addr_count".to_string(), + ), + p2a: AverageCumulativeHeightMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new( + client.clone(), + "p2a_new_addr_count".to_string(), + ), } } } @@ -6405,14 +9740,32 @@ pub struct MetricsTree_Supply { impl MetricsTree_Supply { pub fn new(client: Arc, base_path: String) -> Self { Self { - circulating: BtcCentsSatsUsdPattern::new(client.clone(), "circulating_supply".to_string()), + circulating: BtcCentsSatsUsdPattern::new( + client.clone(), + "circulating_supply".to_string(), + ), burned: MetricsTree_Supply_Burned::new(client.clone(), format!("{base_path}_burned")), - inflation_rate: BpsPercentRatioPattern::new(client.clone(), "inflation_rate".to_string()), - velocity: MetricsTree_Supply_Velocity::new(client.clone(), format!("{base_path}_velocity")), + inflation_rate: BpsPercentRatioPattern::new( + client.clone(), + "inflation_rate".to_string(), + ), + velocity: MetricsTree_Supply_Velocity::new( + client.clone(), + format!("{base_path}_velocity"), + ), market_cap: MetricPattern1::new(client.clone(), "market_cap".to_string()), - market_cap_growth_rate: BpsPercentRatioPattern::new(client.clone(), "market_cap_growth_rate".to_string()), - realized_cap_growth_rate: BpsPercentRatioPattern::new(client.clone(), "realized_cap_growth_rate".to_string()), - market_minus_realized_cap_growth_rate: MetricPattern1::new(client.clone(), "market_minus_realized_cap_growth_rate".to_string()), + market_cap_growth_rate: BpsPercentRatioPattern::new( + client.clone(), + "market_cap_growth_rate".to_string(), + ), + realized_cap_growth_rate: BpsPercentRatioPattern::new( + client.clone(), + "realized_cap_growth_rate".to_string(), + ), + market_minus_realized_cap_growth_rate: MetricPattern1::new( + client.clone(), + "market_minus_realized_cap_growth_rate".to_string(), + ), } } } @@ -6427,7 +9780,10 @@ impl MetricsTree_Supply_Burned { pub fn new(client: Arc, base_path: String) -> Self { Self { opreturn: BaseCumulativeSumPattern::new(client.clone(), "opreturn_supply".to_string()), - unspendable: BaseCumulativeSumPattern::new(client.clone(), "unspendable_supply".to_string()), + unspendable: BaseCumulativeSumPattern::new( + client.clone(), + "unspendable_supply".to_string(), + ), } } } @@ -6487,20 +9843,26 @@ impl BrkClient { /// .last(10) /// .json::()?; /// ``` - pub fn metric(&self, metric: impl Into, index: Index) -> MetricEndpointBuilder { - MetricEndpointBuilder::new( - self.base.clone(), - Arc::from(metric.into().as_str()), - index, - ) + pub fn metric( + &self, + metric: impl Into, + index: Index, + ) -> MetricEndpointBuilder { + MetricEndpointBuilder::new(self.base.clone(), Arc::from(metric.into().as_str()), index) } /// Create a dynamic date-based metric endpoint builder. /// /// Returns `Err` if the index is not date-based. - pub fn date_metric(&self, metric: impl Into, index: Index) -> Result> { + pub fn date_metric( + &self, + metric: impl Into, + index: Index, + ) -> Result> { if !index.is_date_based() { - return Err(BrkError { message: format!("{} is not a date-based index", index.name()) }); + return Err(BrkError { + message: format!("{} is not a date-based index", index.name()), + }); } Ok(DateMetricEndpointBuilder::new( self.base.clone(), @@ -6536,11 +9898,24 @@ impl BrkClient { /// *[Mempool.space docs](https://mempool.space/docs/api/rest#get-address-transactions)* /// /// Endpoint: `GET /api/address/{address}/txs` - pub fn get_address_txs(&self, address: Address, after_txid: Option<&str>, limit: Option) -> Result> { + pub fn get_address_txs( + &self, + address: Address, + after_txid: Option<&str>, + limit: Option, + ) -> Result> { let mut query = Vec::new(); - if let Some(v) = after_txid { query.push(format!("after_txid={}", v)); } - if let Some(v) = limit { query.push(format!("limit={}", v)); } - let query_str = if query.is_empty() { String::new() } else { format!("?{}", query.join("&")) }; + if let Some(v) = after_txid { + query.push(format!("after_txid={}", v)); + } + if let Some(v) = limit { + query.push(format!("limit={}", v)); + } + let query_str = if query.is_empty() { + String::new() + } else { + format!("?{}", query.join("&")) + }; let path = format!("/api/address/{address}/txs{}", query_str); self.base.get_json(&path) } @@ -6552,11 +9927,24 @@ impl BrkClient { /// *[Mempool.space docs](https://mempool.space/docs/api/rest#get-address-transactions-chain)* /// /// Endpoint: `GET /api/address/{address}/txs/chain` - pub fn get_address_confirmed_txs(&self, address: Address, after_txid: Option<&str>, limit: Option) -> Result> { + pub fn get_address_confirmed_txs( + &self, + address: Address, + after_txid: Option<&str>, + limit: Option, + ) -> Result> { let mut query = Vec::new(); - if let Some(v) = after_txid { query.push(format!("after_txid={}", v)); } - if let Some(v) = limit { query.push(format!("limit={}", v)); } - let query_str = if query.is_empty() { String::new() } else { format!("?{}", query.join("&")) }; + if let Some(v) = after_txid { + query.push(format!("after_txid={}", v)); + } + if let Some(v) = limit { + query.push(format!("limit={}", v)); + } + let query_str = if query.is_empty() { + String::new() + } else { + format!("?{}", query.join("&")) + }; let path = format!("/api/address/{address}/txs/chain{}", query_str); self.base.get_json(&path) } @@ -6569,7 +9957,8 @@ impl BrkClient { /// /// Endpoint: `GET /api/address/{address}/txs/mempool` pub fn get_address_mempool_txs(&self, address: Address) -> Result> { - self.base.get_json(&format!("/api/address/{address}/txs/mempool")) + self.base + .get_json(&format!("/api/address/{address}/txs/mempool")) } /// Address UTXOs @@ -6635,7 +10024,8 @@ impl BrkClient { /// /// Endpoint: `GET /api/block/{hash}/txid/{index}` pub fn get_block_txid(&self, hash: BlockHash, index: TxIndex) -> Result { - self.base.get_json(&format!("/api/block/{hash}/txid/{index}")) + self.base + .get_json(&format!("/api/block/{hash}/txid/{index}")) } /// Block transaction IDs @@ -6657,7 +10047,8 @@ impl BrkClient { /// /// Endpoint: `GET /api/block/{hash}/txs/{start_index}` pub fn get_block_txs(&self, hash: BlockHash, start_index: TxIndex) -> Result> { - self.base.get_json(&format!("/api/block/{hash}/txs/{start_index}")) + self.base + .get_json(&format!("/api/block/{hash}/txs/{start_index}")) } /// Recent blocks @@ -6727,13 +10118,33 @@ impl BrkClient { /// Fetch data for a specific metric at the given index. Use query parameters to filter by date range and format (json/csv). /// /// Endpoint: `GET /api/metric/{metric}/{index}` - pub fn get_metric(&self, metric: Metric, index: Index, start: Option, end: Option, limit: Option<&str>, format: Option) -> Result> { + pub fn get_metric( + &self, + metric: Metric, + index: Index, + start: Option, + end: Option, + limit: Option<&str>, + format: Option, + ) -> Result> { let mut query = Vec::new(); - if let Some(v) = start { query.push(format!("start={}", v)); } - if let Some(v) = end { query.push(format!("end={}", v)); } - if let Some(v) = limit { query.push(format!("limit={}", v)); } - if let Some(v) = format { query.push(format!("format={}", v)); } - let query_str = if query.is_empty() { String::new() } else { format!("?{}", query.join("&")) }; + if let Some(v) = start { + query.push(format!("start={}", v)); + } + if let Some(v) = end { + query.push(format!("end={}", v)); + } + if let Some(v) = limit { + query.push(format!("limit={}", v)); + } + if let Some(v) = format { + query.push(format!("format={}", v)); + } + let query_str = if query.is_empty() { + String::new() + } else { + format!("?{}", query.join("&")) + }; let path = format!("/api/metric/{metric}/{}{}", index.name(), query_str); if format == Some(Format::CSV) { self.base.get_text(&path).map(FormatResponse::Csv) @@ -6756,15 +10167,35 @@ impl BrkClient { /// Fetch multiple metrics in a single request. Supports filtering by index and date range. Returns an array of MetricData objects. For a single metric, use `get_metric` instead. /// /// Endpoint: `GET /api/metrics/bulk` - pub fn get_metrics(&self, metrics: Metrics, index: Index, start: Option, end: Option, limit: Option<&str>, format: Option) -> Result>> { + pub fn get_metrics( + &self, + metrics: Metrics, + index: Index, + start: Option, + end: Option, + limit: Option<&str>, + format: Option, + ) -> Result>> { let mut query = Vec::new(); query.push(format!("metrics={}", metrics)); query.push(format!("index={}", index)); - if let Some(v) = start { query.push(format!("start={}", v)); } - if let Some(v) = end { query.push(format!("end={}", v)); } - if let Some(v) = limit { query.push(format!("limit={}", v)); } - if let Some(v) = format { query.push(format!("format={}", v)); } - let query_str = if query.is_empty() { String::new() } else { format!("?{}", query.join("&")) }; + if let Some(v) = start { + query.push(format!("start={}", v)); + } + if let Some(v) = end { + query.push(format!("end={}", v)); + } + if let Some(v) = limit { + query.push(format!("limit={}", v)); + } + if let Some(v) = format { + query.push(format!("format={}", v)); + } + let query_str = if query.is_empty() { + String::new() + } else { + format!("?{}", query.join("&")) + }; let path = format!("/api/metrics/bulk{}", query_str); if format == Some(Format::CSV) { self.base.get_text(&path).map(FormatResponse::Csv) @@ -6788,7 +10219,8 @@ impl BrkClient { /// /// Endpoint: `GET /api/metrics/cost-basis/{cohort}/dates` pub fn get_cost_basis_dates(&self, cohort: Cohort) -> Result> { - self.base.get_json(&format!("/api/metrics/cost-basis/{cohort}/dates")) + self.base + .get_json(&format!("/api/metrics/cost-basis/{cohort}/dates")) } /// Cost basis distribution @@ -6800,11 +10232,25 @@ impl BrkClient { /// - `value`: supply (default, in BTC), realized (USD), unrealized (USD) /// /// Endpoint: `GET /api/metrics/cost-basis/{cohort}/{date}` - pub fn get_cost_basis(&self, cohort: Cohort, date: &str, bucket: Option, value: Option) -> Result { + pub fn get_cost_basis( + &self, + cohort: Cohort, + date: &str, + bucket: Option, + value: Option, + ) -> Result { let mut query = Vec::new(); - if let Some(v) = bucket { query.push(format!("bucket={}", v)); } - if let Some(v) = value { query.push(format!("value={}", v)); } - let query_str = if query.is_empty() { String::new() } else { format!("?{}", query.join("&")) }; + if let Some(v) = bucket { + query.push(format!("bucket={}", v)); + } + if let Some(v) = value { + query.push(format!("value={}", v)); + } + let query_str = if query.is_empty() { + String::new() + } else { + format!("?{}", query.join("&")) + }; let path = format!("/api/metrics/cost-basis/{cohort}/{date}{}", query_str); self.base.get_json(&path) } @@ -6834,8 +10280,14 @@ impl BrkClient { /// Endpoint: `GET /api/metrics/list` pub fn list_metrics(&self, page: Option) -> Result { let mut query = Vec::new(); - if let Some(v) = page { query.push(format!("page={}", v)); } - let query_str = if query.is_empty() { String::new() } else { format!("?{}", query.join("&")) }; + if let Some(v) = page { + query.push(format!("page={}", v)); + } + let query_str = if query.is_empty() { + String::new() + } else { + format!("?{}", query.join("&")) + }; let path = format!("/api/metrics/list{}", query_str); self.base.get_json(&path) } @@ -6847,8 +10299,14 @@ impl BrkClient { /// Endpoint: `GET /api/metrics/search/{metric}` pub fn search_metrics(&self, metric: Metric, limit: Option) -> Result> { let mut query = Vec::new(); - if let Some(v) = limit { query.push(format!("limit={}", v)); } - let query_str = if query.is_empty() { String::new() } else { format!("?{}", query.join("&")) }; + if let Some(v) = limit { + query.push(format!("limit={}", v)); + } + let query_str = if query.is_empty() { + String::new() + } else { + format!("?{}", query.join("&")) + }; let path = format!("/api/metrics/search/{metric}{}", query_str); self.base.get_json(&path) } @@ -6901,7 +10359,8 @@ impl BrkClient { /// /// Endpoint: `GET /api/tx/{txid}/outspend/{vout}` pub fn get_tx_outspend(&self, txid: Txid, vout: Vout) -> Result { - self.base.get_json(&format!("/api/tx/{txid}/outspend/{vout}")) + self.base + .get_json(&format!("/api/tx/{txid}/outspend/{vout}")) } /// All output spend statuses @@ -6934,7 +10393,8 @@ impl BrkClient { /// /// Endpoint: `GET /api/v1/difficulty-adjustment` pub fn get_difficulty_adjustment(&self) -> Result { - self.base.get_json(&format!("/api/v1/difficulty-adjustment")) + self.base + .get_json(&format!("/api/v1/difficulty-adjustment")) } /// Projected mempool blocks @@ -6967,7 +10427,8 @@ impl BrkClient { /// /// Endpoint: `GET /api/v1/mining/blocks/fee-rates/{time_period}` pub fn get_block_fee_rates(&self, time_period: TimePeriod) -> Result { - self.base.get_json(&format!("/api/v1/mining/blocks/fee-rates/{time_period}")) + self.base + .get_json(&format!("/api/v1/mining/blocks/fee-rates/{time_period}")) } /// Block fees @@ -6978,7 +10439,8 @@ impl BrkClient { /// /// Endpoint: `GET /api/v1/mining/blocks/fees/{time_period}` pub fn get_block_fees(&self, time_period: TimePeriod) -> Result> { - self.base.get_json(&format!("/api/v1/mining/blocks/fees/{time_period}")) + self.base + .get_json(&format!("/api/v1/mining/blocks/fees/{time_period}")) } /// Block rewards @@ -6989,7 +10451,8 @@ impl BrkClient { /// /// Endpoint: `GET /api/v1/mining/blocks/rewards/{time_period}` pub fn get_block_rewards(&self, time_period: TimePeriod) -> Result> { - self.base.get_json(&format!("/api/v1/mining/blocks/rewards/{time_period}")) + self.base + .get_json(&format!("/api/v1/mining/blocks/rewards/{time_period}")) } /// Block sizes and weights @@ -7000,7 +10463,9 @@ impl BrkClient { /// /// Endpoint: `GET /api/v1/mining/blocks/sizes-weights/{time_period}` pub fn get_block_sizes_weights(&self, time_period: TimePeriod) -> Result { - self.base.get_json(&format!("/api/v1/mining/blocks/sizes-weights/{time_period}")) + self.base.get_json(&format!( + "/api/v1/mining/blocks/sizes-weights/{time_period}" + )) } /// Block by timestamp @@ -7011,7 +10476,8 @@ impl BrkClient { /// /// Endpoint: `GET /api/v1/mining/blocks/timestamp/{timestamp}` pub fn get_block_by_timestamp(&self, timestamp: Timestamp) -> Result { - self.base.get_json(&format!("/api/v1/mining/blocks/timestamp/{timestamp}")) + self.base + .get_json(&format!("/api/v1/mining/blocks/timestamp/{timestamp}")) } /// Difficulty adjustments (all time) @@ -7022,7 +10488,8 @@ impl BrkClient { /// /// Endpoint: `GET /api/v1/mining/difficulty-adjustments` pub fn get_difficulty_adjustments(&self) -> Result> { - self.base.get_json(&format!("/api/v1/mining/difficulty-adjustments")) + self.base + .get_json(&format!("/api/v1/mining/difficulty-adjustments")) } /// Difficulty adjustments @@ -7032,8 +10499,13 @@ impl BrkClient { /// *[Mempool.space docs](https://mempool.space/docs/api/rest#get-difficulty-adjustments)* /// /// Endpoint: `GET /api/v1/mining/difficulty-adjustments/{time_period}` - pub fn get_difficulty_adjustments_by_period(&self, time_period: TimePeriod) -> Result> { - self.base.get_json(&format!("/api/v1/mining/difficulty-adjustments/{time_period}")) + pub fn get_difficulty_adjustments_by_period( + &self, + time_period: TimePeriod, + ) -> Result> { + self.base.get_json(&format!( + "/api/v1/mining/difficulty-adjustments/{time_period}" + )) } /// Network hashrate (all time) @@ -7055,7 +10527,8 @@ impl BrkClient { /// /// Endpoint: `GET /api/v1/mining/hashrate/{time_period}` pub fn get_hashrate_by_period(&self, time_period: TimePeriod) -> Result { - self.base.get_json(&format!("/api/v1/mining/hashrate/{time_period}")) + self.base + .get_json(&format!("/api/v1/mining/hashrate/{time_period}")) } /// Mining pool details @@ -7088,7 +10561,8 @@ impl BrkClient { /// /// Endpoint: `GET /api/v1/mining/pools/{time_period}` pub fn get_pool_stats(&self, time_period: TimePeriod) -> Result { - self.base.get_json(&format!("/api/v1/mining/pools/{time_period}")) + self.base + .get_json(&format!("/api/v1/mining/pools/{time_period}")) } /// Mining reward statistics @@ -7099,7 +10573,8 @@ impl BrkClient { /// /// Endpoint: `GET /api/v1/mining/reward-stats/{block_count}` pub fn get_reward_stats(&self, block_count: i64) -> Result { - self.base.get_json(&format!("/api/v1/mining/reward-stats/{block_count}")) + self.base + .get_json(&format!("/api/v1/mining/reward-stats/{block_count}")) } /// Validate address @@ -7110,7 +10585,8 @@ impl BrkClient { /// /// Endpoint: `GET /api/v1/validate-address/{address}` pub fn validate_address(&self, address: &str) -> Result { - self.base.get_json(&format!("/api/v1/validate-address/{address}")) + self.base + .get_json(&format!("/api/v1/validate-address/{address}")) } /// Health check @@ -7139,5 +10615,4 @@ impl BrkClient { pub fn get_version(&self) -> Result { self.base.get_json(&format!("/version")) } - } diff --git a/crates/brk_cohort/src/by_age_range.rs b/crates/brk_cohort/src/by_age_range.rs index ce5c4a039..1b25e9475 100644 --- a/crates/brk_cohort/src/by_age_range.rs +++ b/crates/brk_cohort/src/by_age_range.rs @@ -1,7 +1,7 @@ use std::ops::Range; -use brk_types::Age; use brk_traversable::Traversable; +use brk_types::Age; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use serde::Serialize; @@ -32,9 +32,9 @@ pub const HOURS_15Y: usize = 24 * 15 * 365; /// Age boundaries in hours. Defines the cohort ranges: /// [0, 1h), [1h, 1d), [1d, 1w), [1w, 1m), ..., [15y, ∞) pub const AGE_BOUNDARIES: [usize; 20] = [ - HOURS_1H, HOURS_1D, HOURS_1W, HOURS_1M, HOURS_2M, HOURS_3M, HOURS_4M, - HOURS_5M, HOURS_6M, HOURS_1Y, HOURS_2Y, HOURS_3Y, HOURS_4Y, HOURS_5Y, - HOURS_6Y, HOURS_7Y, HOURS_8Y, HOURS_10Y, HOURS_12Y, HOURS_15Y, + HOURS_1H, HOURS_1D, HOURS_1W, HOURS_1M, HOURS_2M, HOURS_3M, HOURS_4M, HOURS_5M, HOURS_6M, + HOURS_1Y, HOURS_2Y, HOURS_3Y, HOURS_4Y, HOURS_5Y, HOURS_6Y, HOURS_7Y, HOURS_8Y, HOURS_10Y, + HOURS_12Y, HOURS_15Y, ]; /// Age range bounds (end = usize::MAX means unbounded) diff --git a/crates/brk_cohort/src/by_amount_range.rs b/crates/brk_cohort/src/by_amount_range.rs index 7d918c3d0..73f0e416f 100644 --- a/crates/brk_cohort/src/by_amount_range.rs +++ b/crates/brk_cohort/src/by_amount_range.rs @@ -81,11 +81,7 @@ pub const AMOUNT_RANGE_BOUNDS: ByAmountRange> = ByAmountRange { pub const AMOUNT_RANGE_NAMES: ByAmountRange = ByAmountRange { _0sats: CohortName::new("with_0sats", "0 sats", "0 Sats"), _1sat_to_10sats: CohortName::new("above_1sat_under_10sats", "1-10 sats", "1-10 Sats"), - _10sats_to_100sats: CohortName::new( - "above_10sats_under_100sats", - "10-100 sats", - "10-100 Sats", - ), + _10sats_to_100sats: CohortName::new("above_10sats_under_100sats", "10-100 sats", "10-100 Sats"), _100sats_to_1k_sats: CohortName::new( "above_100sats_under_1k_sats", "100-1k sats", @@ -115,11 +111,7 @@ pub const AMOUNT_RANGE_NAMES: ByAmountRange = ByAmountRange { _1btc_to_10btc: CohortName::new("above_1btc_under_10btc", "1-10 BTC", "1-10 BTC"), _10btc_to_100btc: CohortName::new("above_10btc_under_100btc", "10-100 BTC", "10-100 BTC"), _100btc_to_1k_btc: CohortName::new("above_100btc_under_1k_btc", "100-1k BTC", "100-1K BTC"), - _1k_btc_to_10k_btc: CohortName::new( - "above_1k_btc_under_10k_btc", - "1k-10k BTC", - "1K-10K BTC", - ), + _1k_btc_to_10k_btc: CohortName::new("above_1k_btc_under_10k_btc", "1k-10k BTC", "1K-10K BTC"), _10k_btc_to_100k_btc: CohortName::new( "above_10k_btc_under_100k_btc", "10k-100k BTC", diff --git a/crates/brk_cohort/src/by_max_age.rs b/crates/brk_cohort/src/by_max_age.rs index cc7c584ab..e37501d5f 100644 --- a/crates/brk_cohort/src/by_max_age.rs +++ b/crates/brk_cohort/src/by_max_age.rs @@ -3,9 +3,9 @@ use rayon::prelude::*; use serde::Serialize; use super::{ - CohortName, Filter, TimeFilter, HOURS_10Y, HOURS_12Y, HOURS_15Y, HOURS_1M, HOURS_1W, HOURS_1Y, - HOURS_2M, HOURS_2Y, HOURS_3M, HOURS_3Y, HOURS_4M, HOURS_4Y, HOURS_5M, HOURS_5Y, HOURS_6M, - HOURS_6Y, HOURS_7Y, HOURS_8Y, + CohortName, Filter, HOURS_1M, HOURS_1W, HOURS_1Y, HOURS_2M, HOURS_2Y, HOURS_3M, HOURS_3Y, + HOURS_4M, HOURS_4Y, HOURS_5M, HOURS_5Y, HOURS_6M, HOURS_6Y, HOURS_7Y, HOURS_8Y, HOURS_10Y, + HOURS_12Y, HOURS_15Y, TimeFilter, }; /// Max age thresholds in hours diff --git a/crates/brk_cohort/src/by_min_age.rs b/crates/brk_cohort/src/by_min_age.rs index 1cd444b3e..5939f6ea7 100644 --- a/crates/brk_cohort/src/by_min_age.rs +++ b/crates/brk_cohort/src/by_min_age.rs @@ -3,9 +3,9 @@ use rayon::prelude::*; use serde::Serialize; use super::{ - CohortName, Filter, TimeFilter, HOURS_10Y, HOURS_12Y, HOURS_1D, HOURS_1M, HOURS_1W, HOURS_1Y, - HOURS_2M, HOURS_2Y, HOURS_3M, HOURS_3Y, HOURS_4M, HOURS_4Y, HOURS_5M, HOURS_5Y, HOURS_6M, - HOURS_6Y, HOURS_7Y, HOURS_8Y, + CohortName, Filter, HOURS_1D, HOURS_1M, HOURS_1W, HOURS_1Y, HOURS_2M, HOURS_2Y, HOURS_3M, + HOURS_3Y, HOURS_4M, HOURS_4Y, HOURS_5M, HOURS_5Y, HOURS_6M, HOURS_6Y, HOURS_7Y, HOURS_8Y, + HOURS_10Y, HOURS_12Y, TimeFilter, }; /// Min age thresholds in hours diff --git a/crates/brk_cohort/src/cohort_context.rs b/crates/brk_cohort/src/cohort_context.rs index cdfbd9fcf..d2cf5ac1b 100644 --- a/crates/brk_cohort/src/cohort_context.rs +++ b/crates/brk_cohort/src/cohort_context.rs @@ -28,9 +28,11 @@ impl CohortContext { /// - Context prefix: `Time`, `Amount` pub fn full_name(&self, filter: &Filter, name: &str) -> String { match filter { - Filter::All | Filter::Term(_) | Filter::Epoch(_) | Filter::Year(_) | Filter::Type(_) => { - name.to_string() - } + Filter::All + | Filter::Term(_) + | Filter::Epoch(_) + | Filter::Year(_) + | Filter::Type(_) => name.to_string(), Filter::Time(_) | Filter::Amount(_) => self.prefixed(name), } } diff --git a/crates/brk_cohort/src/lib.rs b/crates/brk_cohort/src/lib.rs index 48448625d..f5eb33c50 100644 --- a/crates/brk_cohort/src/lib.rs +++ b/crates/brk_cohort/src/lib.rs @@ -8,7 +8,6 @@ mod by_amount_range; mod by_any_address; mod by_epoch; mod by_ge_amount; -mod by_year; mod by_lt_amount; mod by_max_age; mod by_min_age; @@ -16,6 +15,7 @@ mod by_spendable_type; mod by_term; mod by_type; mod by_unspendable_type; +mod by_year; mod cohort_context; mod cohort_name; mod filter; diff --git a/crates/brk_computer/src/blocks/compute.rs b/crates/brk_computer/src/blocks/compute.rs index dd8f6ca5c..c9306bef1 100644 --- a/crates/brk_computer/src/blocks/compute.rs +++ b/crates/brk_computer/src/blocks/compute.rs @@ -22,7 +22,8 @@ impl Vecs { .compute(indexer, &self.time, starting_indexes, exit)?; self.interval .compute(indexer, &self.count, starting_indexes, exit)?; - self.size.compute(indexer, &self.count, starting_indexes, exit)?; + self.size + .compute(indexer, &self.count, starting_indexes, exit)?; self.weight .compute(indexer, &self.count, starting_indexes, exit)?; self.difficulty diff --git a/crates/brk_computer/src/blocks/count/compute.rs b/crates/brk_computer/src/blocks/count/compute.rs index ef3c292ee..110d97285 100644 --- a/crates/brk_computer/src/blocks/count/compute.rs +++ b/crates/brk_computer/src/blocks/count/compute.rs @@ -32,120 +32,54 @@ impl Vecs { self.compute_rolling_start_hours(time, starting_indexes, exit, 1, |s| { &mut s.height_1h_ago })?; - self.compute_rolling_start(time, starting_indexes, exit, 1, |s| { - &mut s.height_24h_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 3, |s| { - &mut s.height_3d_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 7, |s| { - &mut s.height_1w_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 8, |s| { - &mut s.height_8d_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 9, |s| { - &mut s.height_9d_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 12, |s| { - &mut s.height_12d_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 13, |s| { - &mut s.height_13d_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 14, |s| { - &mut s.height_2w_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 21, |s| { - &mut s.height_21d_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 26, |s| { - &mut s.height_26d_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 30, |s| { - &mut s.height_1m_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 34, |s| { - &mut s.height_34d_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 55, |s| { - &mut s.height_55d_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 60, |s| { - &mut s.height_2m_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 63, |s| { - &mut s.height_9w_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 84, |s| { - &mut s.height_12w_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 89, |s| { - &mut s.height_89d_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 90, |s| { - &mut s.height_3m_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 98, |s| { - &mut s.height_14w_ago - })?; + self.compute_rolling_start(time, starting_indexes, exit, 1, |s| &mut s.height_24h_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 3, |s| &mut s.height_3d_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 7, |s| &mut s.height_1w_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 8, |s| &mut s.height_8d_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 9, |s| &mut s.height_9d_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 12, |s| &mut s.height_12d_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 13, |s| &mut s.height_13d_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 14, |s| &mut s.height_2w_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 21, |s| &mut s.height_21d_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 26, |s| &mut s.height_26d_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 30, |s| &mut s.height_1m_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 34, |s| &mut s.height_34d_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 55, |s| &mut s.height_55d_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 60, |s| &mut s.height_2m_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 63, |s| &mut s.height_9w_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 84, |s| &mut s.height_12w_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 89, |s| &mut s.height_89d_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 90, |s| &mut s.height_3m_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 98, |s| &mut s.height_14w_ago)?; self.compute_rolling_start(time, starting_indexes, exit, 111, |s| { &mut s.height_111d_ago })?; self.compute_rolling_start(time, starting_indexes, exit, 144, |s| { &mut s.height_144d_ago })?; - self.compute_rolling_start(time, starting_indexes, exit, 180, |s| { - &mut s.height_6m_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 182, |s| { - &mut s.height_26w_ago - })?; + self.compute_rolling_start(time, starting_indexes, exit, 180, |s| &mut s.height_6m_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 182, |s| &mut s.height_26w_ago)?; self.compute_rolling_start(time, starting_indexes, exit, 200, |s| { &mut s.height_200d_ago })?; - self.compute_rolling_start(time, starting_indexes, exit, 270, |s| { - &mut s.height_9m_ago - })?; + self.compute_rolling_start(time, starting_indexes, exit, 270, |s| &mut s.height_9m_ago)?; self.compute_rolling_start(time, starting_indexes, exit, 350, |s| { &mut s.height_350d_ago })?; - self.compute_rolling_start(time, starting_indexes, exit, 360, |s| { - &mut s.height_12m_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 365, |s| { - &mut s.height_1y_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 420, |s| { - &mut s.height_14m_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 730, |s| { - &mut s.height_2y_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 780, |s| { - &mut s.height_26m_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 1095, |s| { - &mut s.height_3y_ago - })?; + self.compute_rolling_start(time, starting_indexes, exit, 360, |s| &mut s.height_12m_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 365, |s| &mut s.height_1y_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 420, |s| &mut s.height_14m_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 730, |s| &mut s.height_2y_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 780, |s| &mut s.height_26m_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 1095, |s| &mut s.height_3y_ago)?; self.compute_rolling_start(time, starting_indexes, exit, 1400, |s| { &mut s.height_200w_ago })?; - self.compute_rolling_start(time, starting_indexes, exit, 1460, |s| { - &mut s.height_4y_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 1825, |s| { - &mut s.height_5y_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 2190, |s| { - &mut s.height_6y_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 2920, |s| { - &mut s.height_8y_ago - })?; - self.compute_rolling_start(time, starting_indexes, exit, 3285, |s| { - &mut s.height_9y_ago - })?; + self.compute_rolling_start(time, starting_indexes, exit, 1460, |s| &mut s.height_4y_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 1825, |s| &mut s.height_5y_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 2190, |s| &mut s.height_6y_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 2920, |s| &mut s.height_8y_ago)?; + self.compute_rolling_start(time, starting_indexes, exit, 3285, |s| &mut s.height_9y_ago)?; self.compute_rolling_start(time, starting_indexes, exit, 3650, |s| { &mut s.height_10y_ago })?; @@ -193,13 +127,9 @@ impl Vecs { where F: FnOnce(&mut Self) -> &mut EagerVec>, { - self.compute_rolling_start_inner( - time, - starting_indexes, - exit, - get_field, - |t, prev_ts| t.difference_in_days_between(prev_ts) >= days, - ) + self.compute_rolling_start_inner(time, starting_indexes, exit, get_field, |t, prev_ts| { + t.difference_in_days_between(prev_ts) >= days + }) } fn compute_rolling_start_hours( @@ -213,13 +143,9 @@ impl Vecs { where F: FnOnce(&mut Self) -> &mut EagerVec>, { - self.compute_rolling_start_inner( - time, - starting_indexes, - exit, - get_field, - |t, prev_ts| t.difference_in_hours_between(prev_ts) >= hours, - ) + self.compute_rolling_start_inner(time, starting_indexes, exit, get_field, |t, prev_ts| { + t.difference_in_hours_between(prev_ts) >= hours + }) } fn compute_rolling_start_inner( diff --git a/crates/brk_computer/src/blocks/count/import.rs b/crates/brk_computer/src/blocks/count/import.rs index 637af210f..53fc9a31a 100644 --- a/crates/brk_computer/src/blocks/count/import.rs +++ b/crates/brk_computer/src/blocks/count/import.rs @@ -9,7 +9,11 @@ use crate::{ }; impl Vecs { - pub(crate) fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { + pub(crate) fn forced_import( + db: &Database, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { Ok(Self { block_count_target: ConstantVecs::new::( "block_count_target", diff --git a/crates/brk_computer/src/blocks/count/vecs.rs b/crates/brk_computer/src/blocks/count/vecs.rs index bda68acd6..7bd8be3d1 100644 --- a/crates/brk_computer/src/blocks/count/vecs.rs +++ b/crates/brk_computer/src/blocks/count/vecs.rs @@ -12,54 +12,52 @@ pub struct Vecs { pub block_count: ComputedFromHeightCumulativeSum, pub block_count_sum: RollingWindows, - // Window starts sorted by duration pub height_1h_ago: M::Stored>>, - pub height_24h_ago: M::Stored>>, // 1d + pub height_24h_ago: M::Stored>>, // 1d pub height_3d_ago: M::Stored>>, - pub height_1w_ago: M::Stored>>, // 7d + pub height_1w_ago: M::Stored>>, // 7d pub height_8d_ago: M::Stored>>, pub height_9d_ago: M::Stored>>, pub height_12d_ago: M::Stored>>, pub height_13d_ago: M::Stored>>, - pub height_2w_ago: M::Stored>>, // 14d + pub height_2w_ago: M::Stored>>, // 14d pub height_21d_ago: M::Stored>>, pub height_26d_ago: M::Stored>>, - pub height_1m_ago: M::Stored>>, // 30d + pub height_1m_ago: M::Stored>>, // 30d pub height_34d_ago: M::Stored>>, pub height_55d_ago: M::Stored>>, - pub height_2m_ago: M::Stored>>, // 60d - pub height_9w_ago: M::Stored>>, // 63d - pub height_12w_ago: M::Stored>>, // 84d + pub height_2m_ago: M::Stored>>, // 60d + pub height_9w_ago: M::Stored>>, // 63d + pub height_12w_ago: M::Stored>>, // 84d pub height_89d_ago: M::Stored>>, - pub height_3m_ago: M::Stored>>, // 90d - pub height_14w_ago: M::Stored>>, // 98d + pub height_3m_ago: M::Stored>>, // 90d + pub height_14w_ago: M::Stored>>, // 98d pub height_111d_ago: M::Stored>>, pub height_144d_ago: M::Stored>>, - pub height_6m_ago: M::Stored>>, // 180d - pub height_26w_ago: M::Stored>>, // 182d + pub height_6m_ago: M::Stored>>, // 180d + pub height_26w_ago: M::Stored>>, // 182d pub height_200d_ago: M::Stored>>, - pub height_9m_ago: M::Stored>>, // 270d + pub height_9m_ago: M::Stored>>, // 270d pub height_350d_ago: M::Stored>>, - pub height_12m_ago: M::Stored>>, // 360d - pub height_1y_ago: M::Stored>>, // 365d - pub height_14m_ago: M::Stored>>, // 420d - pub height_2y_ago: M::Stored>>, // 730d - pub height_26m_ago: M::Stored>>, // 780d - pub height_3y_ago: M::Stored>>, // 1095d - pub height_200w_ago: M::Stored>>, // 1400d - pub height_4y_ago: M::Stored>>, // 1460d - pub height_5y_ago: M::Stored>>, // 1825d - pub height_6y_ago: M::Stored>>, // 2190d - pub height_8y_ago: M::Stored>>, // 2920d - pub height_9y_ago: M::Stored>>, // 3285d - pub height_10y_ago: M::Stored>>, // 3650d - pub height_12y_ago: M::Stored>>, // 4380d - pub height_14y_ago: M::Stored>>, // 5110d - pub height_26y_ago: M::Stored>>, // 9490d + pub height_12m_ago: M::Stored>>, // 360d + pub height_1y_ago: M::Stored>>, // 365d + pub height_14m_ago: M::Stored>>, // 420d + pub height_2y_ago: M::Stored>>, // 730d + pub height_26m_ago: M::Stored>>, // 780d + pub height_3y_ago: M::Stored>>, // 1095d + pub height_200w_ago: M::Stored>>, // 1400d + pub height_4y_ago: M::Stored>>, // 1460d + pub height_5y_ago: M::Stored>>, // 1825d + pub height_6y_ago: M::Stored>>, // 2190d + pub height_8y_ago: M::Stored>>, // 2920d + pub height_9y_ago: M::Stored>>, // 3285d + pub height_10y_ago: M::Stored>>, // 3650d + pub height_12y_ago: M::Stored>>, // 4380d + pub height_14y_ago: M::Stored>>, // 5110d + pub height_26y_ago: M::Stored>>, // 9490d } impl Vecs { - /// Get the standard 4 rolling window start heights (24h, 1w, 1m, 1y). pub fn window_starts(&self) -> WindowStarts<'_> { WindowStarts { _24h: &self.height_24h_ago, diff --git a/crates/brk_computer/src/blocks/difficulty/compute.rs b/crates/brk_computer/src/blocks/difficulty/compute.rs index 9ab53ac53..639bcd3ba 100644 --- a/crates/brk_computer/src/blocks/difficulty/compute.rs +++ b/crates/brk_computer/src/blocks/difficulty/compute.rs @@ -43,12 +43,14 @@ impl Vecs { )?; // Compute blocks before next adjustment - self.blocks_before_next_adjustment.height.compute_transform( - starting_indexes.height, - &indexes.height.identity, - |(h, ..)| (h, StoredU32::from(h.left_before_next_diff_adj())), - exit, - )?; + self.blocks_before_next_adjustment + .height + .compute_transform( + starting_indexes.height, + &indexes.height.identity, + |(h, ..)| (h, StoredU32::from(h.left_before_next_diff_adj())), + exit, + )?; // Compute days before next adjustment self.days_before_next_adjustment.height.compute_transform( diff --git a/crates/brk_computer/src/blocks/difficulty/import.rs b/crates/brk_computer/src/blocks/difficulty/import.rs index b1e46aeaf..633585bd4 100644 --- a/crates/brk_computer/src/blocks/difficulty/import.rs +++ b/crates/brk_computer/src/blocks/difficulty/import.rs @@ -26,7 +26,12 @@ impl Vecs { indexes, ), as_hash: ComputedFromHeight::forced_import(db, "difficulty_as_hash", version, indexes)?, - adjustment: PercentFromHeight::forced_import(db, "difficulty_adjustment", version, indexes)?, + adjustment: PercentFromHeight::forced_import( + db, + "difficulty_adjustment", + version, + indexes, + )?, epoch: ComputedFromHeight::forced_import(db, "difficulty_epoch", version, indexes)?, blocks_before_next_adjustment: ComputedFromHeight::forced_import( db, diff --git a/crates/brk_computer/src/blocks/difficulty/vecs.rs b/crates/brk_computer/src/blocks/difficulty/vecs.rs index 4e202c00f..1ef4ebd24 100644 --- a/crates/brk_computer/src/blocks/difficulty/vecs.rs +++ b/crates/brk_computer/src/blocks/difficulty/vecs.rs @@ -3,8 +3,6 @@ use brk_types::{BasisPointsSigned32, DifficultyEpoch, StoredF32, StoredF64, Stor use vecdb::{Rw, StorageMode}; use crate::internal::{ComputedFromHeight, ComputedHeightDerived, PercentFromHeight}; - -/// Difficulty metrics: raw difficulty, derived stats, adjustment, and countdown #[derive(Traversable)] pub struct Vecs { pub raw: ComputedHeightDerived, diff --git a/crates/brk_computer/src/blocks/halving/vecs.rs b/crates/brk_computer/src/blocks/halving/vecs.rs index 60e6dcdb4..c0ca8afea 100644 --- a/crates/brk_computer/src/blocks/halving/vecs.rs +++ b/crates/brk_computer/src/blocks/halving/vecs.rs @@ -3,8 +3,6 @@ use brk_types::{HalvingEpoch, StoredF32, StoredU32}; use vecdb::{Rw, StorageMode}; use crate::internal::ComputedFromHeight; - -/// Halving epoch metrics and countdown #[derive(Traversable)] pub struct Vecs { pub epoch: ComputedFromHeight, diff --git a/crates/brk_computer/src/blocks/import.rs b/crates/brk_computer/src/blocks/import.rs index 7c9a08a9a..9830c2994 100644 --- a/crates/brk_computer/src/blocks/import.rs +++ b/crates/brk_computer/src/blocks/import.rs @@ -2,15 +2,15 @@ use std::path::Path; use brk_error::Result; use brk_indexer::Indexer; -use brk_traversable::Traversable; use brk_types::Version; -use vecdb::{Database, PAGE_SIZE}; -use crate::indexes; +use crate::{ + indexes, + internal::{finalize_db, open_db}, +}; use super::{ - CountVecs, DifficultyVecs, HalvingVecs, IntervalVecs, SizeVecs, - TimeVecs, Vecs, WeightVecs, + CountVecs, DifficultyVecs, HalvingVecs, IntervalVecs, SizeVecs, TimeVecs, Vecs, WeightVecs, }; impl Vecs { @@ -20,9 +20,7 @@ impl Vecs { indexer: &Indexer, indexes: &indexes::Vecs, ) -> Result { - let db = Database::open(&parent_path.join(super::DB_NAME))?; - db.set_min_len(PAGE_SIZE * 50_000_000)?; - + let db = open_db(parent_path, super::DB_NAME, 50_000_000)?; let version = parent_version; let count = CountVecs::forced_import(&db, version, indexes)?; @@ -43,14 +41,7 @@ impl Vecs { difficulty, halving, }; - - this.db.retain_regions( - this.iter_any_exportable() - .flat_map(|v| v.region_names()) - .collect(), - )?; - this.db.compact()?; - + finalize_db(&this.db, &this)?; Ok(this) } } diff --git a/crates/brk_computer/src/blocks/interval/compute.rs b/crates/brk_computer/src/blocks/interval/compute.rs index 6ce98b497..9d0e04b18 100644 --- a/crates/brk_computer/src/blocks/interval/compute.rs +++ b/crates/brk_computer/src/blocks/interval/compute.rs @@ -16,11 +16,8 @@ impl Vecs { ) -> Result<()> { let mut prev_timestamp = None; let window_starts = count_vecs.window_starts(); - self.0.compute( - starting_indexes.height, - &window_starts, - exit, - |vec| { + self.0 + .compute(starting_indexes.height, &window_starts, exit, |vec| { vec.compute_transform( starting_indexes.height, &indexer.vecs.blocks.timestamp, @@ -39,8 +36,7 @@ impl Vecs { exit, )?; Ok(()) - }, - )?; + })?; Ok(()) } diff --git a/crates/brk_computer/src/blocks/interval/vecs.rs b/crates/brk_computer/src/blocks/interval/vecs.rs index 1edfffff8..eb9cecabb 100644 --- a/crates/brk_computer/src/blocks/interval/vecs.rs +++ b/crates/brk_computer/src/blocks/interval/vecs.rs @@ -8,6 +8,5 @@ use crate::internal::ComputedFromHeightDistribution; #[derive(Deref, DerefMut, Traversable)] pub struct Vecs( - #[traversable(flatten)] - pub ComputedFromHeightDistribution, + #[traversable(flatten)] pub ComputedFromHeightDistribution, ); diff --git a/crates/brk_computer/src/blocks/size/compute.rs b/crates/brk_computer/src/blocks/size/compute.rs index ad8d7340a..46b9d72ad 100644 --- a/crates/brk_computer/src/blocks/size/compute.rs +++ b/crates/brk_computer/src/blocks/size/compute.rs @@ -17,19 +17,15 @@ impl Vecs { let window_starts = count_vecs.window_starts(); // vbytes = floor(weight / 4), stored at height level - self.vbytes.compute( - starting_indexes.height, - &window_starts, - exit, - |height| { + self.vbytes + .compute(starting_indexes.height, &window_starts, exit, |height| { Ok(height.compute_transform( starting_indexes.height, &indexer.vecs.blocks.weight, |(h, weight, ..)| (h, StoredU64::from(weight.to_vbytes_floor())), exit, )?) - }, - )?; + })?; // size from indexer total_size self.size.compute( diff --git a/crates/brk_computer/src/blocks/size/import.rs b/crates/brk_computer/src/blocks/size/import.rs index 4557fb0ff..538626211 100644 --- a/crates/brk_computer/src/blocks/size/import.rs +++ b/crates/brk_computer/src/blocks/size/import.rs @@ -15,18 +15,8 @@ impl Vecs { indexes: &indexes::Vecs, ) -> Result { Ok(Self { - vbytes: ComputedFromHeightFull::forced_import( - db, - "block_vbytes", - version, - indexes, - )?, - size: ComputedHeightDerivedFull::forced_import( - db, - "block_size", - version, - indexes, - )?, + vbytes: ComputedFromHeightFull::forced_import(db, "block_vbytes", version, indexes)?, + size: ComputedHeightDerivedFull::forced_import(db, "block_size", version, indexes)?, }) } } diff --git a/crates/brk_computer/src/blocks/time/import.rs b/crates/brk_computer/src/blocks/time/import.rs index 584e0b9ca..68aa2aaf9 100644 --- a/crates/brk_computer/src/blocks/time/import.rs +++ b/crates/brk_computer/src/blocks/time/import.rs @@ -11,8 +11,7 @@ impl Vecs { version: Version, indexes: &indexes::Vecs, ) -> Result { - let timestamp_monotonic = - EagerVec::forced_import(db, "timestamp_monotonic", version)?; + let timestamp_monotonic = EagerVec::forced_import(db, "timestamp_monotonic", version)?; Ok(Self { date: LazyVecFrom1::init( @@ -28,11 +27,7 @@ impl Vecs { } impl TimestampIndexes { - fn forced_import( - db: &Database, - version: Version, - indexes: &indexes::Vecs, - ) -> Result { + fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { macro_rules! period { ($field:ident) => { LazyVecFrom1::init( @@ -50,6 +45,22 @@ impl TimestampIndexes { }; } - Ok(Self(crate::indexes_from!(period, epoch))) + Ok(Self(crate::internal::PerPeriod { + minute10: period!(minute10), + minute30: period!(minute30), + hour1: period!(hour1), + hour4: period!(hour4), + hour12: period!(hour12), + day1: period!(day1), + day3: period!(day3), + week1: period!(week1), + month1: period!(month1), + month3: period!(month3), + month6: period!(month6), + year1: period!(year1), + year10: period!(year10), + halvingepoch: epoch!(halvingepoch), + difficultyepoch: epoch!(difficultyepoch), + })) } } diff --git a/crates/brk_computer/src/blocks/time/vecs.rs b/crates/brk_computer/src/blocks/time/vecs.rs index 027582ac4..2d1f30c5b 100644 --- a/crates/brk_computer/src/blocks/time/vecs.rs +++ b/crates/brk_computer/src/blocks/time/vecs.rs @@ -1,15 +1,13 @@ use brk_error::Result; use brk_traversable::Traversable; use brk_types::{ - Date, Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour12, Hour4, - Indexes, Minute10, Minute30, Month1, Month3, Month6, Timestamp, Week1, Year1, Year10, + Date, Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour4, Hour12, Indexes, + Minute10, Minute30, Month1, Month3, Month6, Timestamp, Week1, Year1, Year10, }; use derive_more::{Deref, DerefMut}; use vecdb::{EagerVec, Exit, LazyVecFrom1, PcoVec, ReadableVec, Rw, StorageMode}; use crate::{indexes, internal::PerPeriod}; - -/// Timestamp and date metrics for blocks #[derive(Traversable)] pub struct Vecs { pub date: LazyVecFrom1, @@ -58,13 +56,21 @@ impl TimestampIndexes { ) -> Result<()> { let prev_height = starting_indexes.height.decremented().unwrap_or_default(); self.halvingepoch.compute_indirect_sequential( - indexes.height.halvingepoch.collect_one(prev_height).unwrap_or_default(), + indexes + .height + .halvingepoch + .collect_one(prev_height) + .unwrap_or_default(), &indexes.halvingepoch.first_height, &indexer.vecs.blocks.timestamp, exit, )?; self.difficultyepoch.compute_indirect_sequential( - indexes.height.difficultyepoch.collect_one(prev_height).unwrap_or_default(), + indexes + .height + .difficultyepoch + .collect_one(prev_height) + .unwrap_or_default(), &indexes.difficultyepoch.first_height, &indexer.vecs.blocks.timestamp, exit, diff --git a/crates/brk_computer/src/blocks/weight/compute.rs b/crates/brk_computer/src/blocks/weight/compute.rs index ad023b4e2..560198635 100644 --- a/crates/brk_computer/src/blocks/weight/compute.rs +++ b/crates/brk_computer/src/blocks/weight/compute.rs @@ -23,11 +23,8 @@ impl Vecs { exit, )?; - self.fullness.compute( - starting_indexes.height, - &window_starts, - exit, - |vec| { + self.fullness + .compute(starting_indexes.height, &window_starts, exit, |vec| { vec.compute_transform( starting_indexes.height, &indexer.vecs.blocks.weight, @@ -35,8 +32,7 @@ impl Vecs { exit, )?; Ok(()) - }, - )?; + })?; Ok(()) } diff --git a/crates/brk_computer/src/blocks/weight/import.rs b/crates/brk_computer/src/blocks/weight/import.rs index 509939140..455ced995 100644 --- a/crates/brk_computer/src/blocks/weight/import.rs +++ b/crates/brk_computer/src/blocks/weight/import.rs @@ -14,12 +14,8 @@ impl Vecs { version: Version, indexes: &indexes::Vecs, ) -> Result { - let weight = ComputedHeightDerivedFull::forced_import( - db, - "block_weight", - version, - indexes, - )?; + let weight = + ComputedHeightDerivedFull::forced_import(db, "block_weight", version, indexes)?; let fullness = PercentFromHeightDistribution::forced_import(db, "block_fullness", version, indexes)?; diff --git a/crates/brk_computer/src/cointime/activity/import.rs b/crates/brk_computer/src/cointime/activity/import.rs index cafb00fad..c37947bab 100644 --- a/crates/brk_computer/src/cointime/activity/import.rs +++ b/crates/brk_computer/src/cointime/activity/import.rs @@ -5,11 +5,15 @@ use vecdb::Database; use super::Vecs; use crate::{ indexes, - internal::{ComputedFromHeightCumulativeSum, ComputedFromHeight}, + internal::{ComputedFromHeight, ComputedFromHeightCumulativeSum}, }; impl Vecs { - pub(crate) fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { + pub(crate) fn forced_import( + db: &Database, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { Ok(Self { coinblocks_created: ComputedFromHeightCumulativeSum::forced_import( db, diff --git a/crates/brk_computer/src/cointime/activity/vecs.rs b/crates/brk_computer/src/cointime/activity/vecs.rs index bd2dd4d24..79d11a499 100644 --- a/crates/brk_computer/src/cointime/activity/vecs.rs +++ b/crates/brk_computer/src/cointime/activity/vecs.rs @@ -2,7 +2,7 @@ use brk_traversable::Traversable; use brk_types::StoredF64; use vecdb::{Rw, StorageMode}; -use crate::internal::{ComputedFromHeightCumulativeSum, ComputedFromHeight}; +use crate::internal::{ComputedFromHeight, ComputedFromHeightCumulativeSum}; #[derive(Traversable)] pub struct Vecs { diff --git a/crates/brk_computer/src/cointime/adjusted/compute.rs b/crates/brk_computer/src/cointime/adjusted/compute.rs index 1c235e5cb..5561c26c2 100644 --- a/crates/brk_computer/src/cointime/adjusted/compute.rs +++ b/crates/brk_computer/src/cointime/adjusted/compute.rs @@ -14,31 +14,35 @@ impl Vecs { activity: &activity::Vecs, exit: &Exit, ) -> Result<()> { - self.cointime_adj_inflation_rate.bps.height.compute_transform2( + self.cointime_adj_inflation_rate + .bps + .height + .compute_transform2( + starting_indexes.height, + &activity.liveliness.height, + &supply.inflation_rate.bps.height, + |(h, liveliness, inflation, ..)| { + ( + h, + BasisPointsSigned32::from(f64::from(liveliness) * f64::from(inflation)), + ) + }, + exit, + )?; + + self.cointime_adj_tx_velocity_btc.height.compute_multiply( starting_indexes.height, - &activity.liveliness.height, - &supply.inflation_rate.bps.height, - |(h, liveliness, inflation, ..)| (h, BasisPointsSigned32::from(f64::from(liveliness) * f64::from(inflation))), + &activity.activity_to_vaultedness_ratio.height, + &supply.velocity.btc.height, exit, )?; - self.cointime_adj_tx_velocity_btc - .height - .compute_multiply( - starting_indexes.height, - &activity.activity_to_vaultedness_ratio.height, - &supply.velocity.btc.height, - exit, - )?; - - self.cointime_adj_tx_velocity_usd - .height - .compute_multiply( - starting_indexes.height, - &activity.activity_to_vaultedness_ratio.height, - &supply.velocity.usd.height, - exit, - )?; + self.cointime_adj_tx_velocity_usd.height.compute_multiply( + starting_indexes.height, + &activity.activity_to_vaultedness_ratio.height, + &supply.velocity.usd.height, + exit, + )?; Ok(()) } diff --git a/crates/brk_computer/src/cointime/adjusted/import.rs b/crates/brk_computer/src/cointime/adjusted/import.rs index 2881cbf35..f5e23032b 100644 --- a/crates/brk_computer/src/cointime/adjusted/import.rs +++ b/crates/brk_computer/src/cointime/adjusted/import.rs @@ -9,7 +9,11 @@ use crate::{ }; impl Vecs { - pub(crate) fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { + pub(crate) fn forced_import( + db: &Database, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { Ok(Self { cointime_adj_inflation_rate: PercentFromHeight::forced_import( db, diff --git a/crates/brk_computer/src/cointime/cap/import.rs b/crates/brk_computer/src/cointime/cap/import.rs index f3fcc1275..9b04365d1 100644 --- a/crates/brk_computer/src/cointime/cap/import.rs +++ b/crates/brk_computer/src/cointime/cap/import.rs @@ -6,7 +6,11 @@ use super::Vecs; use crate::{indexes, internal::FiatFromHeight}; impl Vecs { - pub(crate) fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { + pub(crate) fn forced_import( + db: &Database, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { Ok(Self { thermo_cap: FiatFromHeight::forced_import(db, "thermo_cap", version, indexes)?, investor_cap: FiatFromHeight::forced_import(db, "investor_cap", version, indexes)?, diff --git a/crates/brk_computer/src/cointime/compute.rs b/crates/brk_computer/src/cointime/compute.rs index e906cd0aa..a02af0d93 100644 --- a/crates/brk_computer/src/cointime/compute.rs +++ b/crates/brk_computer/src/cointime/compute.rs @@ -22,12 +22,8 @@ impl Vecs { .compute(starting_indexes, blocks, distribution, exit)?; // Supply computes next (depends on activity) - self.supply.compute( - starting_indexes, - distribution, - &self.activity, - exit, - )?; + self.supply + .compute(starting_indexes, distribution, &self.activity, exit)?; // Adjusted velocity metrics (BTC) - can compute without price self.adjusted diff --git a/crates/brk_computer/src/cointime/import.rs b/crates/brk_computer/src/cointime/import.rs index 7885fb6e2..c829c4309 100644 --- a/crates/brk_computer/src/cointime/import.rs +++ b/crates/brk_computer/src/cointime/import.rs @@ -1,15 +1,17 @@ use std::path::Path; use brk_error::Result; -use brk_traversable::Traversable; use brk_types::Version; -use vecdb::{Database, PAGE_SIZE}; + +use crate::{ + indexes, + internal::{finalize_db, open_db}, +}; use super::{ ActivityVecs, AdjustedVecs, CapVecs, DB_NAME, PricingVecs, ReserveRiskVecs, SupplyVecs, ValueVecs, Vecs, }; -use crate::indexes; impl Vecs { pub(crate) fn forced_import( @@ -17,9 +19,7 @@ impl Vecs { parent_version: Version, indexes: &indexes::Vecs, ) -> Result { - let db = Database::open(&parent_path.join(DB_NAME))?; - db.set_min_len(PAGE_SIZE * 1_000_000)?; - + let db = open_db(parent_path, DB_NAME, 1_000_000)?; let version = parent_version; let v1 = version + Version::ONE; let activity = ActivityVecs::forced_import(&db, version, indexes)?; @@ -40,14 +40,7 @@ impl Vecs { adjusted, reserve_risk, }; - - this.db.retain_regions( - this.iter_any_exportable() - .flat_map(|v| v.region_names()) - .collect(), - )?; - this.db.compact()?; - + finalize_db(&this.db, &this)?; Ok(this) } } diff --git a/crates/brk_computer/src/cointime/reserve_risk/compute.rs b/crates/brk_computer/src/cointime/reserve_risk/compute.rs index b2a647cc8..e469c6703 100644 --- a/crates/brk_computer/src/cointime/reserve_risk/compute.rs +++ b/crates/brk_computer/src/cointime/reserve_risk/compute.rs @@ -3,7 +3,7 @@ use brk_types::{Indexes, StoredF64}; use vecdb::Exit; use super::{super::value, Vecs}; -use crate::{blocks, prices, traits::ComputeRollingMedianFromStarts}; +use crate::{blocks, internal::ComputeRollingMedianFromStarts, prices}; impl Vecs { pub(crate) fn compute( diff --git a/crates/brk_computer/src/cointime/supply/import.rs b/crates/brk_computer/src/cointime/supply/import.rs index 7b9e3900f..bfa7bb2ff 100644 --- a/crates/brk_computer/src/cointime/supply/import.rs +++ b/crates/brk_computer/src/cointime/supply/import.rs @@ -12,18 +12,8 @@ impl Vecs { indexes: &indexes::Vecs, ) -> Result { Ok(Self { - vaulted_supply: ValueFromHeight::forced_import( - db, - "vaulted_supply", - version, - indexes, - )?, - active_supply: ValueFromHeight::forced_import( - db, - "active_supply", - version, - indexes, - )?, + vaulted_supply: ValueFromHeight::forced_import(db, "vaulted_supply", version, indexes)?, + active_supply: ValueFromHeight::forced_import(db, "active_supply", version, indexes)?, }) } } diff --git a/crates/brk_computer/src/cointime/value/compute.rs b/crates/brk_computer/src/cointime/value/compute.rs index 02f42764b..a7310fe4a 100644 --- a/crates/brk_computer/src/cointime/value/compute.rs +++ b/crates/brk_computer/src/cointime/value/compute.rs @@ -41,8 +41,11 @@ impl Vecs { .btc .height; - self.cointime_value_destroyed - .compute(starting_indexes.height, &window_starts, exit, |vec| { + self.cointime_value_destroyed.compute( + starting_indexes.height, + &window_starts, + exit, + |vec| { vec.compute_multiply( starting_indexes.height, &prices.price.usd.height, @@ -50,10 +53,14 @@ impl Vecs { exit, )?; Ok(()) - })?; + }, + )?; - self.cointime_value_created - .compute(starting_indexes.height, &window_starts, exit, |vec| { + self.cointime_value_created.compute( + starting_indexes.height, + &window_starts, + exit, + |vec| { vec.compute_multiply( starting_indexes.height, &prices.price.usd.height, @@ -61,10 +68,14 @@ impl Vecs { exit, )?; Ok(()) - })?; + }, + )?; - self.cointime_value_stored - .compute(starting_indexes.height, &window_starts, exit, |vec| { + self.cointime_value_stored.compute( + starting_indexes.height, + &window_starts, + exit, + |vec| { vec.compute_multiply( starting_indexes.height, &prices.price.usd.height, @@ -72,7 +83,8 @@ impl Vecs { exit, )?; Ok(()) - })?; + }, + )?; // VOCDD: Value of Coin Days Destroyed = price × (CDD / circulating_supply) // Supply-adjusted to account for growing supply over time diff --git a/crates/brk_computer/src/cointime/value/import.rs b/crates/brk_computer/src/cointime/value/import.rs index 734418927..5601eaa11 100644 --- a/crates/brk_computer/src/cointime/value/import.rs +++ b/crates/brk_computer/src/cointime/value/import.rs @@ -6,7 +6,11 @@ use super::Vecs; use crate::{indexes, internal::ComputedFromHeightCumulativeSum}; impl Vecs { - pub(crate) fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { + pub(crate) fn forced_import( + db: &Database, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { Ok(Self { cointime_value_destroyed: ComputedFromHeightCumulativeSum::forced_import( db, diff --git a/crates/brk_computer/src/distribution/address/activity.rs b/crates/brk_computer/src/distribution/address/activity.rs index ec0bfe250..c590e04de 100644 --- a/crates/brk_computer/src/distribution/address/activity.rs +++ b/crates/brk_computer/src/distribution/address/activity.rs @@ -22,7 +22,10 @@ use derive_more::{Deref, DerefMut}; use rayon::prelude::*; use vecdb::{AnyStoredVec, AnyVec, Database, Exit, Rw, StorageMode, WritableVec}; -use crate::{indexes, internal::{ComputedFromHeightDistribution, WindowStarts}}; +use crate::{ + indexes, + internal::{ComputedFromHeightDistribution, WindowStarts}, +}; /// Per-block activity counts - reset each block. /// @@ -137,7 +140,9 @@ impl ActivityCountVecs { .min(self.both.height.len()) } - pub(crate) fn par_iter_height_mut(&mut self) -> impl ParallelIterator { + pub(crate) fn par_iter_height_mut( + &mut self, + ) -> impl ParallelIterator { [ &mut self.reactivated.height as &mut dyn AnyStoredVec, &mut self.sending.height as &mut dyn AnyStoredVec, @@ -181,9 +186,7 @@ impl ActivityCountVecs { self.balance_decreased .height .truncate_push(height, (counts.sending - counts.both).into())?; - self.both - .height - .truncate_push(height, counts.both.into())?; + self.both.height.truncate_push(height, counts.both.into())?; Ok(()) } @@ -196,8 +199,10 @@ impl ActivityCountVecs { self.reactivated.compute_rest(max_from, windows, exit)?; self.sending.compute_rest(max_from, windows, exit)?; self.receiving.compute_rest(max_from, windows, exit)?; - self.balance_increased.compute_rest(max_from, windows, exit)?; - self.balance_decreased.compute_rest(max_from, windows, exit)?; + self.balance_increased + .compute_rest(max_from, windows, exit)?; + self.balance_decreased + .compute_rest(max_from, windows, exit)?; self.both.compute_rest(max_from, windows, exit)?; Ok(()) } @@ -223,16 +228,27 @@ impl AddressTypeToActivityCountVecs { ) -> Result { Ok(Self::from( ByAddressType::::new_with_name(|type_name| { - ActivityCountVecs::forced_import(db, &format!("{type_name}_{name}"), version, indexes) + ActivityCountVecs::forced_import( + db, + &format!("{type_name}_{name}"), + version, + indexes, + ) })?, )) } pub(crate) fn min_stateful_height(&self) -> usize { - self.0.values().map(|v| v.min_stateful_height()).min().unwrap_or(0) + self.0 + .values() + .map(|v| v.min_stateful_height()) + .min() + .unwrap_or(0) } - pub(crate) fn par_iter_height_mut(&mut self) -> impl ParallelIterator { + pub(crate) fn par_iter_height_mut( + &mut self, + ) -> impl ParallelIterator { let mut vecs: Vec<&mut dyn AnyStoredVec> = Vec::new(); for type_vecs in self.0.values_mut() { vecs.push(&mut type_vecs.reactivated.height); @@ -274,7 +290,6 @@ impl AddressTypeToActivityCountVecs { } Ok(()) } - } /// Storage for activity metrics (global + per type). @@ -301,10 +316,14 @@ impl AddressActivityVecs { } pub(crate) fn min_stateful_height(&self) -> usize { - self.all.min_stateful_height().min(self.by_addresstype.min_stateful_height()) + self.all + .min_stateful_height() + .min(self.by_addresstype.min_stateful_height()) } - pub(crate) fn par_iter_height_mut(&mut self) -> impl ParallelIterator { + pub(crate) fn par_iter_height_mut( + &mut self, + ) -> impl ParallelIterator { self.all .par_iter_height_mut() .chain(self.by_addresstype.par_iter_height_mut()) @@ -337,5 +356,4 @@ impl AddressActivityVecs { self.by_addresstype.truncate_push_height(height, counts)?; Ok(()) } - } diff --git a/crates/brk_computer/src/distribution/address/address_count.rs b/crates/brk_computer/src/distribution/address/address_count.rs index a4ef99b3e..ceb88d680 100644 --- a/crates/brk_computer/src/distribution/address/address_count.rs +++ b/crates/brk_computer/src/distribution/address/address_count.rs @@ -70,14 +70,62 @@ impl From<(&AddressTypeToAddrCountVecs, Height)> for AddressTypeToAddressCount { fn from((groups, starting_height): (&AddressTypeToAddrCountVecs, Height)) -> Self { if let Some(prev_height) = starting_height.decremented() { Self(ByAddressType { - p2pk65: groups.p2pk65.count.height.collect_one(prev_height).unwrap().into(), - p2pk33: groups.p2pk33.count.height.collect_one(prev_height).unwrap().into(), - p2pkh: groups.p2pkh.count.height.collect_one(prev_height).unwrap().into(), - p2sh: groups.p2sh.count.height.collect_one(prev_height).unwrap().into(), - p2wpkh: groups.p2wpkh.count.height.collect_one(prev_height).unwrap().into(), - p2wsh: groups.p2wsh.count.height.collect_one(prev_height).unwrap().into(), - p2tr: groups.p2tr.count.height.collect_one(prev_height).unwrap().into(), - p2a: groups.p2a.count.height.collect_one(prev_height).unwrap().into(), + p2pk65: groups + .p2pk65 + .count + .height + .collect_one(prev_height) + .unwrap() + .into(), + p2pk33: groups + .p2pk33 + .count + .height + .collect_one(prev_height) + .unwrap() + .into(), + p2pkh: groups + .p2pkh + .count + .height + .collect_one(prev_height) + .unwrap() + .into(), + p2sh: groups + .p2sh + .count + .height + .collect_one(prev_height) + .unwrap() + .into(), + p2wpkh: groups + .p2wpkh + .count + .height + .collect_one(prev_height) + .unwrap() + .into(), + p2wsh: groups + .p2wsh + .count + .height + .collect_one(prev_height) + .unwrap() + .into(), + p2tr: groups + .p2tr + .count + .height + .collect_one(prev_height) + .unwrap() + .into(), + p2a: groups + .p2a + .count + .height + .collect_one(prev_height) + .unwrap() + .into(), }) } else { Default::default() @@ -103,24 +151,23 @@ impl AddressTypeToAddrCountVecs { version: Version, indexes: &indexes::Vecs, ) -> Result { - Ok(Self::from( - ByAddressType::::new_with_name(|type_name| { - AddrCountVecs::forced_import( - db, - &format!("{type_name}_{name}"), - version, - indexes, - ) - })?, - )) + Ok(Self::from(ByAddressType::::new_with_name( + |type_name| { + AddrCountVecs::forced_import(db, &format!("{type_name}_{name}"), version, indexes) + }, + )?)) } pub(crate) fn min_stateful_height(&self) -> usize { self.0.values().map(|v| v.count.height.len()).min().unwrap() } - pub(crate) fn par_iter_height_mut(&mut self) -> impl ParallelIterator { - self.0.par_values_mut().map(|v| &mut v.count.height as &mut dyn AnyStoredVec) + pub(crate) fn par_iter_height_mut( + &mut self, + ) -> impl ParallelIterator { + self.0 + .par_values_mut() + .map(|v| &mut v.count.height as &mut dyn AnyStoredVec) } pub(crate) fn truncate_push_height( @@ -180,10 +227,16 @@ impl AddrCountsVecs { } pub(crate) fn min_stateful_height(&self) -> usize { - self.all.count.height.len().min(self.by_addresstype.min_stateful_height()) + self.all + .count + .height + .len() + .min(self.by_addresstype.min_stateful_height()) } - pub(crate) fn par_iter_height_mut(&mut self) -> impl ParallelIterator { + pub(crate) fn par_iter_height_mut( + &mut self, + ) -> impl ParallelIterator { rayon::iter::once(&mut self.all.count.height as &mut dyn AnyStoredVec) .chain(self.by_addresstype.par_iter_height_mut()) } diff --git a/crates/brk_computer/src/distribution/address/data.rs b/crates/brk_computer/src/distribution/address/data.rs index b56455638..a0d3420db 100644 --- a/crates/brk_computer/src/distribution/address/data.rs +++ b/crates/brk_computer/src/distribution/address/data.rs @@ -4,9 +4,7 @@ use brk_types::{ EmptyAddressData, EmptyAddressIndex, FundedAddressData, FundedAddressIndex, Height, }; use rayon::prelude::*; -use vecdb::{ - AnyStoredVec, BytesVec, Rw, Stamp, StorageMode, WritableVec, -}; +use vecdb::{AnyStoredVec, BytesVec, Rw, Stamp, StorageMode, WritableVec}; /// Storage for both funded and empty address data. #[derive(Traversable)] diff --git a/crates/brk_computer/src/distribution/address/growth_rate.rs b/crates/brk_computer/src/distribution/address/growth_rate.rs index f871d04e7..f049895f2 100644 --- a/crates/brk_computer/src/distribution/address/growth_rate.rs +++ b/crates/brk_computer/src/distribution/address/growth_rate.rs @@ -1,5 +1,3 @@ -//! Growth rate: new_addr_count / addr_count (global + per-type) - use brk_cohort::ByAddressType; use brk_error::Result; use brk_traversable::Traversable; @@ -27,12 +25,8 @@ impl GrowthRateVecs { version: Version, indexes: &indexes::Vecs, ) -> Result { - let all = PercentFromHeightDistribution::forced_import( - db, - "growth_rate", - version, - indexes, - )?; + let all = + PercentFromHeightDistribution::forced_import(db, "growth_rate", version, indexes)?; let by_addresstype = ByAddressType::new_with_name(|name| { PercentFromHeightDistribution::forced_import( @@ -43,7 +37,10 @@ impl GrowthRateVecs { ) })?; - Ok(Self { all, by_addresstype }) + Ok(Self { + all, + by_addresstype, + }) } pub(crate) fn compute( @@ -64,24 +61,14 @@ impl GrowthRateVecs { ) })?; - for ((_, growth), ((_, new), (_, addr))) in self - .by_addresstype - .iter_mut() - .zip( - new_addr_count - .by_addresstype - .iter() - .zip(addr_count.by_addresstype.iter()), - ) - { + for ((_, growth), ((_, new), (_, addr))) in self.by_addresstype.iter_mut().zip( + new_addr_count + .by_addresstype + .iter() + .zip(addr_count.by_addresstype.iter()), + ) { growth.compute(max_from, windows, exit, |target| { - compute_ratio( - target, - max_from, - &new.height, - &addr.count.height, - exit, - ) + compute_ratio(target, max_from, &new.height, &addr.count.height, exit) })?; } diff --git a/crates/brk_computer/src/distribution/address/new_addr_count.rs b/crates/brk_computer/src/distribution/address/new_addr_count.rs index 86f44b224..0018b7c77 100644 --- a/crates/brk_computer/src/distribution/address/new_addr_count.rs +++ b/crates/brk_computer/src/distribution/address/new_addr_count.rs @@ -1,12 +1,13 @@ -//! New address count: per-block delta of total_addr_count (global + per-type) - use brk_cohort::ByAddressType; use brk_error::Result; use brk_traversable::Traversable; use brk_types::{Height, StoredU64, Version}; use vecdb::{Database, Exit, Rw, StorageMode}; -use crate::{indexes, internal::{ComputedFromHeightFull, WindowStarts}}; +use crate::{ + indexes, + internal::{ComputedFromHeightFull, WindowStarts}, +}; use super::TotalAddrCountVecs; @@ -24,12 +25,7 @@ impl NewAddrCountVecs { version: Version, indexes: &indexes::Vecs, ) -> Result { - let all = ComputedFromHeightFull::forced_import( - db, - "new_addr_count", - version, - indexes, - )?; + let all = ComputedFromHeightFull::forced_import(db, "new_addr_count", version, indexes)?; let by_addresstype: ByAddressType> = ByAddressType::new_with_name(|name| { diff --git a/crates/brk_computer/src/distribution/address/total_addr_count.rs b/crates/brk_computer/src/distribution/address/total_addr_count.rs index f8bd57fa2..cfc4d30fa 100644 --- a/crates/brk_computer/src/distribution/address/total_addr_count.rs +++ b/crates/brk_computer/src/distribution/address/total_addr_count.rs @@ -1,5 +1,3 @@ -//! Total address count: addr_count + empty_addr_count (global + per-type) - use brk_cohort::ByAddressType; use brk_error::Result; use brk_traversable::Traversable; @@ -24,25 +22,22 @@ impl TotalAddrCountVecs { version: Version, indexes: &indexes::Vecs, ) -> Result { - let all = ComputedFromHeight::forced_import( - db, - "total_addr_count", - version, - indexes, - )?; + let all = ComputedFromHeight::forced_import(db, "total_addr_count", version, indexes)?; - let by_addresstype: ByAddressType> = ByAddressType::new_with_name( - |name| { + let by_addresstype: ByAddressType> = + ByAddressType::new_with_name(|name| { ComputedFromHeight::forced_import( db, &format!("{name}_total_addr_count"), version, indexes, ) - }, - )?; + })?; - Ok(Self { all, by_addresstype }) + Ok(Self { + all, + by_addresstype, + }) } /// Eagerly compute total = addr_count + empty_addr_count. @@ -60,22 +55,15 @@ impl TotalAddrCountVecs { exit, )?; - for ((_, total), ((_, addr), (_, empty))) in self - .by_addresstype - .iter_mut() - .zip( - addr_count - .by_addresstype - .iter() - .zip(empty_addr_count.by_addresstype.iter()), - ) - { - total.height.compute_add( - max_from, - &addr.count.height, - &empty.count.height, - exit, - )?; + for ((_, total), ((_, addr), (_, empty))) in self.by_addresstype.iter_mut().zip( + addr_count + .by_addresstype + .iter() + .zip(empty_addr_count.by_addresstype.iter()), + ) { + total + .height + .compute_add(max_from, &addr.count.height, &empty.count.height, exit)?; } Ok(()) diff --git a/crates/brk_computer/src/distribution/address/type_map/index_map.rs b/crates/brk_computer/src/distribution/address/type_map/index_map.rs index baa2a682f..61e3234e6 100644 --- a/crates/brk_computer/src/distribution/address/type_map/index_map.rs +++ b/crates/brk_computer/src/distribution/address/type_map/index_map.rs @@ -60,7 +60,12 @@ impl AddressTypeToTypeIndexMap { } /// Insert a value for a specific address type and typeindex. - pub(crate) fn insert_for_type(&mut self, address_type: OutputType, typeindex: TypeIndex, value: T) { + pub(crate) fn insert_for_type( + &mut self, + address_type: OutputType, + typeindex: TypeIndex, + value: T, + ) { self.get_mut(address_type).unwrap().insert(typeindex, value); } @@ -76,7 +81,9 @@ impl AddressTypeToTypeIndexMap { } /// Iterate mutably over entries by address type. - pub(crate) fn iter_mut(&mut self) -> impl Iterator)> { + pub(crate) fn iter_mut( + &mut self, + ) -> impl Iterator)> { self.0.iter_mut() } } diff --git a/crates/brk_computer/src/distribution/block/cache/address.rs b/crates/brk_computer/src/distribution/block/cache/address.rs index 716b308fd..3a61fa42e 100644 --- a/crates/brk_computer/src/distribution/block/cache/address.rs +++ b/crates/brk_computer/src/distribution/block/cache/address.rs @@ -49,7 +49,10 @@ impl AddressCache { /// Merge address data into funded cache. #[inline] - pub(crate) fn merge_funded(&mut self, data: AddressTypeToTypeIndexMap>) { + pub(crate) fn merge_funded( + &mut self, + data: AddressTypeToTypeIndexMap>, + ) { self.funded.merge_mut(data); } @@ -63,7 +66,10 @@ impl AddressCache { } /// Update transaction counts for addresses. - pub(crate) fn update_tx_counts(&mut self, txindex_vecs: AddressTypeToTypeIndexMap>) { + pub(crate) fn update_tx_counts( + &mut self, + txindex_vecs: AddressTypeToTypeIndexMap>, + ) { update_tx_counts(&mut self.funded, &mut self.empty, txindex_vecs); } @@ -97,7 +103,9 @@ pub(crate) fn load_uncached_address_data( // Check if this is a new address (typeindex >= first for this height) let first = *first_addressindexes.get(address_type).unwrap(); if first <= typeindex { - return Ok(Some(WithAddressDataSource::New(FundedAddressData::default()))); + return Ok(Some(WithAddressDataSource::New( + FundedAddressData::default(), + ))); } // Skip if already in cache diff --git a/crates/brk_computer/src/distribution/block/cache/lookup.rs b/crates/brk_computer/src/distribution/block/cache/lookup.rs index d089e5a49..e988277fb 100644 --- a/crates/brk_computer/src/distribution/block/cache/lookup.rs +++ b/crates/brk_computer/src/distribution/block/cache/lookup.rs @@ -26,7 +26,10 @@ impl<'a> AddressLookup<'a> { &mut self, output_type: OutputType, type_index: TypeIndex, - ) -> (&mut WithAddressDataSource, TrackingStatus) { + ) -> ( + &mut WithAddressDataSource, + TrackingStatus, + ) { use std::collections::hash_map::Entry; let map = self.funded.get_mut(output_type).unwrap(); diff --git a/crates/brk_computer/src/distribution/block/cohort/sent.rs b/crates/brk_computer/src/distribution/block/cohort/sent.rs index 444ce9d50..7f6ae9dba 100644 --- a/crates/brk_computer/src/distribution/block/cohort/sent.rs +++ b/crates/brk_computer/src/distribution/block/cohort/sent.rs @@ -150,14 +150,7 @@ pub(crate) fn process_sent( .state .as_mut() .unwrap() - .send( - addr_data, - value, - current_price, - prev_price, - peak_price, - age, - )?; + .send(addr_data, value, current_price, prev_price, peak_price, age)?; } } } diff --git a/crates/brk_computer/src/distribution/block/utxo/inputs.rs b/crates/brk_computer/src/distribution/block/utxo/inputs.rs index f4f6458a7..0a8fe79ee 100644 --- a/crates/brk_computer/src/distribution/block/utxo/inputs.rs +++ b/crates/brk_computer/src/distribution/block/utxo/inputs.rs @@ -102,7 +102,9 @@ pub(crate) fn process_inputs( ); let mut sent_data = HeightToAddressTypeToVec::with_capacity(estimated_unique_heights); let mut address_data = - AddressTypeToTypeIndexMap::>::with_capacity(estimated_per_type); + AddressTypeToTypeIndexMap::>::with_capacity( + estimated_per_type, + ); let mut txindex_vecs = AddressTypeToTypeIndexMap::>::with_capacity(estimated_per_type); diff --git a/crates/brk_computer/src/distribution/block/utxo/outputs.rs b/crates/brk_computer/src/distribution/block/utxo/outputs.rs index fdd5a1a79..30f6467d4 100644 --- a/crates/brk_computer/src/distribution/block/utxo/outputs.rs +++ b/crates/brk_computer/src/distribution/block/utxo/outputs.rs @@ -52,7 +52,9 @@ pub(crate) fn process_outputs( let mut transacted = Transacted::default(); let mut received_data = AddressTypeToVec::with_capacity(estimated_per_type); let mut address_data = - AddressTypeToTypeIndexMap::>::with_capacity(estimated_per_type); + AddressTypeToTypeIndexMap::>::with_capacity( + estimated_per_type, + ); let mut txindex_vecs = AddressTypeToTypeIndexMap::>::with_capacity(estimated_per_type); diff --git a/crates/brk_computer/src/distribution/cohorts/address/groups.rs b/crates/brk_computer/src/distribution/cohorts/address/groups.rs index 65e328a14..a54acfe1e 100644 --- a/crates/brk_computer/src/distribution/cohorts/address/groups.rs +++ b/crates/brk_computer/src/distribution/cohorts/address/groups.rs @@ -33,13 +33,11 @@ impl AddressCohorts { let v = version + VERSION; // Helper to create a cohort - only amount_range cohorts have state - let create = |filter: Filter, - name: &'static str, - has_state: bool| - -> Result { - let sp = if has_state { Some(states_path) } else { None }; - AddressCohortVecs::forced_import(db, filter, name, v, indexes, sp) - }; + let create = + |filter: Filter, name: &'static str, has_state: bool| -> Result { + let sp = if has_state { Some(states_path) } else { None }; + AddressCohortVecs::forced_import(db, filter, name, v, indexes, sp) + }; let full = |f: Filter, name: &'static str| create(f, name, true); let none = |f: Filter, name: &'static str| create(f, name, false); @@ -156,7 +154,9 @@ impl AddressCohorts { } /// Returns a parallel iterator over all vecs for parallel writing. - pub(crate) fn par_iter_vecs_mut(&mut self) -> impl ParallelIterator { + pub(crate) fn par_iter_vecs_mut( + &mut self, + ) -> impl ParallelIterator { // Collect all vecs from all cohorts self.0 .iter_mut() diff --git a/crates/brk_computer/src/distribution/cohorts/address/vecs.rs b/crates/brk_computer/src/distribution/cohorts/address/vecs.rs index 6a3b7169a..17cd556dd 100644 --- a/crates/brk_computer/src/distribution/cohorts/address/vecs.rs +++ b/crates/brk_computer/src/distribution/cohorts/address/vecs.rs @@ -5,21 +5,15 @@ use brk_error::Result; use brk_traversable::Traversable; use brk_types::{Cents, Dollars, Height, Indexes, Sats, StoredF64, StoredU64, Version}; use rayon::prelude::*; -use vecdb::{AnyStoredVec, AnyVec, Database, Exit, WritableVec, ReadableVec, Rw, StorageMode}; +use vecdb::{AnyStoredVec, AnyVec, Database, Exit, ReadableVec, Rw, StorageMode, WritableVec}; use crate::{ - blocks, - distribution::state::AddressCohortState, - indexes, - internal::ComputedFromHeight, - prices, + blocks, distribution::state::AddressCohortState, indexes, internal::ComputedFromHeight, prices, }; use crate::distribution::metrics::{BasicCohortMetrics, CohortMetricsBase, ImportConfig}; use super::super::traits::{CohortVecs, DynCohortVecs}; - -/// Address cohort with metrics and optional runtime state. #[derive(Traversable)] pub struct AddressCohortVecs { /// Starting height when state was imported @@ -60,8 +54,7 @@ impl AddressCohortVecs { Ok(Self { starting_height: None, - state: states_path - .map(|path| Box::new(AddressCohortState::new(path, &full_name))), + state: states_path.map(|path| Box::new(AddressCohortState::new(path, &full_name))), metrics: BasicCohortMetrics::forced_import(&cfg)?, @@ -86,7 +79,9 @@ impl AddressCohortVecs { } /// Returns a parallel iterator over all vecs for parallel writing. - pub(crate) fn par_iter_vecs_mut(&mut self) -> impl ParallelIterator { + pub(crate) fn par_iter_vecs_mut( + &mut self, + ) -> impl ParallelIterator { rayon::iter::once(&mut self.addr_count.height as &mut dyn AnyStoredVec) .chain(self.metrics.par_iter_mut()) } diff --git a/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs b/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs index a3deaa6e4..88a3fa6fc 100644 --- a/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs +++ b/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs @@ -1,8 +1,8 @@ use std::{cmp::Reverse, collections::BinaryHeap, fs, path::Path}; use brk_cohort::{ - ByAgeRange, ByAmountRange, ByEpoch, ByGreatEqualAmount, ByLowerThanAmount, - ByMaxAge, ByMinAge, BySpendableType, ByYear, CohortContext, Filter, Filtered, TERM_NAMES, Term, + ByAgeRange, ByAmountRange, ByEpoch, ByGreatEqualAmount, ByLowerThanAmount, ByMaxAge, ByMinAge, + BySpendableType, ByYear, CohortContext, Filter, Filtered, TERM_NAMES, Term, }; use brk_error::Result; use brk_traversable::Traversable; @@ -11,7 +11,9 @@ use brk_types::{ Sats, Version, }; use rayon::prelude::*; -use vecdb::{AnyStoredVec, Database, Exit, ReadOnlyClone, ReadableVec, Rw, StorageMode, WritableVec}; +use vecdb::{ + AnyStoredVec, Database, Exit, ReadOnlyClone, ReadableVec, Rw, StorageMode, WritableVec, +}; use crate::{ blocks, @@ -23,8 +25,7 @@ use crate::{ use crate::distribution::metrics::{ AdjustedCohortMetrics, AllCohortMetrics, BasicCohortMetrics, CohortMetricsBase, - ExtendedAdjustedCohortMetrics, ExtendedCohortMetrics, ImportConfig, - SupplyMetrics, + ExtendedAdjustedCohortMetrics, ExtendedCohortMetrics, ImportConfig, SupplyMetrics, }; use super::vecs::UTXOCohortVecs; @@ -146,12 +147,7 @@ impl UTXOCohorts { version: v, indexes, }; - UTXOCohortVecs::new( - None, - ExtendedAdjustedCohortMetrics::forced_import( - &cfg, - )?, - ) + UTXOCohortVecs::new(None, ExtendedAdjustedCohortMetrics::forced_import(&cfg)?) }; // lth: ExtendedCohortMetrics @@ -165,10 +161,7 @@ impl UTXOCohorts { version: v, indexes, }; - UTXOCohortVecs::new( - None, - ExtendedCohortMetrics::forced_import(&cfg)?, - ) + UTXOCohortVecs::new(None, ExtendedCohortMetrics::forced_import(&cfg)?) }; // max_age: AdjustedCohortMetrics (adjusted + peak_regret) @@ -243,9 +236,6 @@ impl UTXOCohorts { }) } - // === Iteration helpers === - - /// Parallel iterator over all separate (stateful) cohorts. pub(crate) fn par_iter_separate_mut( &mut self, ) -> impl ParallelIterator { @@ -296,9 +286,6 @@ impl UTXOCohorts { v.into_iter() } - // === Computation methods === - - /// Compute overlapping cohorts from component age/amount range cohorts. pub(crate) fn compute_overlapping_vecs( &mut self, starting_indexes: &Indexes, @@ -573,8 +560,22 @@ impl UTXOCohorts { HM: ReadableVec + Sync, { // Get up_to_1h value sources for adjusted computation (cloned to avoid borrow conflicts). - let up_to_1h_value_created = self.age_range.up_to_1h.metrics.realized.value_created.height.read_only_clone(); - let up_to_1h_value_destroyed = self.age_range.up_to_1h.metrics.realized.value_destroyed.height.read_only_clone(); + let up_to_1h_value_created = self + .age_range + .up_to_1h + .metrics + .realized + .value_created + .height + .read_only_clone(); + let up_to_1h_value_destroyed = self + .age_range + .up_to_1h + .metrics + .realized + .value_destroyed + .height + .read_only_clone(); // "all" cohort computed first (no all_supply_sats needed). self.all.metrics.compute_rest_part2( @@ -1024,5 +1025,4 @@ impl UTXOCohorts { Ok(()) } - } diff --git a/crates/brk_computer/src/distribution/cohorts/utxo/receive.rs b/crates/brk_computer/src/distribution/cohorts/utxo/receive.rs index 3c6c66828..b5c2ecc89 100644 --- a/crates/brk_computer/src/distribution/cohorts/utxo/receive.rs +++ b/crates/brk_computer/src/distribution/cohorts/utxo/receive.rs @@ -24,19 +24,32 @@ impl UTXOCohorts { let supply_state = received.spendable_supply; // New UTXOs go into up_to_1h, current epoch, and current year - self.age_range.up_to_1h.state.as_mut().unwrap().receive_utxo(&supply_state, price); - self.epoch.mut_vec_from_height(height).state.as_mut().unwrap().receive_utxo(&supply_state, price); - self.year.mut_vec_from_timestamp(timestamp).state.as_mut().unwrap().receive_utxo(&supply_state, price); + self.age_range + .up_to_1h + .state + .as_mut() + .unwrap() + .receive_utxo(&supply_state, price); + self.epoch + .mut_vec_from_height(height) + .state + .as_mut() + .unwrap() + .receive_utxo(&supply_state, price); + self.year + .mut_vec_from_timestamp(timestamp) + .state + .as_mut() + .unwrap() + .receive_utxo(&supply_state, price); // Update output type cohorts - self.type_ - .iter_typed_mut() - .for_each(|(output_type, vecs)| { - vecs.state - .as_mut() - .unwrap() - .receive_utxo(received.by_type.get(output_type), price) - }); + self.type_.iter_typed_mut().for_each(|(output_type, vecs)| { + vecs.state + .as_mut() + .unwrap() + .receive_utxo(received.by_type.get(output_type), price) + }); // Update amount range cohorts received diff --git a/crates/brk_computer/src/distribution/cohorts/utxo/send.rs b/crates/brk_computer/src/distribution/cohorts/utxo/send.rs index 05cb33925..9e125b137 100644 --- a/crates/brk_computer/src/distribution/cohorts/utxo/send.rs +++ b/crates/brk_computer/src/distribution/cohorts/utxo/send.rs @@ -36,9 +36,8 @@ impl UTXOCohorts { let mut min_receive_height: Option = None; for (receive_height, sent) in height_to_sent { - min_receive_height = Some( - min_receive_height.map_or(receive_height, |cur| cur.min(receive_height)), - ); + min_receive_height = + Some(min_receive_height.map_or(receive_height, |cur| cur.min(receive_height))); // Update chain_state to reflect spent supply chain_state[receive_height.to_usize()].supply -= &sent.spendable_supply; @@ -52,19 +51,25 @@ impl UTXOCohorts { let peak_price = price_range_max.max_between(receive_height, send_height); // Update age range cohort (direct index lookup) - self.age_range.get_mut(age).state.as_mut().unwrap().send_utxo( - &sent.spendable_supply, - current_price, - prev_price, - peak_price, - age, - ); + self.age_range + .get_mut(age) + .state + .as_mut() + .unwrap() + .send_utxo( + &sent.spendable_supply, + current_price, + prev_price, + peak_price, + age, + ); // Update epoch cohort (direct lookup by height) self.epoch .mut_vec_from_height(receive_height) .state - .as_mut().unwrap() + .as_mut() + .unwrap() .send_utxo( &sent.spendable_supply, current_price, @@ -77,7 +82,8 @@ impl UTXOCohorts { self.year .mut_vec_from_timestamp(block_state.timestamp) .state - .as_mut().unwrap() + .as_mut() + .unwrap() .send_utxo( &sent.spendable_supply, current_price, @@ -91,26 +97,24 @@ impl UTXOCohorts { .spendable .iter_typed() .for_each(|(output_type, supply_state)| { - self.type_.get_mut(output_type).state.as_mut().unwrap().send_utxo( - supply_state, - current_price, - prev_price, - peak_price, - age, - ) + self.type_ + .get_mut(output_type) + .state + .as_mut() + .unwrap() + .send_utxo(supply_state, current_price, prev_price, peak_price, age) }); // Update amount range cohorts sent.by_size_group .iter_typed() .for_each(|(group, supply_state)| { - self.amount_range.get_mut(group).state.as_mut().unwrap().send_utxo( - supply_state, - current_price, - prev_price, - peak_price, - age, - ); + self.amount_range + .get_mut(group) + .state + .as_mut() + .unwrap() + .send_utxo(supply_state, current_price, prev_price, peak_price, age); }); } diff --git a/crates/brk_computer/src/distribution/cohorts/utxo/tick_tock.rs b/crates/brk_computer/src/distribution/cohorts/utxo/tick_tock.rs index 4ce52d753..a0da35b3a 100644 --- a/crates/brk_computer/src/distribution/cohorts/utxo/tick_tock.rs +++ b/crates/brk_computer/src/distribution/cohorts/utxo/tick_tock.rs @@ -16,7 +16,11 @@ impl UTXOCohorts { /// - k = 20 boundaries to check /// - n = total blocks in chain_state /// - Linear scan for end_idx is faster than binary search since typically 0-2 blocks cross each boundary - pub(crate) fn tick_tock_next_block(&mut self, chain_state: &[BlockState], timestamp: Timestamp) { + pub(crate) fn tick_tock_next_block( + &mut self, + chain_state: &[BlockState], + timestamp: Timestamp, + ) { if chain_state.is_empty() { return; } diff --git a/crates/brk_computer/src/distribution/cohorts/utxo/vecs.rs b/crates/brk_computer/src/distribution/cohorts/utxo/vecs.rs index 5d2510c5b..5d97bfcb8 100644 --- a/crates/brk_computer/src/distribution/cohorts/utxo/vecs.rs +++ b/crates/brk_computer/src/distribution/cohorts/utxo/vecs.rs @@ -10,10 +10,6 @@ use crate::distribution::metrics::CohortMetricsBase; use super::super::traits::DynCohortVecs; -/// UTXO cohort with metrics and optional runtime state. -/// -/// Generic over the metrics type to support different cohort configurations -/// (e.g. AllCohortMetrics, ExtendedCohortMetrics, BasicCohortMetrics, etc.) #[derive(Traversable)] pub struct UTXOCohortVecs { /// Starting height when state was imported @@ -38,7 +34,6 @@ impl UTXOCohortVecs { metrics, } } - } impl Filtered for UTXOCohortVecs { @@ -117,8 +112,11 @@ impl DynCohortVecs for UTXOCohortVecs< height_price: Cents, ) -> Result<()> { if let Some(state) = self.state.as_mut() { - self.metrics - .compute_then_truncate_push_unrealized_states(height, height_price, state)?; + self.metrics.compute_then_truncate_push_unrealized_states( + height, + height_price, + state, + )?; } Ok(()) } diff --git a/crates/brk_computer/src/distribution/compute/block_loop.rs b/crates/brk_computer/src/distribution/compute/block_loop.rs index f146d9c51..550305aab 100644 --- a/crates/brk_computer/src/distribution/compute/block_loop.rs +++ b/crates/brk_computer/src/distribution/compute/block_loop.rs @@ -3,7 +3,9 @@ use std::thread; use brk_cohort::ByAddressType; use brk_error::Result; use brk_indexer::Indexer; -use brk_types::{Cents, Date, Height, OutputType, Sats, Timestamp, TxIndex, TypeIndex, ONE_DAY_IN_SEC}; +use brk_types::{ + Cents, Date, Height, ONE_DAY_IN_SEC, OutputType, Sats, Timestamp, TxIndex, TypeIndex, +}; use rayon::prelude::*; use rustc_hash::FxHashSet; use tracing::{debug, info}; @@ -401,12 +403,11 @@ pub(crate) fn process_blocks( // Main thread: Update UTXO cohorts vecs.utxo_cohorts .receive(transacted, height, timestamp, block_price); - if let Some(min_h) = vecs.utxo_cohorts - .send(height_to_sent, chain_state, ctx.price_range_max) + if let Some(min_h) = + vecs.utxo_cohorts + .send(height_to_sent, chain_state, ctx.price_range_max) { - min_supply_modified = Some( - min_supply_modified.map_or(min_h, |cur| cur.min(min_h)), - ); + min_supply_modified = Some(min_supply_modified.map_or(min_h, |cur| cur.min(min_h))); } }); @@ -423,8 +424,7 @@ pub(crate) fn process_blocks( let h = height.to_usize(); let is_last_of_day = height == last_height - || *cached_timestamps[h] / ONE_DAY_IN_SEC - != *cached_timestamps[h + 1] / ONE_DAY_IN_SEC; + || *cached_timestamps[h] / ONE_DAY_IN_SEC != *cached_timestamps[h + 1] / ONE_DAY_IN_SEC; let date_opt = is_last_of_day.then(|| Date::from(timestamp)); push_cohort_states( diff --git a/crates/brk_computer/src/distribution/compute/readers.rs b/crates/brk_computer/src/distribution/compute/readers.rs index 1a0d27a70..5a83cd977 100644 --- a/crates/brk_computer/src/distribution/compute/readers.rs +++ b/crates/brk_computer/src/distribution/compute/readers.rs @@ -1,9 +1,7 @@ use brk_cohort::{ByAddressType, ByAnyAddress}; use brk_indexer::Indexer; -use brk_types::{ - Height, OutPoint, OutputType, Sats, StoredU64, TxIndex, TypeIndex, -}; -use vecdb::{Reader, ReadableVec, VecIndex}; +use brk_types::{Height, OutPoint, OutputType, Sats, StoredU64, TxIndex, TypeIndex}; +use vecdb::{ReadableVec, Reader, VecIndex}; use crate::{ distribution::{ @@ -46,9 +44,21 @@ impl<'a> TxOutReaders<'a> { output_count: usize, ) -> Vec { let end = first_txoutindex + output_count; - self.indexer.vecs.outputs.value.collect_range_into_at(first_txoutindex, end, &mut self.values_buf); - self.indexer.vecs.outputs.outputtype.collect_range_into_at(first_txoutindex, end, &mut self.outputtypes_buf); - self.indexer.vecs.outputs.typeindex.collect_range_into_at(first_txoutindex, end, &mut self.typeindexes_buf); + self.indexer.vecs.outputs.value.collect_range_into_at( + first_txoutindex, + end, + &mut self.values_buf, + ); + self.indexer.vecs.outputs.outputtype.collect_range_into_at( + first_txoutindex, + end, + &mut self.outputtypes_buf, + ); + self.indexer.vecs.outputs.typeindex.collect_range_into_at( + first_txoutindex, + end, + &mut self.typeindexes_buf, + ); self.values_buf .iter() @@ -94,12 +104,31 @@ impl<'a> TxInReaders<'a> { current_height: Height, ) -> (Vec, Vec, Vec, Vec) { let end = first_txinindex + input_count; - let values: Vec = self.txins.spent.value.collect_range_at(first_txinindex, end); - self.indexer.vecs.inputs.outpoint.collect_range_into_at(first_txinindex, end, &mut self.outpoints_buf); - let outputtypes: Vec = self.indexer.vecs.inputs.outputtype.collect_range_at(first_txinindex, end); - let typeindexes: Vec = self.indexer.vecs.inputs.typeindex.collect_range_at(first_txinindex, end); + let values: Vec = self + .txins + .spent + .value + .collect_range_at(first_txinindex, end); + self.indexer.vecs.inputs.outpoint.collect_range_into_at( + first_txinindex, + end, + &mut self.outpoints_buf, + ); + let outputtypes: Vec = self + .indexer + .vecs + .inputs + .outputtype + .collect_range_at(first_txinindex, end); + let typeindexes: Vec = self + .indexer + .vecs + .inputs + .typeindex + .collect_range_at(first_txinindex, end); - let prev_heights: Vec = self.outpoints_buf + let prev_heights: Vec = self + .outpoints_buf .iter() .map(|outpoint| { if outpoint.is_coinbase() { @@ -175,7 +204,11 @@ impl IndexToTxIndexBuf { txindex_to_count: &impl ReadableVec, ) -> &[TxIndex] { let first = block_first_txindex.to_usize(); - txindex_to_count.collect_range_into_at(first, first + block_tx_count as usize, &mut self.counts); + txindex_to_count.collect_range_into_at( + first, + first + block_tx_count as usize, + &mut self.counts, + ); let total: u64 = self.counts.iter().map(|c| u64::from(*c)).sum(); self.result.clear(); @@ -183,7 +216,8 @@ impl IndexToTxIndexBuf { for (offset, count) in self.counts.iter().enumerate() { let txindex = TxIndex::from(first + offset); - self.result.extend(std::iter::repeat_n(txindex, u64::from(*count) as usize)); + self.result + .extend(std::iter::repeat_n(txindex, u64::from(*count) as usize)); } &self.result diff --git a/crates/brk_computer/src/distribution/compute/recover.rs b/crates/brk_computer/src/distribution/compute/recover.rs index 87eb4a6bb..13104425f 100644 --- a/crates/brk_computer/src/distribution/compute/recover.rs +++ b/crates/brk_computer/src/distribution/compute/recover.rs @@ -71,9 +71,15 @@ pub(crate) fn recover_state( } // Import UTXO cohort states - all must succeed - debug!("importing UTXO cohort states at height {}", consistent_height); + debug!( + "importing UTXO cohort states at height {}", + consistent_height + ); if !utxo_cohorts.import_separate_states(consistent_height) { - warn!("UTXO cohort state import failed at height {}", consistent_height); + warn!( + "UTXO cohort state import failed at height {}", + consistent_height + ); return Ok(RecoveredState { starting_height: Height::ZERO, }); @@ -81,9 +87,15 @@ pub(crate) fn recover_state( debug!("UTXO cohort states imported"); // Import address cohort states - all must succeed - debug!("importing address cohort states at height {}", consistent_height); + debug!( + "importing address cohort states at height {}", + consistent_height + ); if !address_cohorts.import_separate_states(consistent_height) { - warn!("Address cohort state import failed at height {}", consistent_height); + warn!( + "Address cohort state import failed at height {}", + consistent_height + ); return Ok(RecoveredState { starting_height: Height::ZERO, }); @@ -163,16 +175,25 @@ fn rollback_states( return Height::ZERO; }; let chain_height = Height::from(s).incremented(); - debug!("chain_state rolled back to stamp {:?}, height {}", s, chain_height); + debug!( + "chain_state rolled back to stamp {:?}, height {}", + s, chain_height + ); heights.insert(chain_height); let Ok(stamps) = address_indexes_rollbacks else { - warn!("address_indexes rollback failed: {:?}", address_indexes_rollbacks); + warn!( + "address_indexes rollback failed: {:?}", + address_indexes_rollbacks + ); return Height::ZERO; }; for (i, s) in stamps.iter().enumerate() { let h = Height::from(*s).incremented(); - debug!("address_indexes[{}] rolled back to stamp {:?}, height {}", i, s, h); + debug!( + "address_indexes[{}] rolled back to stamp {:?}, height {}", + i, s, h + ); heights.insert(h); } @@ -182,7 +203,10 @@ fn rollback_states( }; for (i, s) in stamps.iter().enumerate() { let h = Height::from(*s).incremented(); - debug!("address_data[{}] rolled back to stamp {:?}, height {}", i, s, h); + debug!( + "address_data[{}] rolled back to stamp {:?}, height {}", + i, s, h + ); heights.insert(h); } diff --git a/crates/brk_computer/src/distribution/compute/write.rs b/crates/brk_computer/src/distribution/compute/write.rs index b5e6ac22a..9ca1ff348 100644 --- a/crates/brk_computer/src/distribution/compute/write.rs +++ b/crates/brk_computer/src/distribution/compute/write.rs @@ -4,7 +4,7 @@ use brk_error::Result; use brk_types::{EmptyAddressData, FundedAddressData, Height}; use rayon::prelude::*; use tracing::info; -use vecdb::{AnyStoredVec, AnyVec, VecIndex, WritableVec, Stamp}; +use vecdb::{AnyStoredVec, AnyVec, Stamp, VecIndex, WritableVec}; use crate::distribution::{ Vecs, @@ -65,8 +65,8 @@ pub(crate) fn write( // Incremental supply_state write: only rewrite from the earliest modified height let supply_state_len = vecs.supply_state.len(); - let truncate_to = min_supply_modified - .map_or(supply_state_len, |h| h.to_usize().min(supply_state_len)); + let truncate_to = + min_supply_modified.map_or(supply_state_len, |h| h.to_usize().min(supply_state_len)); vecs.supply_state .truncate_if_needed(Height::from(truncate_to))?; for block_state in &chain_state[truncate_to..] { diff --git a/crates/brk_computer/src/distribution/metrics/activity.rs b/crates/brk_computer/src/distribution/metrics/activity.rs index 44d2b7570..fb43807e1 100644 --- a/crates/brk_computer/src/distribution/metrics/activity.rs +++ b/crates/brk_computer/src/distribution/metrics/activity.rs @@ -2,7 +2,9 @@ use brk_error::Result; use brk_traversable::Traversable; use brk_types::{Bitcoin, Height, Indexes, Sats, StoredF64, Version}; use rayon::prelude::*; -use vecdb::{AnyStoredVec, AnyVec, EagerVec, Exit, ImportableVec, PcoVec, Rw, StorageMode, WritableVec}; +use vecdb::{ + AnyStoredVec, AnyVec, EagerVec, Exit, ImportableVec, PcoVec, Rw, StorageMode, WritableVec, +}; use crate::{ blocks, @@ -51,7 +53,8 @@ impl ActivityMetrics { cfg.version, )?, - coinblocks_destroyed: cfg.import_cumulative_sum("coinblocks_destroyed", Version::ZERO)?, + coinblocks_destroyed: cfg + .import_cumulative_sum("coinblocks_destroyed", Version::ZERO)?, coindays_destroyed: cfg.import_cumulative_sum("coindays_destroyed", Version::ZERO)?, }) } @@ -151,25 +154,27 @@ impl ActivityMetrics { exit, )?; - self.coinblocks_destroyed.compute(starting_indexes.height, &window_starts, exit, |v| { - v.compute_transform( - starting_indexes.height, - &self.satblocks_destroyed, - |(i, v, ..)| (i, StoredF64::from(Bitcoin::from(v))), - exit, - )?; - Ok(()) - })?; + self.coinblocks_destroyed + .compute(starting_indexes.height, &window_starts, exit, |v| { + v.compute_transform( + starting_indexes.height, + &self.satblocks_destroyed, + |(i, v, ..)| (i, StoredF64::from(Bitcoin::from(v))), + exit, + )?; + Ok(()) + })?; - self.coindays_destroyed.compute(starting_indexes.height, &window_starts, exit, |v| { - v.compute_transform( - starting_indexes.height, - &self.satdays_destroyed, - |(i, v, ..)| (i, StoredF64::from(Bitcoin::from(v))), - exit, - )?; - Ok(()) - })?; + self.coindays_destroyed + .compute(starting_indexes.height, &window_starts, exit, |v| { + v.compute_transform( + starting_indexes.height, + &self.satdays_destroyed, + |(i, v, ..)| (i, StoredF64::from(Bitcoin::from(v))), + exit, + )?; + Ok(()) + })?; Ok(()) } diff --git a/crates/brk_computer/src/distribution/metrics/cohort/adjusted.rs b/crates/brk_computer/src/distribution/metrics/cohort/adjusted.rs index aa411d226..249128b95 100644 --- a/crates/brk_computer/src/distribution/metrics/cohort/adjusted.rs +++ b/crates/brk_computer/src/distribution/metrics/cohort/adjusted.rs @@ -28,19 +28,45 @@ pub struct AdjustedCohortMetrics { } impl CohortMetricsBase for AdjustedCohortMetrics { - fn filter(&self) -> &Filter { &self.filter } - fn supply(&self) -> &SupplyMetrics { &self.supply } - fn supply_mut(&mut self) -> &mut SupplyMetrics { &mut self.supply } - fn outputs(&self) -> &OutputsMetrics { &self.outputs } - fn outputs_mut(&mut self) -> &mut OutputsMetrics { &mut self.outputs } - fn activity(&self) -> &ActivityMetrics { &self.activity } - fn activity_mut(&mut self) -> &mut ActivityMetrics { &mut self.activity } - fn realized_base(&self) -> &RealizedBase { &self.realized } - fn realized_base_mut(&mut self) -> &mut RealizedBase { &mut self.realized } - fn unrealized_base(&self) -> &UnrealizedBase { &self.unrealized } - fn unrealized_base_mut(&mut self) -> &mut UnrealizedBase { &mut self.unrealized } - fn cost_basis_base(&self) -> &CostBasisBase { &self.cost_basis } - fn cost_basis_base_mut(&mut self) -> &mut CostBasisBase { &mut self.cost_basis } + fn filter(&self) -> &Filter { + &self.filter + } + fn supply(&self) -> &SupplyMetrics { + &self.supply + } + fn supply_mut(&mut self) -> &mut SupplyMetrics { + &mut self.supply + } + fn outputs(&self) -> &OutputsMetrics { + &self.outputs + } + fn outputs_mut(&mut self) -> &mut OutputsMetrics { + &mut self.outputs + } + fn activity(&self) -> &ActivityMetrics { + &self.activity + } + fn activity_mut(&mut self) -> &mut ActivityMetrics { + &mut self.activity + } + fn realized_base(&self) -> &RealizedBase { + &self.realized + } + fn realized_base_mut(&mut self) -> &mut RealizedBase { + &mut self.realized + } + fn unrealized_base(&self) -> &UnrealizedBase { + &self.unrealized + } + fn unrealized_base_mut(&mut self) -> &mut UnrealizedBase { + &mut self.unrealized + } + fn cost_basis_base(&self) -> &CostBasisBase { + &self.cost_basis + } + fn cost_basis_base_mut(&mut self) -> &mut CostBasisBase { + &mut self.cost_basis + } fn validate_computed_versions(&mut self, base_version: Version) -> Result<()> { self.supply.validate_computed_versions(base_version)?; @@ -48,7 +74,10 @@ impl CohortMetricsBase for AdjustedCohortMetrics { Ok(()) } fn compute_then_truncate_push_unrealized_states( - &mut self, height: Height, height_price: Cents, state: &mut CohortState, + &mut self, + height: Height, + height_price: Cents, + state: &mut CohortState, ) -> Result<()> { state.apply_pending(); self.cost_basis.truncate_push_minmax(height, state)?; @@ -69,9 +98,7 @@ impl CohortMetricsBase for AdjustedCohortMetrics { } impl AdjustedCohortMetrics { - pub(crate) fn forced_import( - cfg: &ImportConfig, - ) -> Result { + pub(crate) fn forced_import(cfg: &ImportConfig) -> Result { let supply = SupplyMetrics::forced_import(cfg)?; let unrealized = UnrealizedBase::forced_import(cfg)?; let realized = RealizedWithAdjusted::forced_import(cfg)?; @@ -125,5 +152,4 @@ impl AdjustedCohortMetrics { Ok(()) } - } diff --git a/crates/brk_computer/src/distribution/metrics/cohort/all.rs b/crates/brk_computer/src/distribution/metrics/cohort/all.rs index 3d3699099..9f5e1e82a 100644 --- a/crates/brk_computer/src/distribution/metrics/cohort/all.rs +++ b/crates/brk_computer/src/distribution/metrics/cohort/all.rs @@ -84,8 +84,7 @@ impl CohortMetricsBase for AllCohortMetrics { state.apply_pending(); self.cost_basis.truncate_push_minmax(height, state)?; let unrealized_state = state.compute_unrealized_state(height_price); - self.unrealized - .truncate_push(height, &unrealized_state)?; + self.unrealized.truncate_push(height, &unrealized_state)?; self.cost_basis .extended .truncate_push_percentiles(height, state, height_price)?; diff --git a/crates/brk_computer/src/distribution/metrics/cohort/basic.rs b/crates/brk_computer/src/distribution/metrics/cohort/basic.rs index affe7903d..4a2bb1248 100644 --- a/crates/brk_computer/src/distribution/metrics/cohort/basic.rs +++ b/crates/brk_computer/src/distribution/metrics/cohort/basic.rs @@ -8,8 +8,8 @@ use vecdb::{AnyStoredVec, Exit, ReadableVec, Rw, StorageMode}; use crate::{blocks, distribution::state::CohortState, prices}; use crate::distribution::metrics::{ - ActivityMetrics, CohortMetricsBase, CostBasisBase, ImportConfig, OutputsMetrics, - RealizedBase, RelativeWithRelToAll, SupplyMetrics, UnrealizedBase, + ActivityMetrics, CohortMetricsBase, CostBasisBase, ImportConfig, OutputsMetrics, RealizedBase, + RelativeWithRelToAll, SupplyMetrics, UnrealizedBase, }; /// Basic cohort metrics: no extensions, with relative (rel_to_all). @@ -28,26 +28,55 @@ pub struct BasicCohortMetrics { } impl CohortMetricsBase for BasicCohortMetrics { - fn filter(&self) -> &Filter { &self.filter } - fn supply(&self) -> &SupplyMetrics { &self.supply } - fn supply_mut(&mut self) -> &mut SupplyMetrics { &mut self.supply } - fn outputs(&self) -> &OutputsMetrics { &self.outputs } - fn outputs_mut(&mut self) -> &mut OutputsMetrics { &mut self.outputs } - fn activity(&self) -> &ActivityMetrics { &self.activity } - fn activity_mut(&mut self) -> &mut ActivityMetrics { &mut self.activity } - fn realized_base(&self) -> &RealizedBase { &self.realized } - fn realized_base_mut(&mut self) -> &mut RealizedBase { &mut self.realized } - fn unrealized_base(&self) -> &UnrealizedBase { &self.unrealized } - fn unrealized_base_mut(&mut self) -> &mut UnrealizedBase { &mut self.unrealized } - fn cost_basis_base(&self) -> &CostBasisBase { &self.cost_basis } - fn cost_basis_base_mut(&mut self) -> &mut CostBasisBase { &mut self.cost_basis } + fn filter(&self) -> &Filter { + &self.filter + } + fn supply(&self) -> &SupplyMetrics { + &self.supply + } + fn supply_mut(&mut self) -> &mut SupplyMetrics { + &mut self.supply + } + fn outputs(&self) -> &OutputsMetrics { + &self.outputs + } + fn outputs_mut(&mut self) -> &mut OutputsMetrics { + &mut self.outputs + } + fn activity(&self) -> &ActivityMetrics { + &self.activity + } + fn activity_mut(&mut self) -> &mut ActivityMetrics { + &mut self.activity + } + fn realized_base(&self) -> &RealizedBase { + &self.realized + } + fn realized_base_mut(&mut self) -> &mut RealizedBase { + &mut self.realized + } + fn unrealized_base(&self) -> &UnrealizedBase { + &self.unrealized + } + fn unrealized_base_mut(&mut self) -> &mut UnrealizedBase { + &mut self.unrealized + } + fn cost_basis_base(&self) -> &CostBasisBase { + &self.cost_basis + } + fn cost_basis_base_mut(&mut self) -> &mut CostBasisBase { + &mut self.cost_basis + } fn validate_computed_versions(&mut self, base_version: Version) -> Result<()> { self.supply.validate_computed_versions(base_version)?; self.activity.validate_computed_versions(base_version)?; Ok(()) } fn compute_then_truncate_push_unrealized_states( - &mut self, height: Height, height_price: Cents, state: &mut CohortState, + &mut self, + height: Height, + height_price: Cents, + state: &mut CohortState, ) -> Result<()> { state.apply_pending(); self.cost_basis.truncate_push_minmax(height, state)?; @@ -68,9 +97,7 @@ impl CohortMetricsBase for BasicCohortMetrics { } impl BasicCohortMetrics { - pub(crate) fn forced_import( - cfg: &ImportConfig, - ) -> Result { + pub(crate) fn forced_import(cfg: &ImportConfig) -> Result { let supply = SupplyMetrics::forced_import(cfg)?; let unrealized = UnrealizedBase::forced_import(cfg)?; let realized = RealizedBase::forced_import(cfg)?; diff --git a/crates/brk_computer/src/distribution/metrics/cohort/extended.rs b/crates/brk_computer/src/distribution/metrics/cohort/extended.rs index 7cc2c868c..c7c0b7c5f 100644 --- a/crates/brk_computer/src/distribution/metrics/cohort/extended.rs +++ b/crates/brk_computer/src/distribution/metrics/cohort/extended.rs @@ -29,19 +29,45 @@ pub struct ExtendedCohortMetrics { } impl CohortMetricsBase for ExtendedCohortMetrics { - fn filter(&self) -> &Filter { &self.filter } - fn supply(&self) -> &SupplyMetrics { &self.supply } - fn supply_mut(&mut self) -> &mut SupplyMetrics { &mut self.supply } - fn outputs(&self) -> &OutputsMetrics { &self.outputs } - fn outputs_mut(&mut self) -> &mut OutputsMetrics { &mut self.outputs } - fn activity(&self) -> &ActivityMetrics { &self.activity } - fn activity_mut(&mut self) -> &mut ActivityMetrics { &mut self.activity } - fn realized_base(&self) -> &RealizedBase { &self.realized } - fn realized_base_mut(&mut self) -> &mut RealizedBase { &mut self.realized } - fn unrealized_base(&self) -> &UnrealizedBase { &self.unrealized } - fn unrealized_base_mut(&mut self) -> &mut UnrealizedBase { &mut self.unrealized } - fn cost_basis_base(&self) -> &CostBasisBase { &self.cost_basis } - fn cost_basis_base_mut(&mut self) -> &mut CostBasisBase { &mut self.cost_basis } + fn filter(&self) -> &Filter { + &self.filter + } + fn supply(&self) -> &SupplyMetrics { + &self.supply + } + fn supply_mut(&mut self) -> &mut SupplyMetrics { + &mut self.supply + } + fn outputs(&self) -> &OutputsMetrics { + &self.outputs + } + fn outputs_mut(&mut self) -> &mut OutputsMetrics { + &mut self.outputs + } + fn activity(&self) -> &ActivityMetrics { + &self.activity + } + fn activity_mut(&mut self) -> &mut ActivityMetrics { + &mut self.activity + } + fn realized_base(&self) -> &RealizedBase { + &self.realized + } + fn realized_base_mut(&mut self) -> &mut RealizedBase { + &mut self.realized + } + fn unrealized_base(&self) -> &UnrealizedBase { + &self.unrealized + } + fn unrealized_base_mut(&mut self) -> &mut UnrealizedBase { + &mut self.unrealized + } + fn cost_basis_base(&self) -> &CostBasisBase { + &self.cost_basis + } + fn cost_basis_base_mut(&mut self) -> &mut CostBasisBase { + &mut self.cost_basis + } fn validate_computed_versions(&mut self, base_version: Version) -> Result<()> { self.supply.validate_computed_versions(base_version)?; @@ -50,13 +76,18 @@ impl CohortMetricsBase for ExtendedCohortMetrics { Ok(()) } fn compute_then_truncate_push_unrealized_states( - &mut self, height: Height, height_price: Cents, state: &mut CohortState, + &mut self, + height: Height, + height_price: Cents, + state: &mut CohortState, ) -> Result<()> { state.apply_pending(); self.cost_basis.truncate_push_minmax(height, state)?; let unrealized_state = state.compute_unrealized_state(height_price); self.unrealized.truncate_push(height, &unrealized_state)?; - self.cost_basis.extended.truncate_push_percentiles(height, state, height_price)?; + self.cost_basis + .extended + .truncate_push_percentiles(height, state, height_price)?; Ok(()) } fn collect_all_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> { @@ -73,9 +104,7 @@ impl CohortMetricsBase for ExtendedCohortMetrics { } impl ExtendedCohortMetrics { - pub(crate) fn forced_import( - cfg: &ImportConfig, - ) -> Result { + pub(crate) fn forced_import(cfg: &ImportConfig) -> Result { let supply = SupplyMetrics::forced_import(cfg)?; let unrealized = UnrealizedBase::forced_import(cfg)?; let realized = RealizedWithExtended::forced_import(cfg)?; @@ -125,5 +154,4 @@ impl ExtendedCohortMetrics { Ok(()) } - } diff --git a/crates/brk_computer/src/distribution/metrics/cohort/extended_adjusted.rs b/crates/brk_computer/src/distribution/metrics/cohort/extended_adjusted.rs index 3c90b5129..ca959db72 100644 --- a/crates/brk_computer/src/distribution/metrics/cohort/extended_adjusted.rs +++ b/crates/brk_computer/src/distribution/metrics/cohort/extended_adjusted.rs @@ -29,19 +29,45 @@ pub struct ExtendedAdjustedCohortMetrics { } impl CohortMetricsBase for ExtendedAdjustedCohortMetrics { - fn filter(&self) -> &Filter { &self.filter } - fn supply(&self) -> &SupplyMetrics { &self.supply } - fn supply_mut(&mut self) -> &mut SupplyMetrics { &mut self.supply } - fn outputs(&self) -> &OutputsMetrics { &self.outputs } - fn outputs_mut(&mut self) -> &mut OutputsMetrics { &mut self.outputs } - fn activity(&self) -> &ActivityMetrics { &self.activity } - fn activity_mut(&mut self) -> &mut ActivityMetrics { &mut self.activity } - fn realized_base(&self) -> &RealizedBase { &self.realized } - fn realized_base_mut(&mut self) -> &mut RealizedBase { &mut self.realized } - fn unrealized_base(&self) -> &UnrealizedBase { &self.unrealized } - fn unrealized_base_mut(&mut self) -> &mut UnrealizedBase { &mut self.unrealized } - fn cost_basis_base(&self) -> &CostBasisBase { &self.cost_basis } - fn cost_basis_base_mut(&mut self) -> &mut CostBasisBase { &mut self.cost_basis } + fn filter(&self) -> &Filter { + &self.filter + } + fn supply(&self) -> &SupplyMetrics { + &self.supply + } + fn supply_mut(&mut self) -> &mut SupplyMetrics { + &mut self.supply + } + fn outputs(&self) -> &OutputsMetrics { + &self.outputs + } + fn outputs_mut(&mut self) -> &mut OutputsMetrics { + &mut self.outputs + } + fn activity(&self) -> &ActivityMetrics { + &self.activity + } + fn activity_mut(&mut self) -> &mut ActivityMetrics { + &mut self.activity + } + fn realized_base(&self) -> &RealizedBase { + &self.realized + } + fn realized_base_mut(&mut self) -> &mut RealizedBase { + &mut self.realized + } + fn unrealized_base(&self) -> &UnrealizedBase { + &self.unrealized + } + fn unrealized_base_mut(&mut self) -> &mut UnrealizedBase { + &mut self.unrealized + } + fn cost_basis_base(&self) -> &CostBasisBase { + &self.cost_basis + } + fn cost_basis_base_mut(&mut self) -> &mut CostBasisBase { + &mut self.cost_basis + } fn validate_computed_versions(&mut self, base_version: Version) -> Result<()> { self.supply.validate_computed_versions(base_version)?; self.activity.validate_computed_versions(base_version)?; @@ -49,13 +75,18 @@ impl CohortMetricsBase for ExtendedAdjustedCohortMetrics { Ok(()) } fn compute_then_truncate_push_unrealized_states( - &mut self, height: Height, height_price: Cents, state: &mut CohortState, + &mut self, + height: Height, + height_price: Cents, + state: &mut CohortState, ) -> Result<()> { state.apply_pending(); self.cost_basis.truncate_push_minmax(height, state)?; let unrealized_state = state.compute_unrealized_state(height_price); self.unrealized.truncate_push(height, &unrealized_state)?; - self.cost_basis.extended.truncate_push_percentiles(height, state, height_price)?; + self.cost_basis + .extended + .truncate_push_percentiles(height, state, height_price)?; Ok(()) } fn collect_all_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> { @@ -72,9 +103,7 @@ impl CohortMetricsBase for ExtendedAdjustedCohortMetrics { } impl ExtendedAdjustedCohortMetrics { - pub(crate) fn forced_import( - cfg: &ImportConfig, - ) -> Result { + pub(crate) fn forced_import(cfg: &ImportConfig) -> Result { let supply = SupplyMetrics::forced_import(cfg)?; let unrealized = UnrealizedBase::forced_import(cfg)?; let realized = RealizedWithExtendedAdjusted::forced_import(cfg)?; @@ -129,5 +158,4 @@ impl ExtendedAdjustedCohortMetrics { Ok(()) } - } diff --git a/crates/brk_computer/src/distribution/metrics/config.rs b/crates/brk_computer/src/distribution/metrics/config.rs index ad54caca4..acd80cba3 100644 --- a/crates/brk_computer/src/distribution/metrics/config.rs +++ b/crates/brk_computer/src/distribution/metrics/config.rs @@ -7,14 +7,14 @@ use vecdb::{BytesVec, BytesVecValue, Database, ImportableVec}; use crate::{ indexes, internal::{ - CentsType, ComputedFromHeight, ComputedFromHeightCumulative, ComputedFromHeightCumulativeSum, - ComputedFromHeightRatio, FiatFromHeight, NumericValue, PercentFromHeight, - PercentRollingEmas1w1m, PercentRollingWindows, Price, RollingEmas1w1m, RollingEmas2w, - RollingWindows, ValueFromHeight, ValueFromHeightChange, ValueFromHeightCumulative, + CentsType, ComputedFromHeight, ComputedFromHeightCumulative, + ComputedFromHeightCumulativeSum, ComputedFromHeightRatio, FiatFromHeight, NumericValue, + PercentFromHeight, PercentRollingEmas1w1m, PercentRollingWindows, Price, RollingEmas1w1m, + RollingEmas2w, RollingWindows, ValueFromHeight, ValueFromHeightChange, + ValueFromHeightCumulative, }, }; -/// Configuration for importing metrics. #[derive(Clone, Copy)] pub struct ImportConfig<'a> { pub db: &'a Database, @@ -25,7 +25,6 @@ pub struct ImportConfig<'a> { } impl<'a> ImportConfig<'a> { - /// Get full metric name with filter prefix. pub(crate) fn name(&self, suffix: &str) -> String { if self.full_name.is_empty() { suffix.to_string() @@ -36,14 +35,17 @@ impl<'a> ImportConfig<'a> { } } - // --- Computed types --- - pub(crate) fn import_computed( &self, suffix: &str, offset: Version, ) -> Result> { - ComputedFromHeight::forced_import(self.db, &self.name(suffix), self.version + offset, self.indexes) + ComputedFromHeight::forced_import( + self.db, + &self.name(suffix), + self.version + offset, + self.indexes, + ) } pub(crate) fn import_cumulative( @@ -51,7 +53,12 @@ impl<'a> ImportConfig<'a> { suffix: &str, offset: Version, ) -> Result> { - ComputedFromHeightCumulative::forced_import(self.db, &self.name(suffix), self.version + offset, self.indexes) + ComputedFromHeightCumulative::forced_import( + self.db, + &self.name(suffix), + self.version + offset, + self.indexes, + ) } pub(crate) fn import_cumulative_sum( @@ -59,17 +66,25 @@ impl<'a> ImportConfig<'a> { suffix: &str, offset: Version, ) -> Result> { - ComputedFromHeightCumulativeSum::forced_import(self.db, &self.name(suffix), self.version + offset, self.indexes) + ComputedFromHeightCumulativeSum::forced_import( + self.db, + &self.name(suffix), + self.version + offset, + self.indexes, + ) } - // --- Percent types --- - pub(crate) fn import_percent_bp16( &self, suffix: &str, offset: Version, ) -> Result> { - PercentFromHeight::forced_import(self.db, &self.name(suffix), self.version + offset, self.indexes) + PercentFromHeight::forced_import( + self.db, + &self.name(suffix), + self.version + offset, + self.indexes, + ) } pub(crate) fn import_percent_bps16( @@ -77,62 +92,158 @@ impl<'a> ImportConfig<'a> { suffix: &str, offset: Version, ) -> Result> { - PercentFromHeight::forced_import(self.db, &self.name(suffix), self.version + offset, self.indexes) + PercentFromHeight::forced_import( + self.db, + &self.name(suffix), + self.version + offset, + self.indexes, + ) } - // --- Value types --- - - pub(crate) fn import_fiat(&self, suffix: &str, offset: Version) -> Result> { - FiatFromHeight::forced_import(self.db, &self.name(suffix), self.version + offset, self.indexes) + pub(crate) fn import_fiat( + &self, + suffix: &str, + offset: Version, + ) -> Result> { + FiatFromHeight::forced_import( + self.db, + &self.name(suffix), + self.version + offset, + self.indexes, + ) } pub(crate) fn import_value(&self, suffix: &str, offset: Version) -> Result { - ValueFromHeight::forced_import(self.db, &self.name(suffix), self.version + offset, self.indexes) + ValueFromHeight::forced_import( + self.db, + &self.name(suffix), + self.version + offset, + self.indexes, + ) } - pub(crate) fn import_value_cumulative(&self, suffix: &str, offset: Version) -> Result { - ValueFromHeightCumulative::forced_import(self.db, &self.name(suffix), self.version + offset, self.indexes) + pub(crate) fn import_value_cumulative( + &self, + suffix: &str, + offset: Version, + ) -> Result { + ValueFromHeightCumulative::forced_import( + self.db, + &self.name(suffix), + self.version + offset, + self.indexes, + ) } - pub(crate) fn import_value_change(&self, suffix: &str, offset: Version) -> Result { - ValueFromHeightChange::forced_import(self.db, &self.name(suffix), self.version + offset, self.indexes) + pub(crate) fn import_value_change( + &self, + suffix: &str, + offset: Version, + ) -> Result { + ValueFromHeightChange::forced_import( + self.db, + &self.name(suffix), + self.version + offset, + self.indexes, + ) } - // --- Price and ratio --- - - pub(crate) fn import_price(&self, suffix: &str, offset: Version) -> Result>> { - Price::forced_import(self.db, &self.name(suffix), self.version + offset, self.indexes) + pub(crate) fn import_price( + &self, + suffix: &str, + offset: Version, + ) -> Result>> { + Price::forced_import( + self.db, + &self.name(suffix), + self.version + offset, + self.indexes, + ) } - pub(crate) fn import_ratio(&self, suffix: &str, offset: Version) -> Result { - ComputedFromHeightRatio::forced_import(self.db, &self.name(suffix), self.version + offset, self.indexes) + pub(crate) fn import_ratio( + &self, + suffix: &str, + offset: Version, + ) -> Result { + ComputedFromHeightRatio::forced_import( + self.db, + &self.name(suffix), + self.version + offset, + self.indexes, + ) } - // --- Bytes --- - - pub(crate) fn import_bytes(&self, suffix: &str, offset: Version) -> Result> { - Ok(BytesVec::forced_import(self.db, &self.name(suffix), self.version + offset)?) + pub(crate) fn import_bytes( + &self, + suffix: &str, + offset: Version, + ) -> Result> { + Ok(BytesVec::forced_import( + self.db, + &self.name(suffix), + self.version + offset, + )?) } - // --- Rolling --- - - pub(crate) fn import_rolling(&self, suffix: &str, offset: Version) -> Result> { - RollingWindows::forced_import(self.db, &self.name(suffix), self.version + offset, self.indexes) + pub(crate) fn import_rolling( + &self, + suffix: &str, + offset: Version, + ) -> Result> { + RollingWindows::forced_import( + self.db, + &self.name(suffix), + self.version + offset, + self.indexes, + ) } - pub(crate) fn import_percent_rolling_bp16(&self, suffix: &str, offset: Version) -> Result> { - PercentRollingWindows::forced_import(self.db, &self.name(suffix), self.version + offset, self.indexes) + pub(crate) fn import_percent_rolling_bp16( + &self, + suffix: &str, + offset: Version, + ) -> Result> { + PercentRollingWindows::forced_import( + self.db, + &self.name(suffix), + self.version + offset, + self.indexes, + ) } - pub(crate) fn import_emas_1w_1m(&self, suffix: &str, offset: Version) -> Result> { - RollingEmas1w1m::forced_import(self.db, &self.name(suffix), self.version + offset, self.indexes) + pub(crate) fn import_emas_1w_1m( + &self, + suffix: &str, + offset: Version, + ) -> Result> { + RollingEmas1w1m::forced_import( + self.db, + &self.name(suffix), + self.version + offset, + self.indexes, + ) } - pub(crate) fn import_percent_emas_1w_1m_bp16(&self, suffix: &str, offset: Version) -> Result> { - PercentRollingEmas1w1m::forced_import(self.db, &self.name(suffix), self.version + offset, self.indexes) + pub(crate) fn import_percent_emas_1w_1m_bp16( + &self, + suffix: &str, + offset: Version, + ) -> Result> { + PercentRollingEmas1w1m::forced_import( + self.db, + &self.name(suffix), + self.version + offset, + self.indexes, + ) } pub(crate) fn import_emas_2w(&self, suffix: &str, offset: Version) -> Result { - RollingEmas2w::forced_import(self.db, &self.name(suffix), self.version + offset, self.indexes) + RollingEmas2w::forced_import( + self.db, + &self.name(suffix), + self.version + offset, + self.indexes, + ) } } diff --git a/crates/brk_computer/src/distribution/metrics/cost_basis/base.rs b/crates/brk_computer/src/distribution/metrics/cost_basis/base.rs index f3d81d7a5..ee290f3df 100644 --- a/crates/brk_computer/src/distribution/metrics/cost_basis/base.rs +++ b/crates/brk_computer/src/distribution/metrics/cost_basis/base.rs @@ -69,12 +69,18 @@ impl CostBasisBase { ) -> Result<()> { self.min.cents.height.compute_min_of_others( starting_indexes.height, - &others.iter().map(|v| &v.min.cents.height).collect::>(), + &others + .iter() + .map(|v| &v.min.cents.height) + .collect::>(), exit, )?; self.max.cents.height.compute_max_of_others( starting_indexes.height, - &others.iter().map(|v| &v.max.cents.height).collect::>(), + &others + .iter() + .map(|v| &v.max.cents.height) + .collect::>(), exit, )?; Ok(()) diff --git a/crates/brk_computer/src/distribution/metrics/cost_basis/extended.rs b/crates/brk_computer/src/distribution/metrics/cost_basis/extended.rs index 268e3e91e..9a980a0af 100644 --- a/crates/brk_computer/src/distribution/metrics/cost_basis/extended.rs +++ b/crates/brk_computer/src/distribution/metrics/cost_basis/extended.rs @@ -5,10 +5,7 @@ use vecdb::{AnyStoredVec, Rw, StorageMode, WritableVec}; use crate::{ distribution::state::CohortState, - internal::{ - PERCENTILES_LEN, PercentFromHeight, PercentilesVecs, - compute_spot_percentile_rank, - }, + internal::{PERCENTILES_LEN, PercentFromHeight, PercentilesVecs, compute_spot_percentile_rank}, }; use crate::distribution::metrics::ImportConfig; @@ -44,8 +41,10 @@ impl CostBasisExtended { cfg.version, cfg.indexes, )?, - spot_cost_basis_percentile: cfg.import_percent_bp16("spot_cost_basis_percentile", Version::ZERO)?, - spot_invested_capital_percentile: cfg.import_percent_bp16("spot_invested_capital_percentile", Version::ZERO)?, + spot_cost_basis_percentile: cfg + .import_percent_bp16("spot_cost_basis_percentile", Version::ZERO)?, + spot_invested_capital_percentile: cfg + .import_percent_bp16("spot_invested_capital_percentile", Version::ZERO)?, }) } diff --git a/crates/brk_computer/src/distribution/metrics/mod.rs b/crates/brk_computer/src/distribution/metrics/mod.rs index 1bf51f20f..1ee6812c4 100644 --- a/crates/brk_computer/src/distribution/metrics/mod.rs +++ b/crates/brk_computer/src/distribution/metrics/mod.rs @@ -25,11 +25,6 @@ use vecdb::{AnyStoredVec, Exit}; use crate::{blocks, distribution::state::CohortState, prices}; -/// Trait defining the interface for cohort metrics containers. -/// -/// Provides typed accessor methods for base sub-metric components, default -/// implementations for shared operations that only use base fields, and -/// required methods for operations that vary by extension level. pub trait CohortMetricsBase: Send + Sync { fn filter(&self) -> &Filter; fn supply(&self) -> &SupplyMetrics; @@ -45,14 +40,8 @@ pub trait CohortMetricsBase: Send + Sync { fn cost_basis_base(&self) -> &CostBasisBase; fn cost_basis_base_mut(&mut self) -> &mut CostBasisBase; - // === Required methods (vary by extension level) === - - /// Validate computed versions against base version. - /// Extended types also validate cost_basis extended versions. fn validate_computed_versions(&mut self, base_version: Version) -> Result<()>; - /// Compute and push unrealized states. - /// Extended types also push cost_basis percentiles. fn compute_then_truncate_push_unrealized_states( &mut self, height: Height, @@ -60,12 +49,8 @@ pub trait CohortMetricsBase: Send + Sync { state: &mut CohortState, ) -> Result<()>; - /// Collect all stored vecs for parallel writing. fn collect_all_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec>; - // === Default methods (shared across all cohort metric types, use base fields only) === - - /// Get minimum length across height-indexed vectors written in block loop. fn min_stateful_height_len(&self) -> usize { self.supply() .min_len() @@ -76,7 +61,6 @@ pub trait CohortMetricsBase: Send + Sync { .min(self.cost_basis_base().min_stateful_height_len()) } - /// Push state values to height-indexed vectors. fn truncate_push(&mut self, height: Height, state: &CohortState) -> Result<()> { self.supply_mut() .truncate_push(height, state.supply.value)?; @@ -225,12 +209,18 @@ pub trait CohortMetricsBase: Send + Sync { )?; self.unrealized_base_mut().compute_from_stateful( starting_indexes, - &others.iter().map(|v| v.unrealized_base()).collect::>(), + &others + .iter() + .map(|v| v.unrealized_base()) + .collect::>(), exit, )?; self.cost_basis_base_mut().compute_from_stateful( starting_indexes, - &others.iter().map(|v| v.cost_basis_base()).collect::>(), + &others + .iter() + .map(|v| v.cost_basis_base()) + .collect::>(), exit, )?; Ok(()) diff --git a/crates/brk_computer/src/distribution/metrics/realized/adjusted.rs b/crates/brk_computer/src/distribution/metrics/realized/adjusted.rs index 1b02e5f55..82ee76834 100644 --- a/crates/brk_computer/src/distribution/metrics/realized/adjusted.rs +++ b/crates/brk_computer/src/distribution/metrics/realized/adjusted.rs @@ -10,18 +10,14 @@ use crate::{ use crate::distribution::metrics::ImportConfig; -/// Adjusted realized metrics (only for adjusted cohorts: all, sth, max_age). #[derive(Traversable)] pub struct RealizedAdjusted { - // === Adjusted Value (computed: cohort - up_to_1h) === pub adjusted_value_created: ComputedFromHeight, pub adjusted_value_destroyed: ComputedFromHeight, - // === Adjusted Value Created/Destroyed Rolling Sums === pub adjusted_value_created_sum: RollingWindows, pub adjusted_value_destroyed_sum: RollingWindows, - // === Adjusted SOPR (rolling window ratios) === pub adjusted_sopr: RollingWindows, pub adjusted_sopr_ema: RollingEmas1w1m, } @@ -30,9 +26,12 @@ impl RealizedAdjusted { pub(crate) fn forced_import(cfg: &ImportConfig) -> Result { Ok(RealizedAdjusted { adjusted_value_created: cfg.import_computed("adjusted_value_created", Version::ZERO)?, - adjusted_value_destroyed: cfg.import_computed("adjusted_value_destroyed", Version::ZERO)?, - adjusted_value_created_sum: cfg.import_rolling("adjusted_value_created", Version::ONE)?, - adjusted_value_destroyed_sum: cfg.import_rolling("adjusted_value_destroyed", Version::ONE)?, + adjusted_value_destroyed: cfg + .import_computed("adjusted_value_destroyed", Version::ZERO)?, + adjusted_value_created_sum: cfg + .import_rolling("adjusted_value_created", Version::ONE)?, + adjusted_value_destroyed_sum: cfg + .import_rolling("adjusted_value_destroyed", Version::ONE)?, adjusted_sopr: cfg.import_rolling("adjusted_sopr", Version::ONE)?, adjusted_sopr_ema: cfg.import_emas_1w_1m("adjusted_sopr_24h", Version::ONE)?, }) @@ -66,19 +65,31 @@ impl RealizedAdjusted { // Adjusted value created/destroyed rolling sums let window_starts = blocks.count.window_starts(); self.adjusted_value_created_sum.compute_rolling_sum( - starting_indexes.height, &window_starts, &self.adjusted_value_created.height, exit, + starting_indexes.height, + &window_starts, + &self.adjusted_value_created.height, + exit, )?; self.adjusted_value_destroyed_sum.compute_rolling_sum( - starting_indexes.height, &window_starts, &self.adjusted_value_destroyed.height, exit, + starting_indexes.height, + &window_starts, + &self.adjusted_value_destroyed.height, + exit, )?; // SOPR ratios from rolling sums - for ((sopr, vc), vd) in self.adjusted_sopr.as_mut_array().into_iter() + for ((sopr, vc), vd) in self + .adjusted_sopr + .as_mut_array() + .into_iter() .zip(self.adjusted_value_created_sum.as_array()) .zip(self.adjusted_value_destroyed_sum.as_array()) { sopr.compute_binary::( - starting_indexes.height, &vc.height, &vd.height, exit, + starting_indexes.height, + &vc.height, + &vd.height, + exit, )?; } diff --git a/crates/brk_computer/src/distribution/metrics/realized/base.rs b/crates/brk_computer/src/distribution/metrics/realized/base.rs index 584596e52..03e283277 100644 --- a/crates/brk_computer/src/distribution/metrics/realized/base.rs +++ b/crates/brk_computer/src/distribution/metrics/realized/base.rs @@ -1,56 +1,49 @@ use brk_error::Result; use brk_traversable::Traversable; use brk_types::{ - BasisPoints16, BasisPoints32, BasisPointsSigned16, - Bitcoin, Cents, CentsSats, CentsSigned, CentsSquaredSats, Dollars, Height, Indexes, Sats, StoredF32, StoredF64, Version, + BasisPoints16, BasisPoints32, BasisPointsSigned16, Bitcoin, Cents, CentsSats, CentsSigned, + CentsSquaredSats, Dollars, Height, Indexes, Sats, StoredF32, StoredF64, Version, }; use vecdb::{ - AnyStoredVec, AnyVec, BytesVec, Exit, ReadableCloneableVec, - ReadableVec, Rw, StorageMode, WritableVec, + AnyStoredVec, AnyVec, BytesVec, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode, + WritableVec, }; use crate::{ blocks, distribution::state::RealizedState, internal::{ - CentsPlus, CentsUnsignedToDollars, ComputedFromHeightCumulative, ComputedFromHeight, - ComputedFromHeightRatio, FiatFromHeight, NegCentsUnsignedToDollars, PercentFromHeight, - PercentRollingEmas1w1m, PercentRollingWindows, ValueFromHeightCumulative, LazyFromHeight, - Price, - RatioCentsBp16, RatioCentsSignedCentsBps16, RatioCentsSignedDollarsBps16, RatioCents64, - RollingEmas1w1m, RollingEmas2w, RollingWindows, Identity, + CentsPlus, CentsUnsignedToDollars, ComputedFromHeight, ComputedFromHeightCumulative, + ComputedFromHeightRatio, FiatFromHeight, Identity, LazyFromHeight, + NegCentsUnsignedToDollars, PercentFromHeight, PercentRollingEmas1w1m, + PercentRollingWindows, Price, RatioCents64, RatioCentsBp16, RatioCentsSignedCentsBps16, + RatioCentsSignedDollarsBps16, RollingEmas1w1m, RollingEmas2w, RollingWindows, + ValueFromHeightCumulative, }, prices, }; use crate::distribution::metrics::ImportConfig; -/// Base realized metrics (always computed). #[derive(Traversable)] pub struct RealizedBase { - // === Realized Cap === pub realized_cap_cents: ComputedFromHeight, pub realized_cap: LazyFromHeight, pub realized_price: Price>, pub realized_price_ratio: ComputedFromHeightRatio, pub realized_cap_change_1m: ComputedFromHeight, - // === Investor Price === pub investor_price: Price>, pub investor_price_ratio: ComputedFromHeightRatio, - // === Floor/Ceiling Price Bands === pub lower_price_band: Price>, pub upper_price_band: Price>, - // === Raw values for aggregation === pub cap_raw: M::Stored>, pub investor_cap_raw: M::Stored>, - // === MVRV === pub mvrv: LazyFromHeight, - // === Realized Profit/Loss === pub realized_profit: ComputedFromHeightCumulative, pub realized_profit_ema_1w: ComputedFromHeight, pub realized_loss: ComputedFromHeightCumulative, @@ -60,50 +53,38 @@ pub struct RealizedBase { pub net_realized_pnl_ema_1w: ComputedFromHeight, pub gross_pnl: FiatFromHeight, - // === Realized vs Realized Cap Ratios === pub realized_profit_rel_to_realized_cap: PercentFromHeight, pub realized_loss_rel_to_realized_cap: PercentFromHeight, pub net_realized_pnl_rel_to_realized_cap: PercentFromHeight, - // === Value Created/Destroyed Splits (stored) === pub profit_value_created: ComputedFromHeight, pub profit_value_destroyed: ComputedFromHeight, pub loss_value_created: ComputedFromHeight, pub loss_value_destroyed: ComputedFromHeight, - // === Value Created/Destroyed Totals === pub value_created: ComputedFromHeight, pub value_destroyed: ComputedFromHeight, - // === Capitulation/Profit Flow (lazy aliases) === pub capitulation_flow: LazyFromHeight, pub profit_flow: LazyFromHeight, - // === Value Created/Destroyed Rolling Sums === pub value_created_sum: RollingWindows, pub value_destroyed_sum: RollingWindows, - // === SOPR (rolling window ratios) === pub sopr: RollingWindows, pub sopr_24h_ema: RollingEmas1w1m, - // === Sell Side Risk === pub gross_pnl_sum: RollingWindows, pub sell_side_risk_ratio: PercentRollingWindows, pub sell_side_risk_ratio_24h_ema: PercentRollingEmas1w1m, - // === Net Realized PnL Deltas === pub net_pnl_change_1m: ComputedFromHeight, - pub net_pnl_change_1m_rel_to_realized_cap: - PercentFromHeight, - pub net_pnl_change_1m_rel_to_market_cap: - PercentFromHeight, + pub net_pnl_change_1m_rel_to_realized_cap: PercentFromHeight, + pub net_pnl_change_1m_rel_to_market_cap: PercentFromHeight, - // === Peak Regret === pub peak_regret: ComputedFromHeightCumulative, pub peak_regret_rel_to_realized_cap: PercentFromHeight, - // === Sent in Profit/Loss === pub sent_in_profit: ValueFromHeightCumulative, pub sent_in_profit_ema: RollingEmas2w, pub sent_in_loss: ValueFromHeightCumulative, @@ -111,15 +92,16 @@ pub struct RealizedBase { } impl RealizedBase { - /// Import realized base metrics from database. pub(crate) fn forced_import(cfg: &ImportConfig) -> Result { let v0 = Version::ZERO; let v1 = Version::ONE; let realized_cap_cents = cfg.import_computed("realized_cap_cents", v0)?; let realized_cap = LazyFromHeight::from_computed::( - &cfg.name("realized_cap"), cfg.version, - realized_cap_cents.height.read_only_boxed_clone(), &realized_cap_cents, + &cfg.name("realized_cap"), + cfg.version, + realized_cap_cents.height.read_only_boxed_clone(), + &realized_cap_cents, ); let realized_profit = cfg.import_cumulative("realized_profit", v0)?; @@ -128,8 +110,10 @@ impl RealizedBase { let realized_loss_ema_1w = cfg.import_computed("realized_loss_ema_1w", v0)?; let neg_realized_loss = LazyFromHeight::from_height_source::( - &cfg.name("neg_realized_loss"), cfg.version + Version::ONE, - realized_loss.height.read_only_boxed_clone(), cfg.indexes, + &cfg.name("neg_realized_loss"), + cfg.version + Version::ONE, + realized_loss.height.read_only_boxed_clone(), + cfg.indexes, ); let net_realized_pnl = cfg.import_cumulative("net_realized_pnl", v0)?; @@ -161,17 +145,23 @@ impl RealizedBase { let value_destroyed = cfg.import_computed("value_destroyed", v0)?; let capitulation_flow = LazyFromHeight::from_computed::( - &cfg.name("capitulation_flow"), cfg.version, - loss_value_destroyed.height.read_only_boxed_clone(), &loss_value_destroyed, + &cfg.name("capitulation_flow"), + cfg.version, + loss_value_destroyed.height.read_only_boxed_clone(), + &loss_value_destroyed, ); let profit_flow = LazyFromHeight::from_computed::( - &cfg.name("profit_flow"), cfg.version, - profit_value_destroyed.height.read_only_boxed_clone(), &profit_value_destroyed, + &cfg.name("profit_flow"), + cfg.version, + profit_value_destroyed.height.read_only_boxed_clone(), + &profit_value_destroyed, ); let realized_price_ratio = cfg.import_ratio("realized_price", v1)?; let mvrv = LazyFromHeight::from_lazy::, BasisPoints32>( - &cfg.name("mvrv"), cfg.version, &realized_price_ratio.ratio, + &cfg.name("mvrv"), + cfg.version, + &realized_price_ratio.ratio, ); // Rolling windows @@ -183,7 +173,8 @@ impl RealizedBase { // EMAs let sopr_24h_ema = cfg.import_emas_1w_1m("sopr_24h", v1)?; - let sell_side_risk_ratio_24h_ema = cfg.import_percent_emas_1w_1m_bp16("sell_side_risk_ratio_24h", v1)?; + let sell_side_risk_ratio_24h_ema = + cfg.import_percent_emas_1w_1m_bp16("sell_side_risk_ratio_24h", v1)?; let peak_regret_rel_to_realized_cap = cfg.import_percent_bp16("realized_peak_regret_rel_to_realized_cap", v1)?; @@ -228,10 +219,10 @@ impl RealizedBase { sell_side_risk_ratio, sell_side_risk_ratio_24h_ema, net_pnl_change_1m: cfg.import_computed("net_pnl_change_1m", Version::new(3))?, - net_pnl_change_1m_rel_to_realized_cap: - cfg.import_percent_bps16("net_pnl_change_1m_rel_to_realized_cap", Version::new(3))?, - net_pnl_change_1m_rel_to_market_cap: - cfg.import_percent_bps16("net_pnl_change_1m_rel_to_market_cap", Version::new(3))?, + net_pnl_change_1m_rel_to_realized_cap: cfg + .import_percent_bps16("net_pnl_change_1m_rel_to_realized_cap", Version::new(3))?, + net_pnl_change_1m_rel_to_market_cap: cfg + .import_percent_bps16("net_pnl_change_1m_rel_to_market_cap", Version::new(3))?, peak_regret, peak_regret_rel_to_realized_cap, sent_in_profit: cfg.import_value_cumulative("sent_in_profit", v0)?, @@ -241,7 +232,6 @@ impl RealizedBase { }) } - /// Get minimum length across height-indexed vectors written in block loop. pub(crate) fn min_stateful_height_len(&self) -> usize { self.realized_cap .height @@ -260,7 +250,6 @@ impl RealizedBase { .min(self.sent_in_loss.base.sats.height.len()) } - /// Push realized state values to height-indexed vectors. pub(crate) fn truncate_push(&mut self, height: Height, state: &RealizedState) -> Result<()> { self.realized_cap_cents .height @@ -271,7 +260,8 @@ impl RealizedBase { self.realized_loss .height .truncate_push(height, state.loss())?; - self.investor_price.cents + self.investor_price + .cents .height .truncate_push(height, state.investor_price())?; self.cap_raw.truncate_push(height, state.cap_raw())?; @@ -306,7 +296,6 @@ impl RealizedBase { Ok(()) } - /// Returns a Vec of mutable references to all stored vecs for parallel writing. pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> { vec![ &mut self.realized_cap_cents.height as &mut dyn AnyStoredVec, @@ -325,7 +314,6 @@ impl RealizedBase { ] } - /// Compute aggregate values from separate cohorts. pub(crate) fn compute_from_stateful( &mut self, starting_indexes: &Indexes, @@ -362,7 +350,8 @@ impl RealizedBase { .iter() .map(|o| o.investor_price.cents.height.version()) .fold(vecdb::Version::ZERO, |acc, v| acc + v); - self.investor_price.cents + self.investor_price + .cents .height .validate_computed_version_or_reset(investor_price_dep_version)?; @@ -404,7 +393,8 @@ impl RealizedBase { } else { Cents::new((sum_investor_cap / sum_cap.inner()) as u64) }; - self.investor_price.cents + self.investor_price + .cents .height .truncate_push(height, investor_price)?; } @@ -474,7 +464,6 @@ impl RealizedBase { Ok(()) } - /// First phase of computed metrics (indexes from height). pub(crate) fn compute_rest_part1( &mut self, starting_indexes: &Indexes, @@ -492,7 +481,10 @@ impl RealizedBase { &self.realized_profit.height, &self.realized_loss.height, |(i, profit, loss, ..)| { - (i, CentsSigned::new(profit.inner() as i64 - loss.inner() as i64)) + ( + i, + CentsSigned::new(profit.inner() as i64 - loss.inner() as i64), + ) }, exit, )?; @@ -512,7 +504,6 @@ impl RealizedBase { Ok(()) } - /// Second phase of computed metrics (base-only parts: realized price, rolling sums, EMAs). #[allow(clippy::too_many_arguments)] pub(crate) fn compute_rest_part2_base( &mut self, @@ -608,34 +599,54 @@ impl RealizedBase { exit, )?; - // === Rolling sum intermediates === let window_starts = blocks.count.window_starts(); self.value_created_sum.compute_rolling_sum( - starting_indexes.height, &window_starts, &self.value_created.height, exit, + starting_indexes.height, + &window_starts, + &self.value_created.height, + exit, )?; self.value_destroyed_sum.compute_rolling_sum( - starting_indexes.height, &window_starts, &self.value_destroyed.height, exit, + starting_indexes.height, + &window_starts, + &self.value_destroyed.height, + exit, )?; self.gross_pnl_sum.compute_rolling_sum( - starting_indexes.height, &window_starts, &self.gross_pnl.cents.height, exit, + starting_indexes.height, + &window_starts, + &self.gross_pnl.cents.height, + exit, )?; // Compute SOPR from rolling sums - for ((sopr, vc), vd) in self.sopr.as_mut_array().into_iter() + for ((sopr, vc), vd) in self + .sopr + .as_mut_array() + .into_iter() .zip(self.value_created_sum.as_array()) .zip(self.value_destroyed_sum.as_array()) { sopr.compute_binary::( - starting_indexes.height, &vc.height, &vd.height, exit, + starting_indexes.height, + &vc.height, + &vd.height, + exit, )?; } // Compute sell-side risk ratios - for (ssrr, rv) in self.sell_side_risk_ratio.as_mut_array().into_iter() + for (ssrr, rv) in self + .sell_side_risk_ratio + .as_mut_array() + .into_iter() .zip(self.gross_pnl_sum.as_array()) { ssrr.compute_binary::( - starting_indexes.height, &rv.height, &self.realized_cap_cents.height, exit, + starting_indexes.height, + &rv.height, + &self.realized_cap_cents.height, + exit, )?; } @@ -652,14 +663,12 @@ impl RealizedBase { &self.realized_loss.height, exit, )?; - self.net_realized_pnl_ema_1w - .height - .compute_rolling_ema( - starting_indexes.height, - &blocks.count.height_1w_ago, - &self.net_realized_pnl.height, - exit, - )?; + self.net_realized_pnl_ema_1w.height.compute_rolling_ema( + starting_indexes.height, + &blocks.count.height_1w_ago, + &self.net_realized_pnl.height, + exit, + )?; // 14-day EMA of sent in profit/loss self.sent_in_profit_ema.compute( @@ -726,14 +735,12 @@ impl RealizedBase { )?; // Net realized PnL cumulative 30d delta - self.net_pnl_change_1m - .height - .compute_rolling_change( - starting_indexes.height, - &blocks.count.height_1m_ago, - &self.net_realized_pnl.cumulative.height, - exit, - )?; + self.net_pnl_change_1m.height.compute_rolling_change( + starting_indexes.height, + &blocks.count.height_1m_ago, + &self.net_realized_pnl.cumulative.height, + exit, + )?; self.net_pnl_change_1m_rel_to_realized_cap .compute_binary::( diff --git a/crates/brk_computer/src/distribution/metrics/realized/extended.rs b/crates/brk_computer/src/distribution/metrics/realized/extended.rs index 2d38ff1d9..88ec79f2a 100644 --- a/crates/brk_computer/src/distribution/metrics/realized/extended.rs +++ b/crates/brk_computer/src/distribution/metrics/realized/extended.rs @@ -6,8 +6,8 @@ use vecdb::{Exit, ReadableVec, Rw, StorageMode}; use crate::{ blocks, internal::{ - ComputedFromHeightRatioExtension, PercentFromHeight, - RatioCents64, RatioDollarsBp16, RollingWindows, + ComputedFromHeightRatioExtension, PercentFromHeight, RatioCents64, RatioDollarsBp16, + RollingWindows, }, }; @@ -15,19 +15,15 @@ use crate::distribution::metrics::ImportConfig; use super::RealizedBase; -/// Extended realized metrics (only for extended cohorts: all, sth, lth, age_range). #[derive(Traversable)] pub struct RealizedExtended { pub realized_cap_rel_to_own_market_cap: PercentFromHeight, - // === Realized Profit/Loss Rolling Sums === pub realized_profit_sum: RollingWindows, pub realized_loss_sum: RollingWindows, - // === Realized Profit to Loss Ratio (from rolling sums) === pub realized_profit_to_loss_ratio: RollingWindows, - // === Extended ratio metrics for realized/investor price === pub realized_price_ratio_ext: ComputedFromHeightRatioExtension, pub investor_price_ratio_ext: ComputedFromHeightRatioExtension, } @@ -35,15 +31,23 @@ pub struct RealizedExtended { impl RealizedExtended { pub(crate) fn forced_import(cfg: &ImportConfig) -> Result { Ok(RealizedExtended { - realized_cap_rel_to_own_market_cap: cfg.import_percent_bp16("realized_cap_rel_to_own_market_cap", Version::ZERO)?, + realized_cap_rel_to_own_market_cap: cfg + .import_percent_bp16("realized_cap_rel_to_own_market_cap", Version::ZERO)?, realized_profit_sum: cfg.import_rolling("realized_profit", Version::ONE)?, realized_loss_sum: cfg.import_rolling("realized_loss", Version::ONE)?, - realized_profit_to_loss_ratio: cfg.import_rolling("realized_profit_to_loss_ratio", Version::ONE)?, + realized_profit_to_loss_ratio: cfg + .import_rolling("realized_profit_to_loss_ratio", Version::ONE)?, realized_price_ratio_ext: ComputedFromHeightRatioExtension::forced_import( - cfg.db, &cfg.name("realized_price"), cfg.version + Version::ONE, cfg.indexes, + cfg.db, + &cfg.name("realized_price"), + cfg.version + Version::ONE, + cfg.indexes, )?, investor_price_ratio_ext: ComputedFromHeightRatioExtension::forced_import( - cfg.db, &cfg.name("investor_price"), cfg.version, cfg.indexes, + cfg.db, + &cfg.name("investor_price"), + cfg.version, + cfg.indexes, )?, }) } @@ -60,10 +64,16 @@ impl RealizedExtended { // Realized profit/loss rolling sums let window_starts = blocks.count.window_starts(); self.realized_profit_sum.compute_rolling_sum( - starting_indexes.height, &window_starts, &base.realized_profit.height, exit, + starting_indexes.height, + &window_starts, + &base.realized_profit.height, + exit, )?; self.realized_loss_sum.compute_rolling_sum( - starting_indexes.height, &window_starts, &base.realized_loss.height, exit, + starting_indexes.height, + &window_starts, + &base.realized_loss.height, + exit, )?; // Realized cap relative to own market cap @@ -76,12 +86,18 @@ impl RealizedExtended { )?; // Realized profit to loss ratios - for ((ratio, profit), loss) in self.realized_profit_to_loss_ratio.as_mut_array().into_iter() + for ((ratio, profit), loss) in self + .realized_profit_to_loss_ratio + .as_mut_array() + .into_iter() .zip(self.realized_profit_sum.as_array()) .zip(self.realized_loss_sum.as_array()) { ratio.compute_binary::( - starting_indexes.height, &profit.height, &loss.height, exit, + starting_indexes.height, + &profit.height, + &loss.height, + exit, )?; } diff --git a/crates/brk_computer/src/distribution/metrics/relative/base.rs b/crates/brk_computer/src/distribution/metrics/relative/base.rs index 193b8b647..a95140ba4 100644 --- a/crates/brk_computer/src/distribution/metrics/relative/base.rs +++ b/crates/brk_computer/src/distribution/metrics/relative/base.rs @@ -4,29 +4,23 @@ use brk_types::{BasisPoints16, BasisPointsSigned16, Dollars, Height, Sats, Store use vecdb::{Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode}; use crate::internal::{ - Bps16ToFloat, LazyFromHeight, - NegRatioDollarsBps16, PercentFromHeight, RatioDollarsBp16, RatioDollarsBps16, RatioSatsBp16, + Bps16ToFloat, LazyFromHeight, NegRatioDollarsBps16, PercentFromHeight, RatioDollarsBp16, + RatioDollarsBps16, RatioSatsBp16, }; use crate::distribution::metrics::{ImportConfig, RealizedBase, UnrealizedBase}; -/// Base relative metrics (always computed when relative is enabled). -/// All fields are non-Optional - market_cap and realized_cap are always -/// available when relative metrics are enabled. #[derive(Traversable)] pub struct RelativeBase { - // === Supply in Profit/Loss Relative to Own Supply === pub supply_in_profit_rel_to_own_supply: PercentFromHeight, pub supply_in_loss_rel_to_own_supply: PercentFromHeight, - // === Unrealized vs Market Cap === pub unrealized_profit_rel_to_market_cap: PercentFromHeight, pub unrealized_loss_rel_to_market_cap: PercentFromHeight, pub neg_unrealized_loss_rel_to_market_cap: PercentFromHeight, pub net_unrealized_pnl_rel_to_market_cap: PercentFromHeight, pub nupl: LazyFromHeight, - // === Invested Capital in Profit/Loss as % of Realized Cap === pub invested_capital_in_profit_rel_to_realized_cap: PercentFromHeight, pub invested_capital_in_loss_rel_to_realized_cap: PercentFromHeight, } @@ -42,27 +36,34 @@ impl RelativeBase { let nupl = LazyFromHeight::from_computed::( &cfg.name("nupl"), cfg.version + v2, - net_unrealized_pnl_rel_to_market_cap.bps.height.read_only_boxed_clone(), + net_unrealized_pnl_rel_to_market_cap + .bps + .height + .read_only_boxed_clone(), &net_unrealized_pnl_rel_to_market_cap.bps, ); Ok(Self { - supply_in_profit_rel_to_own_supply: - cfg.import_percent_bp16("supply_in_profit_rel_to_own_supply", v1)?, - supply_in_loss_rel_to_own_supply: - cfg.import_percent_bp16("supply_in_loss_rel_to_own_supply", v1)?, - unrealized_profit_rel_to_market_cap: - cfg.import_percent_bp16("unrealized_profit_rel_to_market_cap", v2)?, - unrealized_loss_rel_to_market_cap: - cfg.import_percent_bp16("unrealized_loss_rel_to_market_cap", v2)?, - neg_unrealized_loss_rel_to_market_cap: - cfg.import_percent_bps16("neg_unrealized_loss_rel_to_market_cap", v2)?, + supply_in_profit_rel_to_own_supply: cfg + .import_percent_bp16("supply_in_profit_rel_to_own_supply", v1)?, + supply_in_loss_rel_to_own_supply: cfg + .import_percent_bp16("supply_in_loss_rel_to_own_supply", v1)?, + unrealized_profit_rel_to_market_cap: cfg + .import_percent_bp16("unrealized_profit_rel_to_market_cap", v2)?, + unrealized_loss_rel_to_market_cap: cfg + .import_percent_bp16("unrealized_loss_rel_to_market_cap", v2)?, + neg_unrealized_loss_rel_to_market_cap: cfg + .import_percent_bps16("neg_unrealized_loss_rel_to_market_cap", v2)?, net_unrealized_pnl_rel_to_market_cap, nupl, - invested_capital_in_profit_rel_to_realized_cap: - cfg.import_percent_bp16("invested_capital_in_profit_rel_to_realized_cap", Version::ZERO)?, - invested_capital_in_loss_rel_to_realized_cap: - cfg.import_percent_bp16("invested_capital_in_loss_rel_to_realized_cap", Version::ZERO)?, + invested_capital_in_profit_rel_to_realized_cap: cfg.import_percent_bp16( + "invested_capital_in_profit_rel_to_realized_cap", + Version::ZERO, + )?, + invested_capital_in_loss_rel_to_realized_cap: cfg.import_percent_bp16( + "invested_capital_in_loss_rel_to_realized_cap", + Version::ZERO, + )?, }) } @@ -77,35 +78,59 @@ impl RelativeBase { ) -> Result<()> { self.supply_in_profit_rel_to_own_supply .compute_binary::( - max_from, &unrealized.supply_in_profit.sats.height, supply_total_sats, exit, + max_from, + &unrealized.supply_in_profit.sats.height, + supply_total_sats, + exit, )?; self.supply_in_loss_rel_to_own_supply .compute_binary::( - max_from, &unrealized.supply_in_loss.sats.height, supply_total_sats, exit, + max_from, + &unrealized.supply_in_loss.sats.height, + supply_total_sats, + exit, )?; self.unrealized_profit_rel_to_market_cap .compute_binary::( - max_from, &unrealized.unrealized_profit.usd.height, market_cap, exit, + max_from, + &unrealized.unrealized_profit.usd.height, + market_cap, + exit, )?; self.unrealized_loss_rel_to_market_cap .compute_binary::( - max_from, &unrealized.unrealized_loss.usd.height, market_cap, exit, + max_from, + &unrealized.unrealized_loss.usd.height, + market_cap, + exit, )?; self.neg_unrealized_loss_rel_to_market_cap .compute_binary::( - max_from, &unrealized.unrealized_loss.usd.height, market_cap, exit, + max_from, + &unrealized.unrealized_loss.usd.height, + market_cap, + exit, )?; self.net_unrealized_pnl_rel_to_market_cap .compute_binary::( - max_from, &unrealized.net_unrealized_pnl.usd.height, market_cap, exit, + max_from, + &unrealized.net_unrealized_pnl.usd.height, + market_cap, + exit, )?; self.invested_capital_in_profit_rel_to_realized_cap .compute_binary::( - max_from, &unrealized.invested_capital_in_profit.usd.height, &realized.realized_cap.height, exit, + max_from, + &unrealized.invested_capital_in_profit.usd.height, + &realized.realized_cap.height, + exit, )?; self.invested_capital_in_loss_rel_to_realized_cap .compute_binary::( - max_from, &unrealized.invested_capital_in_loss.usd.height, &realized.realized_cap.height, exit, + max_from, + &unrealized.invested_capital_in_loss.usd.height, + &realized.realized_cap.height, + exit, )?; Ok(()) } diff --git a/crates/brk_computer/src/distribution/metrics/relative/extended_own_market_cap.rs b/crates/brk_computer/src/distribution/metrics/relative/extended_own_market_cap.rs index 86fae4b7c..67eb92dc9 100644 --- a/crates/brk_computer/src/distribution/metrics/relative/extended_own_market_cap.rs +++ b/crates/brk_computer/src/distribution/metrics/relative/extended_own_market_cap.rs @@ -12,14 +12,10 @@ use crate::distribution::metrics::{ImportConfig, UnrealizedBase}; /// Extended relative metrics for own market cap (extended && rel_to_all). #[derive(Traversable)] pub struct RelativeExtendedOwnMarketCap { - pub unrealized_profit_rel_to_own_market_cap: - PercentFromHeight, - pub unrealized_loss_rel_to_own_market_cap: - PercentFromHeight, - pub neg_unrealized_loss_rel_to_own_market_cap: - PercentFromHeight, - pub net_unrealized_pnl_rel_to_own_market_cap: - PercentFromHeight, + pub unrealized_profit_rel_to_own_market_cap: PercentFromHeight, + pub unrealized_loss_rel_to_own_market_cap: PercentFromHeight, + pub neg_unrealized_loss_rel_to_own_market_cap: PercentFromHeight, + pub net_unrealized_pnl_rel_to_own_market_cap: PercentFromHeight, } impl RelativeExtendedOwnMarketCap { @@ -27,14 +23,14 @@ impl RelativeExtendedOwnMarketCap { let v2 = Version::new(2); Ok(Self { - unrealized_profit_rel_to_own_market_cap: - cfg.import_percent_bp16("unrealized_profit_rel_to_own_market_cap", v2)?, - unrealized_loss_rel_to_own_market_cap: - cfg.import_percent_bp16("unrealized_loss_rel_to_own_market_cap", v2)?, - neg_unrealized_loss_rel_to_own_market_cap: - cfg.import_percent_bps16("neg_unrealized_loss_rel_to_own_market_cap", v2)?, - net_unrealized_pnl_rel_to_own_market_cap: - cfg.import_percent_bps16("net_unrealized_pnl_rel_to_own_market_cap", v2)?, + unrealized_profit_rel_to_own_market_cap: cfg + .import_percent_bp16("unrealized_profit_rel_to_own_market_cap", v2)?, + unrealized_loss_rel_to_own_market_cap: cfg + .import_percent_bp16("unrealized_loss_rel_to_own_market_cap", v2)?, + neg_unrealized_loss_rel_to_own_market_cap: cfg + .import_percent_bps16("neg_unrealized_loss_rel_to_own_market_cap", v2)?, + net_unrealized_pnl_rel_to_own_market_cap: cfg + .import_percent_bps16("net_unrealized_pnl_rel_to_own_market_cap", v2)?, }) } @@ -47,19 +43,31 @@ impl RelativeExtendedOwnMarketCap { ) -> Result<()> { self.unrealized_profit_rel_to_own_market_cap .compute_binary::( - max_from, &unrealized.unrealized_profit.usd.height, own_market_cap, exit, + max_from, + &unrealized.unrealized_profit.usd.height, + own_market_cap, + exit, )?; self.unrealized_loss_rel_to_own_market_cap .compute_binary::( - max_from, &unrealized.unrealized_loss.usd.height, own_market_cap, exit, + max_from, + &unrealized.unrealized_loss.usd.height, + own_market_cap, + exit, )?; self.neg_unrealized_loss_rel_to_own_market_cap .compute_binary::( - max_from, &unrealized.unrealized_loss.usd.height, own_market_cap, exit, + max_from, + &unrealized.unrealized_loss.usd.height, + own_market_cap, + exit, )?; self.net_unrealized_pnl_rel_to_own_market_cap .compute_binary::( - max_from, &unrealized.net_unrealized_pnl.usd.height, own_market_cap, exit, + max_from, + &unrealized.net_unrealized_pnl.usd.height, + own_market_cap, + exit, )?; Ok(()) } diff --git a/crates/brk_computer/src/distribution/metrics/relative/extended_own_pnl.rs b/crates/brk_computer/src/distribution/metrics/relative/extended_own_pnl.rs index 2ad5ec999..c5914eb9e 100644 --- a/crates/brk_computer/src/distribution/metrics/relative/extended_own_pnl.rs +++ b/crates/brk_computer/src/distribution/metrics/relative/extended_own_pnl.rs @@ -12,14 +12,10 @@ use crate::distribution::metrics::{ImportConfig, UnrealizedBase}; /// Extended relative metrics for own total unrealized PnL (extended only). #[derive(Traversable)] pub struct RelativeExtendedOwnPnl { - pub unrealized_profit_rel_to_own_gross_pnl: - PercentFromHeight, - pub unrealized_loss_rel_to_own_gross_pnl: - PercentFromHeight, - pub neg_unrealized_loss_rel_to_own_gross_pnl: - PercentFromHeight, - pub net_unrealized_pnl_rel_to_own_gross_pnl: - PercentFromHeight, + pub unrealized_profit_rel_to_own_gross_pnl: PercentFromHeight, + pub unrealized_loss_rel_to_own_gross_pnl: PercentFromHeight, + pub neg_unrealized_loss_rel_to_own_gross_pnl: PercentFromHeight, + pub net_unrealized_pnl_rel_to_own_gross_pnl: PercentFromHeight, } impl RelativeExtendedOwnPnl { @@ -28,14 +24,14 @@ impl RelativeExtendedOwnPnl { let v2 = Version::new(2); Ok(Self { - unrealized_profit_rel_to_own_gross_pnl: - cfg.import_percent_bp16("unrealized_profit_rel_to_own_gross_pnl", v1)?, - unrealized_loss_rel_to_own_gross_pnl: - cfg.import_percent_bp16("unrealized_loss_rel_to_own_gross_pnl", v1)?, - neg_unrealized_loss_rel_to_own_gross_pnl: - cfg.import_percent_bps16("neg_unrealized_loss_rel_to_own_gross_pnl", v1)?, - net_unrealized_pnl_rel_to_own_gross_pnl: - cfg.import_percent_bps16("net_unrealized_pnl_rel_to_own_gross_pnl", v2)?, + unrealized_profit_rel_to_own_gross_pnl: cfg + .import_percent_bp16("unrealized_profit_rel_to_own_gross_pnl", v1)?, + unrealized_loss_rel_to_own_gross_pnl: cfg + .import_percent_bp16("unrealized_loss_rel_to_own_gross_pnl", v1)?, + neg_unrealized_loss_rel_to_own_gross_pnl: cfg + .import_percent_bps16("neg_unrealized_loss_rel_to_own_gross_pnl", v1)?, + net_unrealized_pnl_rel_to_own_gross_pnl: cfg + .import_percent_bps16("net_unrealized_pnl_rel_to_own_gross_pnl", v2)?, }) } @@ -47,19 +43,31 @@ impl RelativeExtendedOwnPnl { ) -> Result<()> { self.unrealized_profit_rel_to_own_gross_pnl .compute_binary::( - max_from, &unrealized.unrealized_profit.usd.height, &unrealized.gross_pnl.usd.height, exit, + max_from, + &unrealized.unrealized_profit.usd.height, + &unrealized.gross_pnl.usd.height, + exit, )?; self.unrealized_loss_rel_to_own_gross_pnl .compute_binary::( - max_from, &unrealized.unrealized_loss.usd.height, &unrealized.gross_pnl.usd.height, exit, + max_from, + &unrealized.unrealized_loss.usd.height, + &unrealized.gross_pnl.usd.height, + exit, )?; self.neg_unrealized_loss_rel_to_own_gross_pnl .compute_binary::( - max_from, &unrealized.unrealized_loss.usd.height, &unrealized.gross_pnl.usd.height, exit, + max_from, + &unrealized.unrealized_loss.usd.height, + &unrealized.gross_pnl.usd.height, + exit, )?; self.net_unrealized_pnl_rel_to_own_gross_pnl .compute_binary::( - max_from, &unrealized.net_unrealized_pnl.usd.height, &unrealized.gross_pnl.usd.height, exit, + max_from, + &unrealized.net_unrealized_pnl.usd.height, + &unrealized.gross_pnl.usd.height, + exit, )?; Ok(()) } diff --git a/crates/brk_computer/src/distribution/metrics/relative/to_all.rs b/crates/brk_computer/src/distribution/metrics/relative/to_all.rs index 8194001c7..43ee646bc 100644 --- a/crates/brk_computer/src/distribution/metrics/relative/to_all.rs +++ b/crates/brk_computer/src/distribution/metrics/relative/to_all.rs @@ -10,23 +10,20 @@ use crate::distribution::metrics::{ImportConfig, UnrealizedBase}; /// Relative-to-all metrics (not present for the "all" cohort itself). #[derive(Traversable)] pub struct RelativeToAll { - pub supply_rel_to_circulating_supply: - PercentFromHeight, - pub supply_in_profit_rel_to_circulating_supply: - PercentFromHeight, - pub supply_in_loss_rel_to_circulating_supply: - PercentFromHeight, + pub supply_rel_to_circulating_supply: PercentFromHeight, + pub supply_in_profit_rel_to_circulating_supply: PercentFromHeight, + pub supply_in_loss_rel_to_circulating_supply: PercentFromHeight, } impl RelativeToAll { pub(crate) fn forced_import(cfg: &ImportConfig) -> Result { Ok(Self { - supply_rel_to_circulating_supply: - cfg.import_percent_bp16("supply_rel_to_circulating_supply", Version::ONE)?, - supply_in_profit_rel_to_circulating_supply: - cfg.import_percent_bp16("supply_in_profit_rel_to_circulating_supply", Version::ONE)?, - supply_in_loss_rel_to_circulating_supply: - cfg.import_percent_bp16("supply_in_loss_rel_to_circulating_supply", Version::ONE)?, + supply_rel_to_circulating_supply: cfg + .import_percent_bp16("supply_rel_to_circulating_supply", Version::ONE)?, + supply_in_profit_rel_to_circulating_supply: cfg + .import_percent_bp16("supply_in_profit_rel_to_circulating_supply", Version::ONE)?, + supply_in_loss_rel_to_circulating_supply: cfg + .import_percent_bp16("supply_in_loss_rel_to_circulating_supply", Version::ONE)?, }) } @@ -40,15 +37,24 @@ impl RelativeToAll { ) -> Result<()> { self.supply_rel_to_circulating_supply .compute_binary::( - max_from, supply_total_sats, all_supply_sats, exit, + max_from, + supply_total_sats, + all_supply_sats, + exit, )?; self.supply_in_profit_rel_to_circulating_supply .compute_binary::( - max_from, &unrealized.supply_in_profit.sats.height, all_supply_sats, exit, + max_from, + &unrealized.supply_in_profit.sats.height, + all_supply_sats, + exit, )?; self.supply_in_loss_rel_to_circulating_supply .compute_binary::( - max_from, &unrealized.supply_in_loss.sats.height, all_supply_sats, exit, + max_from, + &unrealized.supply_in_loss.sats.height, + all_supply_sats, + exit, )?; Ok(()) } diff --git a/crates/brk_computer/src/distribution/metrics/relative/with_extended.rs b/crates/brk_computer/src/distribution/metrics/relative/with_extended.rs index cd8114f45..bd21eaaee 100644 --- a/crates/brk_computer/src/distribution/metrics/relative/with_extended.rs +++ b/crates/brk_computer/src/distribution/metrics/relative/with_extended.rs @@ -6,10 +6,7 @@ use vecdb::{Exit, ReadableVec, Rw, StorageMode}; use crate::distribution::metrics::{ImportConfig, RealizedBase, UnrealizedBase}; -use super::{ - RelativeBase, RelativeExtendedOwnMarketCap, RelativeExtendedOwnPnl, - RelativeToAll, -}; +use super::{RelativeBase, RelativeExtendedOwnMarketCap, RelativeExtendedOwnPnl, RelativeToAll}; /// Full extended relative metrics (base + rel_to_all + own_market_cap + own_pnl). /// Used by: sth, lth, age_range cohorts. diff --git a/crates/brk_computer/src/distribution/metrics/supply.rs b/crates/brk_computer/src/distribution/metrics/supply.rs index c04b3c73c..825504888 100644 --- a/crates/brk_computer/src/distribution/metrics/supply.rs +++ b/crates/brk_computer/src/distribution/metrics/supply.rs @@ -7,8 +7,8 @@ use rayon::prelude::*; use vecdb::{AnyStoredVec, AnyVec, Exit, Rw, StorageMode, WritableVec}; use crate::internal::{ - HalveCents, HalveDollars, HalveSats, HalveSatsToBitcoin, - LazyValueFromHeight, ValueFromHeightChange, ValueFromHeight, + HalveCents, HalveDollars, HalveSats, HalveSatsToBitcoin, LazyValueFromHeight, ValueFromHeight, + ValueFromHeightChange, }; use super::ImportConfig; diff --git a/crates/brk_computer/src/distribution/metrics/unrealized/base.rs b/crates/brk_computer/src/distribution/metrics/unrealized/base.rs index 3f5d1ad0c..d56d75eec 100644 --- a/crates/brk_computer/src/distribution/metrics/unrealized/base.rs +++ b/crates/brk_computer/src/distribution/metrics/unrealized/base.rs @@ -2,8 +2,8 @@ use brk_error::Result; use brk_traversable::Traversable; use brk_types::{Cents, CentsSats, CentsSigned, CentsSquaredSats, Height, Indexes, Version}; use vecdb::{ - AnyStoredVec, AnyVec, BytesVec, Exit, ReadableCloneableVec, ReadableVec, - Rw, StorageMode, WritableVec, + AnyStoredVec, AnyVec, BytesVec, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode, + WritableVec, }; use crate::{ @@ -19,36 +19,28 @@ use brk_types::Dollars; use crate::distribution::metrics::ImportConfig; -/// Base unrealized profit/loss metrics (always computed). #[derive(Traversable)] pub struct UnrealizedBase { - // === Supply in Profit/Loss === pub supply_in_profit: ValueFromHeight, pub supply_in_loss: ValueFromHeight, - // === Unrealized Profit/Loss === pub unrealized_profit: FiatFromHeight, pub unrealized_loss: FiatFromHeight, - // === Invested Capital in Profit/Loss === pub invested_capital_in_profit: FiatFromHeight, pub invested_capital_in_loss: FiatFromHeight, - // === Raw values for precise aggregation (used to compute pain/greed indices) === pub invested_capital_in_profit_raw: M::Stored>, pub invested_capital_in_loss_raw: M::Stored>, pub investor_cap_in_profit_raw: M::Stored>, pub investor_cap_in_loss_raw: M::Stored>, - // === Pain/Greed Indices === pub pain_index: FiatFromHeight, pub greed_index: FiatFromHeight, pub net_sentiment: FiatFromHeight, - // === Negated === pub neg_unrealized_loss: LazyFromHeight, - // === Net and Total === pub net_unrealized_pnl: FiatFromHeight, pub gross_pnl: FiatFromHeight, } @@ -65,7 +57,8 @@ impl UnrealizedBase { let invested_capital_in_profit = cfg.import_fiat("invested_capital_in_profit", v0)?; let invested_capital_in_loss = cfg.import_fiat("invested_capital_in_loss", v0)?; - let invested_capital_in_profit_raw = cfg.import_bytes("invested_capital_in_profit_raw", v0)?; + let invested_capital_in_profit_raw = + cfg.import_bytes("invested_capital_in_profit_raw", v0)?; let invested_capital_in_loss_raw = cfg.import_bytes("invested_capital_in_loss_raw", v0)?; let investor_cap_in_profit_raw = cfg.import_bytes("investor_cap_in_profit_raw", v0)?; let investor_cap_in_loss_raw = cfg.import_bytes("investor_cap_in_loss_raw", v0)?; @@ -193,39 +186,30 @@ impl UnrealizedBase { others: &[&Self], exit: &Exit, ) -> Result<()> { - self.supply_in_profit - .sats - .height - .compute_sum_of_others( - starting_indexes.height, - &others - .iter() - .map(|v| &v.supply_in_profit.sats.height) - .collect::>(), - exit, - )?; - self.supply_in_loss - .sats - .height - .compute_sum_of_others( - starting_indexes.height, - &others - .iter() - .map(|v| &v.supply_in_loss.sats.height) - .collect::>(), - exit, - )?; - self.unrealized_profit - .cents - .height - .compute_sum_of_others( - starting_indexes.height, - &others - .iter() - .map(|v| &v.unrealized_profit.cents.height) - .collect::>(), - exit, - )?; + self.supply_in_profit.sats.height.compute_sum_of_others( + starting_indexes.height, + &others + .iter() + .map(|v| &v.supply_in_profit.sats.height) + .collect::>(), + exit, + )?; + self.supply_in_loss.sats.height.compute_sum_of_others( + starting_indexes.height, + &others + .iter() + .map(|v| &v.supply_in_loss.sats.height) + .collect::>(), + exit, + )?; + self.unrealized_profit.cents.height.compute_sum_of_others( + starting_indexes.height, + &others + .iter() + .map(|v| &v.unrealized_profit.cents.height) + .collect::>(), + exit, + )?; self.unrealized_loss.cents.height.compute_sum_of_others( starting_indexes.height, &others @@ -273,7 +257,10 @@ impl UnrealizedBase { // Pre-collect all cohort data to avoid per-element BytesVec reads in nested loop let invested_profit_ranges: Vec> = others .iter() - .map(|o| o.invested_capital_in_profit_raw.collect_range_at(start, end)) + .map(|o| { + o.invested_capital_in_profit_raw + .collect_range_at(start, end) + }) .collect(); let invested_loss_ranges: Vec> = others .iter() @@ -336,10 +323,7 @@ impl UnrealizedBase { } let investor_price_losers = investor_cap.inner() / invested_cap.inner(); let spot_u128 = spot.as_u128(); - ( - h, - Cents::new((investor_price_losers - spot_u128) as u64), - ) + (h, Cents::new((investor_price_losers - spot_u128) as u64)) }, exit, )?; @@ -356,10 +340,7 @@ impl UnrealizedBase { } let investor_price_winners = investor_cap.inner() / invested_cap.inner(); let spot_u128 = spot.as_u128(); - ( - h, - Cents::new((spot_u128 - investor_price_winners) as u64), - ) + (h, Cents::new((spot_u128 - investor_price_winners) as u64)) }, exit, )?; diff --git a/crates/brk_computer/src/distribution/state/cohort/address.rs b/crates/brk_computer/src/distribution/state/cohort/address.rs index 9409f8a33..1c56fbdd6 100644 --- a/crates/brk_computer/src/distribution/state/cohort/address.rs +++ b/crates/brk_computer/src/distribution/state/cohort/address.rs @@ -18,8 +18,7 @@ impl AddressCohortState { pub(crate) fn new(path: &Path, name: &str) -> Self { Self { addr_count: 0, - inner: CohortState::new(path, name) - .with_price_rounding(COST_BASIS_PRICE_DIGITS), + inner: CohortState::new(path, name).with_price_rounding(COST_BASIS_PRICE_DIGITS), } } @@ -136,5 +135,4 @@ impl AddressCohortState { self.inner.decrement_snapshot(&snapshot); } - } diff --git a/crates/brk_computer/src/distribution/state/cohort/base.rs b/crates/brk_computer/src/distribution/state/cohort/base.rs index 84e63dc0f..644c9c76b 100644 --- a/crates/brk_computer/src/distribution/state/cohort/base.rs +++ b/crates/brk_computer/src/distribution/state/cohort/base.rs @@ -1,7 +1,7 @@ use std::path::Path; use brk_error::Result; -use brk_types::{Age, CentsSats, Cents, CostBasisSnapshot, Height, Sats, SupplyState}; +use brk_types::{Age, Cents, CentsSats, CostBasisSnapshot, Height, Sats, SupplyState}; use super::super::cost_basis::{CostBasisData, Percentiles, RealizedState, UnrealizedState}; @@ -256,8 +256,7 @@ impl CohortState { } pub(crate) fn compute_unrealized_state(&mut self, height_price: Cents) -> UnrealizedState { - self.cost_basis_data - .compute_unrealized_state(height_price) + self.cost_basis_data.compute_unrealized_state(height_price) } pub(crate) fn write(&mut self, height: Height, cleanup: bool) -> Result<()> { diff --git a/crates/brk_computer/src/distribution/state/cost_basis/data.rs b/crates/brk_computer/src/distribution/state/cost_basis/data.rs index 2f29e094a..3408440c1 100644 --- a/crates/brk_computer/src/distribution/state/cost_basis/data.rs +++ b/crates/brk_computer/src/distribution/state/cost_basis/data.rs @@ -6,7 +6,7 @@ use std::{ use brk_error::{Error, Result}; use brk_types::{ - CentsCompact, CentsSats, CentsSquaredSats, Cents, CostBasisDistribution, Height, Sats, + Cents, CentsCompact, CentsSats, CentsSquaredSats, CostBasisDistribution, Height, Sats, }; use rustc_hash::FxHashMap; use vecdb::Bytes; @@ -95,7 +95,13 @@ impl CostBasisData { pub(crate) fn iter(&self) -> impl Iterator { self.assert_pending_empty(); - self.state.as_ref().unwrap().base.map.iter().map(|(&k, v)| (k, v)) + self.state + .as_ref() + .unwrap() + .base + .map + .iter() + .map(|(&k, v)| (k, v)) } pub(crate) fn is_empty(&self) -> bool { @@ -105,7 +111,8 @@ impl CostBasisData { pub(crate) fn first_key_value(&self) -> Option<(CentsCompact, &Sats)> { self.assert_pending_empty(); self.state - .as_ref().unwrap() + .as_ref() + .unwrap() .base .map .first_key_value() @@ -115,7 +122,8 @@ impl CostBasisData { pub(crate) fn last_key_value(&self) -> Option<(CentsCompact, &Sats)> { self.assert_pending_empty(); self.state - .as_ref().unwrap() + .as_ref() + .unwrap() .base .map .last_key_value() @@ -179,7 +187,14 @@ impl CostBasisData { self.percentiles_dirty = true; } for (cents, (inc, dec)) in self.pending.drain() { - let entry = self.state.as_mut().unwrap().base.map.entry(cents).or_default(); + let entry = self + .state + .as_mut() + .unwrap() + .base + .map + .entry(cents) + .or_default(); *entry += inc; if *entry < dec { panic!( @@ -322,7 +337,10 @@ impl CostBasisData { } } - fs::write(self.path_state(height), self.state.as_ref().unwrap().serialize()?)?; + fs::write( + self.path_state(height), + self.state.as_ref().unwrap().serialize()?, + )?; Ok(()) } diff --git a/crates/brk_computer/src/distribution/state/cost_basis/realized.rs b/crates/brk_computer/src/distribution/state/cost_basis/realized.rs index 32fb59a8e..45e2f9ba8 100644 --- a/crates/brk_computer/src/distribution/state/cost_basis/realized.rs +++ b/crates/brk_computer/src/distribution/state/cost_basis/realized.rs @@ -1,6 +1,6 @@ use std::cmp::Ordering; -use brk_types::{CentsSats, CentsSquaredSats, Cents, Sats}; +use brk_types::{Cents, CentsSats, CentsSquaredSats, Sats}; /// Realized state using u128 for raw cent*sat values internally. /// This avoids overflow and defers division to output time for efficiency. @@ -156,14 +156,22 @@ impl RealizedState { /// Increment using pre-computed snapshot values (for address path) #[inline] - pub(crate) fn increment_snapshot(&mut self, price_sats: CentsSats, investor_cap: CentsSquaredSats) { + pub(crate) fn increment_snapshot( + &mut self, + price_sats: CentsSats, + investor_cap: CentsSquaredSats, + ) { self.cap_raw += price_sats.as_u128(); self.investor_cap_raw += investor_cap; } /// Decrement using pre-computed snapshot values (for address path) #[inline] - pub(crate) fn decrement_snapshot(&mut self, price_sats: CentsSats, investor_cap: CentsSquaredSats) { + pub(crate) fn decrement_snapshot( + &mut self, + price_sats: CentsSats, + investor_cap: CentsSquaredSats, + ) { self.cap_raw -= price_sats.as_u128(); self.investor_cap_raw -= investor_cap; } diff --git a/crates/brk_computer/src/distribution/state/cost_basis/unrealized.rs b/crates/brk_computer/src/distribution/state/cost_basis/unrealized.rs index c8a89536b..8ead22961 100644 --- a/crates/brk_computer/src/distribution/state/cost_basis/unrealized.rs +++ b/crates/brk_computer/src/distribution/state/cost_basis/unrealized.rs @@ -35,7 +35,6 @@ impl UnrealizedState { invested_capital_in_profit_raw: 0, invested_capital_in_loss_raw: 0, }; - } /// Internal cache state using u128 for raw cent*sat values. @@ -279,5 +278,4 @@ impl CachedUnrealizedState { state } - } diff --git a/crates/brk_computer/src/distribution/vecs.rs b/crates/brk_computer/src/distribution/vecs.rs index 38094f33f..89693af2d 100644 --- a/crates/brk_computer/src/distribution/vecs.rs +++ b/crates/brk_computer/src/distribution/vecs.rs @@ -4,12 +4,12 @@ use brk_error::Result; use brk_indexer::Indexer; use brk_traversable::Traversable; use brk_types::{ - Cents, EmptyAddressData, EmptyAddressIndex, FundedAddressData, FundedAddressIndex, - Height, Indexes, SupplyState, Timestamp, TxIndex, Version, + Cents, EmptyAddressData, EmptyAddressIndex, FundedAddressData, FundedAddressIndex, Height, + Indexes, SupplyState, Timestamp, TxIndex, Version, }; use tracing::{debug, info}; use vecdb::{ - AnyVec, BytesVec, Database, Exit, ImportableVec, LazyVecFrom1, PAGE_SIZE, ReadOnlyClone, + AnyVec, BytesVec, Database, Exit, ImportableVec, LazyVecFrom1, ReadOnlyClone, ReadableCloneableVec, ReadableVec, Rw, Stamp, StorageMode, WritableVec, }; @@ -22,7 +22,9 @@ use crate::{ }, state::BlockState, }, - indexes, inputs, outputs, prices, transactions, + indexes, inputs, + internal::{finalize_db, open_db}, + outputs, prices, transactions, }; use super::{ @@ -34,8 +36,6 @@ use super::{ }; const VERSION: Version = Version::new(22); - -/// Main struct holding all computed vectors and state for stateful computation. #[derive(Traversable)] pub struct Vecs { #[traversable(skip)] @@ -95,8 +95,7 @@ impl Vecs { let db_path = parent.join(super::DB_NAME); let states_path = db_path.join("states"); - let db = Database::open(&db_path)?; - db.set_min_len(PAGE_SIZE * 20_000_000)?; + let db = open_db(parent, super::DB_NAME, 20_000_000)?; db.set_min_regions(50_000)?; let version = parent_version + VERSION; @@ -139,8 +138,7 @@ impl Vecs { let total_addr_count = TotalAddrCountVecs::forced_import(&db, version, indexes)?; // Per-block delta of total (global + per-type) - let new_addr_count = - NewAddrCountVecs::forced_import(&db, version, indexes)?; + let new_addr_count = NewAddrCountVecs::forced_import(&db, version, indexes)?; // Growth rate: new / addr_count (global + per-type) let growth_rate = GrowthRateVecs::forced_import(&db, version, indexes)?; @@ -180,13 +178,7 @@ impl Vecs { states_path, }; - this.db.retain_regions( - this.iter_any_exportable() - .flat_map(|v| v.region_names()) - .collect(), - )?; - this.db.compact()?; - + finalize_db(&this.db, &this)?; Ok(this) } @@ -308,7 +300,10 @@ impl Vecs { Height::ZERO } else if chain_state.len() == usize::from(recovered_height) { // Normal resume: chain_state already matches, reuse as-is - debug!("reusing in-memory chain_state ({} entries)", chain_state.len()); + debug!( + "reusing in-memory chain_state ({} entries)", + chain_state.len() + ); recovered_height } else { debug!("rebuilding chain_state from stored values"); @@ -359,8 +354,7 @@ impl Vecs { let cached_prices = std::mem::take(&mut self.cached_prices); let cached_timestamps = std::mem::take(&mut self.cached_timestamps); - let cached_price_range_max = - std::mem::take(&mut self.cached_price_range_max); + let cached_price_range_max = std::mem::take(&mut self.cached_price_range_max); process_blocks( self, @@ -424,8 +418,12 @@ impl Vecs { self.address_activity .compute_rest(starting_indexes.height, &window_starts, exit)?; - self.new_addr_count - .compute(starting_indexes.height, &window_starts, &self.total_addr_count, exit)?; + self.new_addr_count.compute( + starting_indexes.height, + &window_starts, + &self.total_addr_count, + exit, + )?; // 6e. Compute growth_rate = new_addr_count / addr_count self.growth_rate.compute( diff --git a/crates/brk_computer/src/indexes/address.rs b/crates/brk_computer/src/indexes/address.rs index 50ed9c97b..c058a1f4c 100644 --- a/crates/brk_computer/src/indexes/address.rs +++ b/crates/brk_computer/src/indexes/address.rs @@ -6,7 +6,7 @@ use brk_types::{ P2PKHBytes, P2SHAddressIndex, P2SHBytes, P2TRAddressIndex, P2TRBytes, P2WPKHAddressIndex, P2WPKHBytes, P2WSHAddressIndex, P2WSHBytes, TxIndex, UnknownOutputIndex, Version, }; -use vecdb::{ReadableCloneableVec, LazyVecFrom1}; +use vecdb::{LazyVecFrom1, ReadableCloneableVec}; #[derive(Clone, Traversable)] pub struct Vecs { @@ -26,12 +26,14 @@ pub struct Vecs { #[derive(Clone, Traversable)] pub struct P2PK33Vecs { - pub identity: LazyVecFrom1, + pub identity: + LazyVecFrom1, } #[derive(Clone, Traversable)] pub struct P2PK65Vecs { - pub identity: LazyVecFrom1, + pub identity: + LazyVecFrom1, } #[derive(Clone, Traversable)] @@ -51,7 +53,8 @@ pub struct P2TRVecs { #[derive(Clone, Traversable)] pub struct P2WPKHVecs { - pub identity: LazyVecFrom1, + pub identity: + LazyVecFrom1, } #[derive(Clone, Traversable)] @@ -163,7 +166,11 @@ impl Vecs { identity: LazyVecFrom1::init( "emptyoutputindex", version, - indexer.vecs.scripts.empty_to_txindex.read_only_boxed_clone(), + indexer + .vecs + .scripts + .empty_to_txindex + .read_only_boxed_clone(), |index, _| index, ), }, @@ -171,7 +178,11 @@ impl Vecs { identity: LazyVecFrom1::init( "unknownoutputindex", version, - indexer.vecs.scripts.unknown_to_txindex.read_only_boxed_clone(), + indexer + .vecs + .scripts + .unknown_to_txindex + .read_only_boxed_clone(), |index, _| index, ), }, @@ -179,7 +190,11 @@ impl Vecs { identity: LazyVecFrom1::init( "opreturnindex", version, - indexer.vecs.scripts.opreturn_to_txindex.read_only_boxed_clone(), + indexer + .vecs + .scripts + .opreturn_to_txindex + .read_only_boxed_clone(), |index, _| index, ), }, diff --git a/crates/brk_computer/src/indexes/height.rs b/crates/brk_computer/src/indexes/height.rs index 285418817..db6ce8eab 100644 --- a/crates/brk_computer/src/indexes/height.rs +++ b/crates/brk_computer/src/indexes/height.rs @@ -1,8 +1,7 @@ use brk_traversable::Traversable; use brk_types::{ - Day1, Day3, Year10, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour12, Hour4, - Minute10, Minute30, Month1, Month3, Month6, StoredU64, Version, Week1, - Year1, + Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour4, Hour12, Minute10, Minute30, + Month1, Month3, Month6, StoredU64, Version, Week1, Year1, Year10, }; use vecdb::{Database, EagerVec, ImportableVec, PcoVec, Rw, StorageMode}; diff --git a/crates/brk_computer/src/indexes/mod.rs b/crates/brk_computer/src/indexes/mod.rs index 75fc6a9d7..0318640e4 100644 --- a/crates/brk_computer/src/indexes/mod.rs +++ b/crates/brk_computer/src/indexes/mod.rs @@ -25,12 +25,15 @@ use brk_error::Result; use brk_indexer::Indexer; use brk_traversable::Traversable; use brk_types::{ - Date, Day1, Day3, Hour1, Hour4, Hour12, Indexes, Minute10, Minute30, Month1, - Month3, Month6, Version, Week1, Year1, Year10, + Date, Day1, Day3, Height, Hour1, Hour4, Hour12, Indexes, Minute10, Minute30, Month1, Month3, + Month6, Version, Week1, Year1, Year10, }; -use vecdb::{Database, Exit, PAGE_SIZE, ReadableVec, Rw, StorageMode}; +use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode}; -use crate::blocks; +use crate::{ + blocks, + internal::{finalize_db, open_db}, +}; pub use address::Vecs as AddressVecs; pub use day1::Vecs as Day1Vecs; @@ -86,8 +89,7 @@ impl Vecs { parent_version: Version, indexer: &Indexer, ) -> Result { - let db = Database::open(&parent.join(DB_NAME))?; - db.set_min_len(PAGE_SIZE * 10_000_000)?; + let db = open_db(parent, DB_NAME, 10_000_000)?; let version = parent_version; @@ -115,13 +117,7 @@ impl Vecs { db, }; - this.db.retain_regions( - this.iter_any_exportable() - .flat_map(|v| v.region_names()) - .collect(), - )?; - this.db.compact()?; - + finalize_db(&this.db, &this)?; Ok(this) } @@ -148,7 +144,39 @@ impl Vecs { starting_indexes: Indexes, exit: &Exit, ) -> Result { - // Transaction indexes - compute input/output counts + self.compute_tx_indexes(indexer, &starting_indexes, exit)?; + self.compute_height_indexes(indexer, &starting_indexes, exit)?; + + let prev_height = starting_indexes.height.decremented().unwrap_or_default(); + + self.compute_timestamp_mappings(blocks_time, &starting_indexes, exit)?; + + let starting_day1 = self.compute_calendar_mappings( + indexer, + blocks_time, + &starting_indexes, + prev_height, + exit, + )?; + + self.compute_period_vecs( + indexer, + blocks_time, + &starting_indexes, + prev_height, + starting_day1, + exit, + )?; + + Ok(starting_indexes) + } + + fn compute_tx_indexes( + &mut self, + indexer: &Indexer, + starting_indexes: &Indexes, + exit: &Exit, + ) -> Result<()> { self.txindex.input_count.compute_count_from_indexes( starting_indexes.txindex, &indexer.vecs.transactions.first_txinindex, @@ -161,80 +189,68 @@ impl Vecs { &indexer.vecs.outputs.value, exit, )?; + Ok(()) + } - // Height indexes + fn compute_height_indexes( + &mut self, + indexer: &Indexer, + starting_indexes: &Indexes, + exit: &Exit, + ) -> Result<()> { self.height.txindex_count.compute_count_from_indexes( starting_indexes.height, &indexer.vecs.transactions.first_txindex, &indexer.vecs.transactions.txid, exit, )?; - self.height.identity.compute_from_index( starting_indexes.height, &indexer.vecs.blocks.weight, exit, )?; + Ok(()) + } - let decremented_starting_height = starting_indexes.height.decremented().unwrap_or_default(); + fn compute_timestamp_mappings( + &mut self, + blocks_time: &blocks::time::Vecs, + starting_indexes: &Indexes, + exit: &Exit, + ) -> Result<()> { + macro_rules! from_timestamp { + ($field:ident, $period:ty) => { + self.height.$field.compute_transform( + starting_indexes.height, + &blocks_time.timestamp_monotonic, + |(h, ts, _)| (h, <$period>::from_timestamp(ts)), + exit, + )?; + }; + } - // --- Timestamp-based height → period mappings --- + from_timestamp!(minute10, Minute10); + from_timestamp!(minute30, Minute30); + from_timestamp!(hour1, Hour1); + from_timestamp!(hour4, Hour4); + from_timestamp!(hour12, Hour12); + from_timestamp!(day3, Day3); - // Minute10 - self.height.minute10.compute_transform( - starting_indexes.height, - &blocks_time.timestamp_monotonic, - |(h, ts, _)| (h, Minute10::from_timestamp(ts)), - exit, - )?; + Ok(()) + } - // Minute30 - self.height.minute30.compute_transform( - starting_indexes.height, - &blocks_time.timestamp_monotonic, - |(h, ts, _)| (h, Minute30::from_timestamp(ts)), - exit, - )?; - - // Hour1 - self.height.hour1.compute_transform( - starting_indexes.height, - &blocks_time.timestamp_monotonic, - |(h, ts, _)| (h, Hour1::from_timestamp(ts)), - exit, - )?; - - // Hour4 - self.height.hour4.compute_transform( - starting_indexes.height, - &blocks_time.timestamp_monotonic, - |(h, ts, _)| (h, Hour4::from_timestamp(ts)), - exit, - )?; - - // Hour12 - self.height.hour12.compute_transform( - starting_indexes.height, - &blocks_time.timestamp_monotonic, - |(h, ts, _)| (h, Hour12::from_timestamp(ts)), - exit, - )?; - - // Day3 - self.height.day3.compute_transform( - starting_indexes.height, - &blocks_time.timestamp_monotonic, - |(h, ts, _)| (h, Day3::from_timestamp(ts)), - exit, - )?; - - // --- Calendar-based height → period mappings --- - - // Day1 (uses blocks_time.date computed in blocks::time::compute_early) + fn compute_calendar_mappings( + &mut self, + indexer: &Indexer, + blocks_time: &blocks::time::Vecs, + starting_indexes: &Indexes, + prev_height: Height, + exit: &Exit, + ) -> Result { let starting_day1 = self .height .day1 - .collect_one(decremented_starting_height) + .collect_one(prev_height) .unwrap_or_default(); self.height.day1.compute_transform( @@ -244,73 +260,14 @@ impl Vecs { exit, )?; - let starting_day1 = - if let Some(day1) = self.height.day1.collect_one(decremented_starting_height) { - starting_day1.min(day1) - } else { - starting_day1 - }; + let starting_day1 = if let Some(day1) = self.height.day1.collect_one(prev_height) { + starting_day1.min(day1) + } else { + starting_day1 + }; - // Difficulty epoch - let starting_difficultyepoch = self - .height - .difficultyepoch - .collect_one(decremented_starting_height) - .unwrap_or_default(); + self.compute_epoch(indexer, blocks_time, starting_indexes, prev_height, exit)?; - self.height.difficultyepoch.compute_from_index( - starting_indexes.height, - &indexer.vecs.blocks.weight, - exit, - )?; - - self.difficultyepoch.first_height.compute_first_per_index( - starting_indexes.height, - &self.height.difficultyepoch, - exit, - )?; - - self.difficultyepoch.identity.compute_from_index( - starting_difficultyepoch, - &self.difficultyepoch.first_height, - exit, - )?; - - self.difficultyepoch - .height_count - .compute_count_from_indexes( - starting_difficultyepoch, - &self.difficultyepoch.first_height, - &blocks_time.date, - exit, - )?; - - // Halving epoch - let starting_halvingepoch = self - .height - .halvingepoch - .collect_one(decremented_starting_height) - .unwrap_or_default(); - - self.height.halvingepoch.compute_from_index( - starting_indexes.height, - &indexer.vecs.blocks.weight, - exit, - )?; - - self.halvingepoch.first_height.compute_first_per_index( - starting_indexes.height, - &self.height.halvingepoch, - exit, - )?; - - self.halvingepoch.identity.compute_from_index( - starting_halvingepoch, - &self.halvingepoch.first_height, - exit, - )?; - - // Height → period mappings (calendar-based, derived from height.day1) self.height.week1.compute_transform( starting_indexes.height, &self.height.day1, @@ -348,81 +305,114 @@ impl Vecs { exit, )?; - // --- Compute period-level vecs (first_height + identity) --- + Ok(starting_day1) + } - let prev_height = decremented_starting_height; + fn compute_epoch( + &mut self, + indexer: &Indexer, + blocks_time: &blocks::time::Vecs, + starting_indexes: &Indexes, + prev_height: Height, + exit: &Exit, + ) -> Result<()> { + let starting_difficultyepoch = self + .height + .difficultyepoch + .collect_one(prev_height) + .unwrap_or_default(); - // Minute10 - self.minute10.first_height.compute_first_per_index( + self.height.difficultyepoch.compute_from_index( starting_indexes.height, - &self.height.minute10, + &indexer.vecs.blocks.weight, exit, )?; - self.minute10.identity.compute_from_index( - self.height.minute10.collect_one(prev_height).unwrap_or_default(), - &self.minute10.first_height, - exit, - )?; - - // Minute30 - self.minute30.first_height.compute_first_per_index( + self.difficultyepoch.first_height.compute_first_per_index( starting_indexes.height, - &self.height.minute30, + &self.height.difficultyepoch, exit, )?; - self.minute30.identity.compute_from_index( - self.height.minute30.collect_one(prev_height).unwrap_or_default(), - &self.minute30.first_height, + self.difficultyepoch.identity.compute_from_index( + starting_difficultyepoch, + &self.difficultyepoch.first_height, exit, )?; + self.difficultyepoch + .height_count + .compute_count_from_indexes( + starting_difficultyepoch, + &self.difficultyepoch.first_height, + &blocks_time.date, + exit, + )?; - // Hour1 - self.hour1.first_height.compute_first_per_index( + let starting_halvingepoch = self + .height + .halvingepoch + .collect_one(prev_height) + .unwrap_or_default(); + + self.height.halvingepoch.compute_from_index( starting_indexes.height, - &self.height.hour1, + &indexer.vecs.blocks.weight, exit, )?; - self.hour1.identity.compute_from_index( - self.height.hour1.collect_one(prev_height).unwrap_or_default(), - &self.hour1.first_height, - exit, - )?; - - // Hour4 - self.hour4.first_height.compute_first_per_index( + self.halvingepoch.first_height.compute_first_per_index( starting_indexes.height, - &self.height.hour4, + &self.height.halvingepoch, exit, )?; - self.hour4.identity.compute_from_index( - self.height.hour4.collect_one(prev_height).unwrap_or_default(), - &self.hour4.first_height, + self.halvingepoch.identity.compute_from_index( + starting_halvingepoch, + &self.halvingepoch.first_height, exit, )?; - // Hour12 - self.hour12.first_height.compute_first_per_index( - starting_indexes.height, - &self.height.hour12, - exit, - )?; - self.hour12.identity.compute_from_index( - self.height.hour12.collect_one(prev_height).unwrap_or_default(), - &self.hour12.first_height, - exit, - )?; + Ok(()) + } + + fn compute_period_vecs( + &mut self, + indexer: &Indexer, + blocks_time: &blocks::time::Vecs, + starting_indexes: &Indexes, + prev_height: Height, + starting_day1: Day1, + exit: &Exit, + ) -> Result<()> { + macro_rules! basic_period { + ($period:ident) => { + self.$period.first_height.compute_first_per_index( + starting_indexes.height, + &self.height.$period, + exit, + )?; + self.$period.identity.compute_from_index( + self.height + .$period + .collect_one(prev_height) + .unwrap_or_default(), + &self.$period.first_height, + exit, + )?; + }; + } + + basic_period!(minute10); + basic_period!(minute30); + basic_period!(hour1); + basic_period!(hour4); + basic_period!(hour12); + basic_period!(day3); - // Day1 self.day1.first_height.compute_first_per_index( starting_indexes.height, &self.height.day1, exit, )?; - self.day1.identity.compute_from_index( - starting_day1, - &self.day1.first_height, - exit, - )?; + self.day1 + .identity + .compute_from_index(starting_day1, &self.day1.first_height, exit)?; self.day1.date.compute_transform( starting_day1, &self.day1.identity, @@ -436,134 +426,41 @@ impl Vecs { exit, )?; - // Day3 - self.day3.first_height.compute_first_per_index( - starting_indexes.height, - &self.height.day3, - exit, - )?; - self.day3.identity.compute_from_index( - self.height.day3.collect_one(prev_height).unwrap_or_default(), - &self.day3.first_height, - exit, - )?; + let date = &blocks_time.date; - let blocks_time_date = &blocks_time.date; + macro_rules! dated_period { + ($period:ident) => {{ + self.$period.first_height.compute_first_per_index( + starting_indexes.height, + &self.height.$period, + exit, + )?; + let start = self + .height + .$period + .collect_one(prev_height) + .unwrap_or_default(); + self.$period.identity.compute_from_index( + start, + &self.$period.first_height, + exit, + )?; + self.$period.date.compute_transform( + start, + &self.$period.first_height, + |(idx, first_h, _)| (idx, date.collect_one(first_h).unwrap()), + exit, + )?; + }}; + } - // Week - self.week1.first_height.compute_first_per_index( - starting_indexes.height, - &self.height.week1, - exit, - )?; - let starting_week1 = self.height.week1.collect_one(prev_height).unwrap_or_default(); - self.week1.identity.compute_from_index( - starting_week1, - &self.week1.first_height, - exit, - )?; - self.week1.date.compute_transform( - starting_week1, - &self.week1.first_height, - |(wi, first_h, _)| (wi, blocks_time_date.collect_one(first_h).unwrap()), - exit, - )?; + dated_period!(week1); + dated_period!(month1); + dated_period!(month3); + dated_period!(month6); + dated_period!(year1); + dated_period!(year10); - // Month - self.month1.first_height.compute_first_per_index( - starting_indexes.height, - &self.height.month1, - exit, - )?; - let starting_month1 = self.height.month1.collect_one(prev_height).unwrap_or_default(); - self.month1.identity.compute_from_index( - starting_month1, - &self.month1.first_height, - exit, - )?; - self.month1.date.compute_transform( - starting_month1, - &self.month1.first_height, - |(mi, first_h, _)| (mi, blocks_time_date.collect_one(first_h).unwrap()), - exit, - )?; - - // Quarter - self.month3.first_height.compute_first_per_index( - starting_indexes.height, - &self.height.month3, - exit, - )?; - let starting_month3 = self.height.month3.collect_one(prev_height).unwrap_or_default(); - self.month3.identity.compute_from_index( - starting_month3, - &self.month3.first_height, - exit, - )?; - self.month3.date.compute_transform( - starting_month3, - &self.month3.first_height, - |(qi, first_h, _)| (qi, blocks_time_date.collect_one(first_h).unwrap()), - exit, - )?; - - // Semester - self.month6.first_height.compute_first_per_index( - starting_indexes.height, - &self.height.month6, - exit, - )?; - let starting_month6 = self.height.month6.collect_one(prev_height).unwrap_or_default(); - self.month6.identity.compute_from_index( - starting_month6, - &self.month6.first_height, - exit, - )?; - self.month6.date.compute_transform( - starting_month6, - &self.month6.first_height, - |(si, first_h, _)| (si, blocks_time_date.collect_one(first_h).unwrap()), - exit, - )?; - - // Year - self.year1.first_height.compute_first_per_index( - starting_indexes.height, - &self.height.year1, - exit, - )?; - let starting_year1 = self.height.year1.collect_one(prev_height).unwrap_or_default(); - self.year1.identity.compute_from_index( - starting_year1, - &self.year1.first_height, - exit, - )?; - self.year1.date.compute_transform( - starting_year1, - &self.year1.first_height, - |(yi, first_h, _)| (yi, blocks_time_date.collect_one(first_h).unwrap()), - exit, - )?; - - // Decade - self.year10.first_height.compute_first_per_index( - starting_indexes.height, - &self.height.year10, - exit, - )?; - let starting_year10 = self.height.year10.collect_one(prev_height).unwrap_or_default(); - self.year10.identity.compute_from_index( - starting_year10, - &self.year10.first_height, - exit, - )?; - self.year10.date.compute_transform( - starting_year10, - &self.year10.first_height, - |(di, first_h, _)| (di, blocks_time_date.collect_one(first_h).unwrap()), - exit, - )?; - - Ok(starting_indexes) + Ok(()) } } diff --git a/crates/brk_computer/src/indexes/txindex.rs b/crates/brk_computer/src/indexes/txindex.rs index e97ddcd7e..be9253516 100644 --- a/crates/brk_computer/src/indexes/txindex.rs +++ b/crates/brk_computer/src/indexes/txindex.rs @@ -1,7 +1,9 @@ use brk_indexer::Indexer; use brk_traversable::Traversable; use brk_types::{StoredU64, TxIndex, Txid, Version}; -use vecdb::{Database, EagerVec, ImportableVec, ReadableCloneableVec, LazyVecFrom1, PcoVec, Rw, StorageMode}; +use vecdb::{ + Database, EagerVec, ImportableVec, LazyVecFrom1, PcoVec, ReadableCloneableVec, Rw, StorageMode, +}; use brk_error::Result; @@ -13,7 +15,11 @@ pub struct Vecs { } impl Vecs { - pub(crate) fn forced_import(db: &Database, version: Version, indexer: &Indexer) -> Result { + pub(crate) fn forced_import( + db: &Database, + version: Version, + indexer: &Indexer, + ) -> Result { Ok(Self { identity: LazyVecFrom1::init( "txindex", diff --git a/crates/brk_computer/src/indexes/txinindex.rs b/crates/brk_computer/src/indexes/txinindex.rs index eb12aa71f..dd5c9528b 100644 --- a/crates/brk_computer/src/indexes/txinindex.rs +++ b/crates/brk_computer/src/indexes/txinindex.rs @@ -1,7 +1,7 @@ use brk_indexer::Indexer; use brk_traversable::Traversable; use brk_types::{OutPoint, TxInIndex, Version}; -use vecdb::{ReadableCloneableVec, LazyVecFrom1}; +use vecdb::{LazyVecFrom1, ReadableCloneableVec}; #[derive(Clone, Traversable)] pub struct Vecs { diff --git a/crates/brk_computer/src/indexes/txoutindex.rs b/crates/brk_computer/src/indexes/txoutindex.rs index b9b5ca1b8..59a24dcfd 100644 --- a/crates/brk_computer/src/indexes/txoutindex.rs +++ b/crates/brk_computer/src/indexes/txoutindex.rs @@ -1,7 +1,7 @@ use brk_indexer::Indexer; use brk_traversable::Traversable; use brk_types::{Sats, TxOutIndex, Version}; -use vecdb::{ReadableCloneableVec, LazyVecFrom1}; +use vecdb::{LazyVecFrom1, ReadableCloneableVec}; #[derive(Clone, Traversable)] pub struct Vecs { diff --git a/crates/brk_computer/src/indexes/year10.rs b/crates/brk_computer/src/indexes/year10.rs index 5d38b5758..6629cdc56 100644 --- a/crates/brk_computer/src/indexes/year10.rs +++ b/crates/brk_computer/src/indexes/year10.rs @@ -1,5 +1,5 @@ use brk_traversable::Traversable; -use brk_types::{Date, Year10, Height, Version}; +use brk_types::{Date, Height, Version, Year10}; use vecdb::{Database, EagerVec, ImportableVec, PcoVec, Rw, StorageMode}; use brk_error::Result; diff --git a/crates/brk_computer/src/inputs/count/compute.rs b/crates/brk_computer/src/inputs/count/compute.rs index dbbd01c39..52f6bdfe3 100644 --- a/crates/brk_computer/src/inputs/count/compute.rs +++ b/crates/brk_computer/src/inputs/count/compute.rs @@ -16,11 +16,8 @@ impl Vecs { exit: &Exit, ) -> Result<()> { let window_starts = blocks.count.window_starts(); - self.0.compute( - starting_indexes.height, - &window_starts, - exit, - |full| { + self.0 + .compute(starting_indexes.height, &window_starts, exit, |full| { full.compute_with_skip( starting_indexes.height, &indexes.txindex.input_count, @@ -29,8 +26,7 @@ impl Vecs { exit, 0, ) - }, - )?; + })?; Ok(()) } diff --git a/crates/brk_computer/src/inputs/import.rs b/crates/brk_computer/src/inputs/import.rs index 4304ab7a1..39742f882 100644 --- a/crates/brk_computer/src/inputs/import.rs +++ b/crates/brk_computer/src/inputs/import.rs @@ -1,12 +1,14 @@ use std::path::Path; use brk_error::Result; -use brk_traversable::Traversable; use brk_types::Version; -use vecdb::{Database, PAGE_SIZE}; + +use crate::{ + indexes, + internal::{finalize_db, open_db}, +}; use super::{CountVecs, SpentVecs, Vecs}; -use crate::indexes; impl Vecs { pub(crate) fn forced_import( @@ -14,23 +16,14 @@ impl Vecs { parent_version: Version, indexes: &indexes::Vecs, ) -> Result { - let db = Database::open(&parent_path.join(super::DB_NAME))?; - db.set_min_len(PAGE_SIZE * 50_000_000)?; - + let db = open_db(parent_path, super::DB_NAME, 50_000_000)?; let version = parent_version; let spent = SpentVecs::forced_import(&db, version)?; let count = CountVecs::forced_import(&db, version, indexes)?; let this = Self { db, spent, count }; - - this.db.retain_regions( - this.iter_any_exportable() - .flat_map(|v| v.region_names()) - .collect(), - )?; - this.db.compact()?; - + finalize_db(&this.db, &this)?; Ok(this) } } diff --git a/crates/brk_computer/src/inputs/spent/compute.rs b/crates/brk_computer/src/inputs/spent/compute.rs index 0f6ee520a..8890e6d74 100644 --- a/crates/brk_computer/src/inputs/spent/compute.rs +++ b/crates/brk_computer/src/inputs/spent/compute.rs @@ -2,7 +2,7 @@ use brk_error::Result; use brk_indexer::Indexer; use brk_types::{Indexes, Sats, TxInIndex, TxIndex, TxOutIndex, Vout}; use tracing::info; -use vecdb::{AnyStoredVec, AnyVec, Database, Exit, WritableVec, ReadableVec, VecIndex}; +use vecdb::{AnyStoredVec, AnyVec, Database, Exit, ReadableVec, VecIndex, WritableVec}; use super::Vecs; @@ -41,7 +41,7 @@ impl Vecs { let first_txoutindex_reader = indexer.vecs.transactions.first_txoutindex.reader(); let value_reader = indexer.vecs.outputs.value.reader(); let actual_total = target - min; - let mut entries: Vec = Vec::with_capacity(actual_total.min(BATCH_SIZE)); + let mut entries: Vec = Vec::with_capacity(actual_total.min(BATCH_SIZE)); let mut batch_start = min; while batch_start < target { @@ -49,16 +49,20 @@ impl Vecs { entries.clear(); let mut j = 0usize; - indexer.vecs.inputs.outpoint.for_each_range_at(batch_start, batch_end, |outpoint| { - entries.push(Entry { - txinindex: TxInIndex::from(batch_start + j), - txindex: outpoint.txindex(), - vout: outpoint.vout(), - txoutindex: TxOutIndex::COINBASE, - value: Sats::MAX, + indexer + .vecs + .inputs + .outpoint + .for_each_range_at(batch_start, batch_end, |outpoint| { + entries.push(Entry { + txinindex: TxInIndex::from(batch_start + j), + txindex: outpoint.txindex(), + vout: outpoint.vout(), + txoutindex: TxOutIndex::COINBASE, + value: Sats::MAX, + }); + j += 1; }); - j += 1; - }); // Coinbase entries (txindex MAX) sorted to end entries.sort_unstable_by_key(|e| e.txindex); @@ -66,7 +70,8 @@ impl Vecs { if entry.txindex.is_coinbase() { break; } - entry.txoutindex = first_txoutindex_reader.get(entry.txindex.to_usize()) + entry.vout; + entry.txoutindex = + first_txoutindex_reader.get(entry.txindex.to_usize()) + entry.vout; } entries.sort_unstable_by_key(|e| e.txoutindex); diff --git a/crates/brk_computer/src/internal/algo/aggregation.rs b/crates/brk_computer/src/internal/algo/aggregation.rs index 3f0a73e52..5ba0beb6b 100644 --- a/crates/brk_computer/src/internal/algo/aggregation.rs +++ b/crates/brk_computer/src/internal/algo/aggregation.rs @@ -1,21 +1,14 @@ -//! Compute functions for aggregation - take optional vecs, compute what's needed. -//! -//! These functions replace the Option-based compute logic in flexible builders. -//! Each function takes optional mutable references and computes only for Some() vecs. - use brk_error::Result; use brk_types::{CheckedSub, StoredU64}; use schemars::JsonSchema; use vecdb::{ - AnyStoredVec, AnyVec, EagerVec, Exit, WritableVec, ReadableVec, PcoVec, VecIndex, - VecValue, + AnyStoredVec, AnyVec, EagerVec, Exit, PcoVec, ReadableVec, VecIndex, VecValue, WritableVec, }; use brk_types::get_percentile; use crate::internal::ComputedVecValue; -/// Helper to validate and get starting index for a single vec fn validate_and_start( vec: &mut EagerVec>, combined_version: vecdb::Version, @@ -25,14 +18,6 @@ fn validate_and_start( Ok(current_start.min(I::from(vec.len()))) } -/// Compute aggregations from a source vec into target vecs. -/// -/// This function computes all requested aggregations in a single pass when possible, -/// optimizing for the common case where multiple aggregations are needed. -/// -/// The `skip_count` parameter allows skipping the first N items from ALL calculations. -/// This is useful for excluding coinbase transactions (which have 0 fee) from -/// fee/feerate aggregations. #[allow(clippy::too_many_arguments)] pub(crate) fn compute_aggregations( max_from: I, @@ -97,7 +82,9 @@ where let mut cumulative_val = cumulative.as_ref().map(|cumulative_vec| { index.decremented().map_or(T::from(0_usize), |idx| { - cumulative_vec.collect_one_at(idx.to_usize()).unwrap_or(T::from(0_usize)) + cumulative_vec + .collect_one_at(idx.to_usize()) + .unwrap_or(T::from(0_usize)) }) }); @@ -106,7 +93,11 @@ where let first_indexes_batch: Vec = first_indexes.collect_range_at(start, fi_len); let count_indexes_batch: Vec = count_indexes.collect_range_at(start, fi_len); - first_indexes_batch.into_iter().zip(count_indexes_batch).enumerate().try_for_each(|(j, (first_index, count_index))| -> Result<()> { + first_indexes_batch + .into_iter() + .zip(count_indexes_batch) + .enumerate() + .try_for_each(|(j, (first_index, count_index))| -> Result<()> { let idx = start + j; let count = u64::from(count_index) as usize; @@ -116,7 +107,9 @@ where if let Some(ref mut first_vec) = first { let f = if effective_count > 0 { - source.collect_one_at(effective_first_index.to_usize()).unwrap() + source + .collect_one_at(effective_first_index.to_usize()) + .unwrap() } else { T::from(0_usize) }; @@ -259,10 +252,19 @@ where } else if needs_aggregates { // Aggregates only (sum/average/cumulative) — no Vec allocation needed let efi = effective_first_index.to_usize(); - let (sum_val, len) = source.fold_range_at(efi, efi + effective_count, (T::from(0_usize), 0_usize), |(acc, cnt), val| (acc + val, cnt + 1)); + let (sum_val, len) = source.fold_range_at( + efi, + efi + effective_count, + (T::from(0_usize), 0_usize), + |(acc, cnt), val| (acc + val, cnt + 1), + ); if let Some(ref mut average_vec) = average { - let avg = if len > 0 { sum_val / len } else { T::from(0_usize) }; + let avg = if len > 0 { + sum_val / len + } else { + T::from(0_usize) + }; average_vec.truncate_push_at(idx, avg)?; } @@ -296,10 +298,6 @@ where Ok(()) } -/// Compute distribution stats from a fixed n-block rolling window. -/// -/// For each height `h`, aggregates all source items from blocks `max(0, h - n_blocks + 1)..=h` -/// and computes average, min, max, median, and percentiles across the full window. #[allow(clippy::too_many_arguments)] pub(crate) fn compute_aggregations_nblock_window( max_from: I, @@ -322,11 +320,19 @@ where T: ComputedVecValue + JsonSchema, A: VecIndex + VecValue + CheckedSub, { - let combined_version = - source.version() + first_indexes.version() + count_indexes.version(); + let combined_version = source.version() + first_indexes.version() + count_indexes.version(); let mut idx = max_from; - for vec in [&mut *min, &mut *max, &mut *average, &mut *median, &mut *pct10, &mut *pct25, &mut *pct75, &mut *pct90] { + for vec in [ + &mut *min, + &mut *max, + &mut *average, + &mut *median, + &mut *pct10, + &mut *pct25, + &mut *pct75, + &mut *pct90, + ] { idx = validate_and_start(vec, combined_version, idx)?; } let index = idx; @@ -362,7 +368,16 @@ where let effective_count = range_end_usize.saturating_sub(range_start_usize); if effective_count == 0 { - for vec in [&mut *min, &mut *max, &mut *average, &mut *median, &mut *pct10, &mut *pct25, &mut *pct75, &mut *pct90] { + for vec in [ + &mut *min, + &mut *max, + &mut *average, + &mut *median, + &mut *pct10, + &mut *pct25, + &mut *pct75, + &mut *pct90, + ] { vec.truncate_push_at(idx, zero)?; } } else { diff --git a/crates/brk_computer/src/internal/algo/drawdown.rs b/crates/brk_computer/src/internal/algo/drawdown.rs new file mode 100644 index 000000000..acdbd0539 --- /dev/null +++ b/crates/brk_computer/src/internal/algo/drawdown.rs @@ -0,0 +1,52 @@ +use brk_error::Result; +use brk_types::BasisPointsSigned16; +use vecdb::{EagerVec, Exit, PcoVec, ReadableVec, VecIndex, VecValue}; + +pub trait ComputeDrawdown { + fn compute_drawdown( + &mut self, + max_from: I, + current: &impl ReadableVec, + ath: &impl ReadableVec, + exit: &Exit, + ) -> Result<()> + where + C: VecValue, + A: VecValue, + f64: From + From; +} + +impl ComputeDrawdown for EagerVec> +where + I: VecIndex, +{ + fn compute_drawdown( + &mut self, + max_from: I, + current: &impl ReadableVec, + ath: &impl ReadableVec, + exit: &Exit, + ) -> Result<()> + where + C: VecValue, + A: VecValue, + f64: From + From, + { + self.compute_transform2( + max_from, + current, + ath, + |(i, current, ath, _)| { + let ath_f64 = f64::from(ath); + let drawdown = if ath_f64 == 0.0 { + BasisPointsSigned16::default() + } else { + BasisPointsSigned16::from((f64::from(current) - ath_f64) / ath_f64) + }; + (i, drawdown) + }, + exit, + )?; + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/algo/mod.rs b/crates/brk_computer/src/internal/algo/mod.rs index b266401b2..ca26e31dd 100644 --- a/crates/brk_computer/src/internal/algo/mod.rs +++ b/crates/brk_computer/src/internal/algo/mod.rs @@ -1,6 +1,12 @@ mod aggregation; +mod drawdown; +mod sliding_distribution; +mod sliding_median; pub(crate) mod sliding_window; mod tdigest; pub(crate) use aggregation::*; +pub(crate) use drawdown::*; +pub(crate) use sliding_distribution::*; +pub(crate) use sliding_median::*; pub(crate) use tdigest::*; diff --git a/crates/brk_computer/src/internal/algo/sliding_distribution.rs b/crates/brk_computer/src/internal/algo/sliding_distribution.rs new file mode 100644 index 000000000..62a41bc0e --- /dev/null +++ b/crates/brk_computer/src/internal/algo/sliding_distribution.rs @@ -0,0 +1,158 @@ +use brk_error::Result; +use vecdb::{ + AnyStoredVec, AnyVec, EagerVec, Exit, PcoVec, PcoVecValue, ReadableVec, VecIndex, VecValue, + WritableVec, +}; + +use super::sliding_window::SlidingWindowSorted; + +/// Compute all 8 rolling distribution stats (avg, min, max, p10, p25, median, p75, p90) +/// in a single sorted-vec pass per window. +#[allow(clippy::too_many_arguments)] +pub fn compute_rolling_distribution_from_starts( + max_from: I, + window_starts: &impl ReadableVec, + values: &impl ReadableVec, + average_out: &mut EagerVec>, + min_out: &mut EagerVec>, + max_out: &mut EagerVec>, + p10_out: &mut EagerVec>, + p25_out: &mut EagerVec>, + median_out: &mut EagerVec>, + p75_out: &mut EagerVec>, + p90_out: &mut EagerVec>, + exit: &Exit, +) -> Result<()> +where + I: VecIndex, + T: PcoVecValue + From, + A: VecValue + Copy, + f64: From, +{ + let version = window_starts.version() + values.version(); + + for v in [ + &mut *average_out, + &mut *min_out, + &mut *max_out, + &mut *p10_out, + &mut *p25_out, + &mut *median_out, + &mut *p75_out, + &mut *p90_out, + ] { + v.validate_and_truncate(version, max_from)?; + } + + let skip = [ + average_out.len(), + min_out.len(), + max_out.len(), + p10_out.len(), + p25_out.len(), + median_out.len(), + p75_out.len(), + p90_out.len(), + ] + .into_iter() + .min() + .unwrap(); + + let end = window_starts.len().min(values.len()); + if skip >= end { + return Ok(()); + } + + let range_start = if skip > 0 { + window_starts.collect_one_at(skip - 1).unwrap().to_usize() + } else { + 0 + }; + let partial_values: Vec = values + .collect_range_at(range_start, end) + .into_iter() + .map(|a| f64::from(a)) + .collect(); + + let capacity = if skip > 0 && skip < end { + let first_start = window_starts.collect_one_at(skip).unwrap().to_usize(); + (skip + 1).saturating_sub(first_start) + } else if !partial_values.is_empty() { + partial_values.len().min(1024) + } else { + 0 + }; + + let mut window = SlidingWindowSorted::with_capacity(capacity); + + if skip > 0 { + window.reconstruct(&partial_values, range_start, skip); + } + + let starts_batch = window_starts.collect_range_at(skip, end); + + for (j, start) in starts_batch.into_iter().enumerate() { + let i = skip + j; + let v = partial_values[i - range_start]; + let start_usize = start.to_usize(); + window.advance(v, start_usize, &partial_values, range_start); + + if window.is_empty() { + let zero = T::from(0.0); + for v in [ + &mut *average_out, + &mut *min_out, + &mut *max_out, + &mut *p10_out, + &mut *p25_out, + &mut *median_out, + &mut *p75_out, + &mut *p90_out, + ] { + v.checked_push_at(i, zero)?; + } + } else { + average_out.checked_push_at(i, T::from(window.average()))?; + min_out.checked_push_at(i, T::from(window.min()))?; + max_out.checked_push_at(i, T::from(window.max()))?; + p10_out.checked_push_at(i, T::from(window.percentile(0.10)))?; + p25_out.checked_push_at(i, T::from(window.percentile(0.25)))?; + median_out.checked_push_at(i, T::from(window.percentile(0.50)))?; + p75_out.checked_push_at(i, T::from(window.percentile(0.75)))?; + p90_out.checked_push_at(i, T::from(window.percentile(0.90)))?; + } + + if average_out.batch_limit_reached() { + let _lock = exit.lock(); + for v in [ + &mut *average_out, + &mut *min_out, + &mut *max_out, + &mut *p10_out, + &mut *p25_out, + &mut *median_out, + &mut *p75_out, + &mut *p90_out, + ] { + v.write()?; + } + } + } + + // Final flush + let _lock = exit.lock(); + for v in [ + average_out, + min_out, + max_out, + p10_out, + p25_out, + median_out, + p75_out, + p90_out, + ] { + v.write()?; + } + + Ok(()) +} diff --git a/crates/brk_computer/src/internal/algo/sliding_median.rs b/crates/brk_computer/src/internal/algo/sliding_median.rs new file mode 100644 index 000000000..3be0282e6 --- /dev/null +++ b/crates/brk_computer/src/internal/algo/sliding_median.rs @@ -0,0 +1,90 @@ +use brk_error::Result; +use vecdb::{ + AnyVec, EagerVec, Exit, PcoVec, PcoVecValue, ReadableVec, VecIndex, VecValue, WritableVec, +}; + +use super::sliding_window::SlidingWindowSorted; + +pub trait ComputeRollingMedianFromStarts { + fn compute_rolling_median_from_starts( + &mut self, + max_from: I, + window_starts: &impl ReadableVec, + values: &impl ReadableVec, + exit: &Exit, + ) -> Result<()> + where + A: VecValue + Copy, + f64: From; +} + +impl ComputeRollingMedianFromStarts for EagerVec> +where + I: VecIndex, + T: PcoVecValue + From, +{ + fn compute_rolling_median_from_starts( + &mut self, + max_from: I, + window_starts: &impl ReadableVec, + values: &impl ReadableVec, + exit: &Exit, + ) -> Result<()> + where + A: VecValue + Copy, + f64: From, + { + self.validate_and_truncate(window_starts.version() + values.version(), max_from)?; + + self.repeat_until_complete(exit, |this| { + let skip = this.len(); + let end = window_starts.len().min(values.len()); + + let range_start = if skip > 0 { + window_starts.collect_one_at(skip - 1).unwrap().to_usize() + } else { + 0 + }; + let partial_values: Vec = values + .collect_range_at(range_start, end) + .into_iter() + .map(|a| f64::from(a)) + .collect(); + + let capacity = if skip > 0 && skip < end { + let first_start = window_starts.collect_one_at(skip).unwrap().to_usize(); + (skip + 1).saturating_sub(first_start) + } else if !partial_values.is_empty() { + partial_values.len().min(1024) + } else { + 0 + }; + + let mut window = SlidingWindowSorted::with_capacity(capacity); + + if skip > 0 { + window.reconstruct(&partial_values, range_start, skip); + } + + let starts_batch = window_starts.collect_range_at(skip, end); + + for (j, start) in starts_batch.into_iter().enumerate() { + let i = skip + j; + let v = partial_values[i - range_start]; + let start_usize = start.to_usize(); + window.advance(v, start_usize, &partial_values, range_start); + + let median = window.percentile(0.50); + this.checked_push_at(i, T::from(median))?; + + if this.batch_limit_reached() { + break; + } + } + + Ok(()) + })?; + + Ok(()) + } +} diff --git a/crates/brk_computer/src/internal/algo/sliding_window.rs b/crates/brk_computer/src/internal/algo/sliding_window.rs index d672f9acd..c62346f8b 100644 --- a/crates/brk_computer/src/internal/algo/sliding_window.rs +++ b/crates/brk_computer/src/internal/algo/sliding_window.rs @@ -37,9 +37,11 @@ impl SortedBlocks { } // Find the block where value belongs: first block whose max >= value - let block_idx = self.blocks.iter().position(|b| { - *b.last().unwrap() >= value - }).unwrap_or(self.blocks.len() - 1); + let block_idx = self + .blocks + .iter() + .position(|b| *b.last().unwrap() >= value) + .unwrap_or(self.blocks.len() - 1); let block = &mut self.blocks[block_idx]; let pos = block.partition_point(|a| *a < value); @@ -131,7 +133,13 @@ impl SlidingWindowSorted { } /// Add a new value and remove all expired values up to `new_start`. - pub fn advance(&mut self, value: f64, new_start: usize, partial_values: &[f64], range_start: usize) { + pub fn advance( + &mut self, + value: f64, + new_start: usize, + partial_values: &[f64], + range_start: usize, + ) { self.running_sum += value; self.sorted.insert(value); @@ -159,12 +167,20 @@ impl SlidingWindowSorted { #[inline] pub fn min(&self) -> f64 { - if self.sorted.is_empty() { 0.0 } else { self.sorted.first() } + if self.sorted.is_empty() { + 0.0 + } else { + self.sorted.first() + } } #[inline] pub fn max(&self) -> f64 { - if self.sorted.is_empty() { 0.0 } else { self.sorted.last() } + if self.sorted.is_empty() { + 0.0 + } else { + self.sorted.last() + } } /// Extract a percentile (0.0-1.0) using linear interpolation. diff --git a/crates/brk_computer/src/internal/algo/tdigest.rs b/crates/brk_computer/src/internal/algo/tdigest.rs index 6d7f4e83f..38caf3fc6 100644 --- a/crates/brk_computer/src/internal/algo/tdigest.rs +++ b/crates/brk_computer/src/internal/algo/tdigest.rs @@ -67,9 +67,11 @@ impl TDigest { } // Single binary search: unclamped position doubles as insert point - let search = self - .centroids - .binary_search_by(|c| c.mean.partial_cmp(&value).unwrap_or(std::cmp::Ordering::Equal)); + let search = self.centroids.binary_search_by(|c| { + c.mean + .partial_cmp(&value) + .unwrap_or(std::cmp::Ordering::Equal) + }); let insert_pos = match search { Ok(i) | Err(i) => i, }; diff --git a/crates/brk_computer/src/internal/db_utils.rs b/crates/brk_computer/src/internal/db_utils.rs new file mode 100644 index 000000000..003c63983 --- /dev/null +++ b/crates/brk_computer/src/internal/db_utils.rs @@ -0,0 +1,26 @@ +use std::path::Path; + +use brk_error::Result; +use brk_traversable::Traversable; +use vecdb::{Database, PAGE_SIZE}; + +pub(crate) fn open_db( + parent_path: &Path, + db_name: &str, + page_multiplier: usize, +) -> Result { + let db = Database::open(&parent_path.join(db_name))?; + db.set_min_len(PAGE_SIZE * page_multiplier)?; + Ok(db) +} + +pub(crate) fn finalize_db(db: &Database, traversable: &impl Traversable) -> Result<()> { + db.retain_regions( + traversable + .iter_any_exportable() + .flat_map(|v| v.region_names()) + .collect(), + )?; + db.compact()?; + Ok(()) +} diff --git a/crates/brk_computer/src/internal/derived/last.rs b/crates/brk_computer/src/internal/derived/last.rs index 47714ba02..9ca58666a 100644 --- a/crates/brk_computer/src/internal/derived/last.rs +++ b/crates/brk_computer/src/internal/derived/last.rs @@ -1,5 +1,3 @@ -//! ComputedHeightDerived — sparse time periods + dense epochs (last value). - use brk_traversable::Traversable; use brk_types::{ Day1, Day3, DifficultyEpoch, FromCoarserIndex, HalvingEpoch, Height, Hour1, Hour4, Hour12, @@ -12,7 +10,7 @@ use vecdb::{ }; use crate::{ - indexes, indexes_from, + indexes, internal::{ComputedVecValue, NumericValue, PerPeriod}, }; @@ -41,7 +39,6 @@ pub struct ComputedHeightDerived( where T: ComputedVecValue + PartialOrd + JsonSchema; -/// Already read-only (no StorageMode); cloning is sufficient. impl ReadOnlyClone for ComputedHeightDerived where T: ComputedVecValue + PartialOrd + JsonSchema, @@ -116,6 +113,22 @@ where }; } - Self(indexes_from!(period, epoch)) + Self(PerPeriod { + minute10: period!(minute10), + minute30: period!(minute30), + hour1: period!(hour1), + hour4: period!(hour4), + hour12: period!(hour12), + day1: period!(day1), + day3: period!(day3), + week1: period!(week1), + month1: period!(month1), + month3: period!(month3), + month6: period!(month6), + year1: period!(year1), + year10: period!(year10), + halvingepoch: epoch!(halvingepoch), + difficultyepoch: epoch!(difficultyepoch), + }) } } diff --git a/crates/brk_computer/src/internal/derived/lazy_last.rs b/crates/brk_computer/src/internal/derived/lazy_last.rs index bb0b1407a..0298f8d38 100644 --- a/crates/brk_computer/src/internal/derived/lazy_last.rs +++ b/crates/brk_computer/src/internal/derived/lazy_last.rs @@ -1,59 +1,20 @@ -//! LazyHeightDerived — unary transform of height-derived last values. - -use std::marker::PhantomData; - use brk_traversable::Traversable; use brk_types::{ - Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour4, Hour12, - Minute10, Minute30, Month1, Month3, Month6, Version, Week1, Year1, Year10, + Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour4, Hour12, Minute10, Minute30, + Month1, Month3, Month6, Version, Week1, Year1, Year10, }; use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; -use vecdb::{ - LazyVecFrom1, ReadableBoxedVec, ReadableCloneableVec, UnaryTransform, VecIndex, VecValue, -}; +use vecdb::{ReadableBoxedVec, ReadableCloneableVec, UnaryTransform, VecValue}; use crate::{ - indexes, indexes_from, + indexes, internal::{ ComputedFromHeight, ComputedHeightDerived, ComputedVecValue, NumericValue, PerPeriod, }, }; -#[derive(Clone, Deref, DerefMut, Traversable)] -#[traversable(transparent)] -pub struct LazyTransformLast(pub LazyVecFrom1) -where - I: VecIndex, - T: VecValue + PartialOrd + JsonSchema, - S1T: VecValue; - -impl LazyTransformLast -where - I: VecIndex, - T: VecValue + PartialOrd + JsonSchema + 'static, - S1T: VecValue + JsonSchema, -{ - fn from_boxed>( - name: &str, - version: Version, - source: ReadableBoxedVec, - ) -> Self { - Self(LazyVecFrom1::transformed::(name, version, source)) - } -} - -struct MapOption(PhantomData); - -impl UnaryTransform, Option> for MapOption -where - F: UnaryTransform, -{ - #[inline(always)] - fn apply(value: Option) -> Option { - value.map(F::apply) - } -} +use super::{LazyTransformLast, MapOption}; #[derive(Clone, Deref, DerefMut, Traversable)] #[traversable(transparent)] @@ -106,8 +67,7 @@ where where S1T: NumericValue, { - let derived = - ComputedHeightDerived::forced_import(name, height_source, version, indexes); + let derived = ComputedHeightDerived::forced_import(name, height_source, version, indexes); Self::from_derived_computed::(name, version, &derived) } @@ -135,7 +95,23 @@ where }; } - Self(indexes_from!(period, epoch)) + Self(PerPeriod { + minute10: period!(minute10), + minute30: period!(minute30), + hour1: period!(hour1), + hour4: period!(hour4), + hour12: period!(hour12), + day1: period!(day1), + day3: period!(day3), + week1: period!(week1), + month1: period!(month1), + month3: period!(month3), + month6: period!(month6), + year1: period!(year1), + year10: period!(year10), + halvingepoch: epoch!(halvingepoch), + difficultyepoch: epoch!(difficultyepoch), + }) } pub(crate) fn from_lazy( @@ -163,6 +139,22 @@ where }; } - Self(indexes_from!(period, epoch)) + Self(PerPeriod { + minute10: period!(minute10), + minute30: period!(minute30), + hour1: period!(hour1), + hour4: period!(hour4), + hour12: period!(hour12), + day1: period!(day1), + day3: period!(day3), + week1: period!(week1), + month1: period!(month1), + month3: period!(month3), + month6: period!(month6), + year1: period!(year1), + year10: period!(year10), + halvingepoch: epoch!(halvingepoch), + difficultyepoch: epoch!(difficultyepoch), + }) } } diff --git a/crates/brk_computer/src/internal/derived/lazy_value.rs b/crates/brk_computer/src/internal/derived/lazy_value.rs index 52077359c..799b9e243 100644 --- a/crates/brk_computer/src/internal/derived/lazy_value.rs +++ b/crates/brk_computer/src/internal/derived/lazy_value.rs @@ -1,5 +1,3 @@ -//! Lazy value type for Last pattern across all height-derived indexes. - use brk_traversable::Traversable; use brk_types::{Bitcoin, Cents, Dollars, Sats, Version}; use vecdb::UnaryTransform; @@ -15,7 +13,12 @@ pub struct LazyValueHeightDerived { } impl LazyValueHeightDerived { - pub(crate) fn from_block_source( + pub(crate) fn from_block_source< + SatsTransform, + BitcoinTransform, + CentsTransform, + DollarsTransform, + >( name: &str, source: &ValueFromHeight, version: Version, @@ -50,6 +53,11 @@ impl LazyValueHeightDerived { &source.usd.rest, ); - Self { sats, btc, cents, usd } + Self { + sats, + btc, + cents, + usd, + } } } diff --git a/crates/brk_computer/src/internal/derived/map_option.rs b/crates/brk_computer/src/internal/derived/map_option.rs new file mode 100644 index 000000000..791233603 --- /dev/null +++ b/crates/brk_computer/src/internal/derived/map_option.rs @@ -0,0 +1,15 @@ +use std::marker::PhantomData; + +use vecdb::UnaryTransform; + +pub struct MapOption(PhantomData); + +impl UnaryTransform, Option> for MapOption +where + F: UnaryTransform, +{ + #[inline(always)] + fn apply(value: Option) -> Option { + value.map(F::apply) + } +} diff --git a/crates/brk_computer/src/internal/derived/mod.rs b/crates/brk_computer/src/internal/derived/mod.rs index 43637a2cb..4b08ef6d2 100644 --- a/crates/brk_computer/src/internal/derived/mod.rs +++ b/crates/brk_computer/src/internal/derived/mod.rs @@ -2,8 +2,12 @@ mod full; mod last; mod lazy_last; mod lazy_value; +mod map_option; +mod transform_last; pub use full::*; pub use last::*; pub use lazy_last::*; pub use lazy_value::*; +pub use map_option::*; +pub use transform_last::*; diff --git a/crates/brk_computer/src/internal/derived/transform_last.rs b/crates/brk_computer/src/internal/derived/transform_last.rs new file mode 100644 index 000000000..6d496cb6e --- /dev/null +++ b/crates/brk_computer/src/internal/derived/transform_last.rs @@ -0,0 +1,29 @@ +use brk_traversable::Traversable; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{LazyVecFrom1, ReadableBoxedVec, UnaryTransform, VecIndex, VecValue}; + +use brk_types::Version; + +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(transparent)] +pub struct LazyTransformLast(pub LazyVecFrom1) +where + I: VecIndex, + T: VecValue + PartialOrd + JsonSchema, + S1T: VecValue; + +impl LazyTransformLast +where + I: VecIndex, + T: VecValue + PartialOrd + JsonSchema + 'static, + S1T: VecValue + JsonSchema, +{ + pub(crate) fn from_boxed>( + name: &str, + version: Version, + source: ReadableBoxedVec, + ) -> Self { + Self(LazyVecFrom1::transformed::(name, version, source)) + } +} diff --git a/crates/brk_computer/src/internal/distribution_stats.rs b/crates/brk_computer/src/internal/distribution_stats.rs index 951c8d94b..0efde5961 100644 --- a/crates/brk_computer/src/internal/distribution_stats.rs +++ b/crates/brk_computer/src/internal/distribution_stats.rs @@ -13,7 +13,9 @@ pub struct DistributionStats { } impl DistributionStats { - pub const SUFFIXES: [&'static str; 8] = ["average", "min", "max", "p10", "p25", "median", "p75", "p90"]; + pub const SUFFIXES: [&'static str; 8] = [ + "average", "min", "max", "p10", "p25", "median", "p75", "p90", + ]; pub fn try_from_fn( mut f: impl FnMut(&str) -> std::result::Result, @@ -31,7 +33,10 @@ impl DistributionStats { } /// Apply a fallible operation to each of the 8 fields. - pub fn try_for_each_mut(&mut self, mut f: impl FnMut(&mut A) -> brk_error::Result<()>) -> brk_error::Result<()> { + pub fn try_for_each_mut( + &mut self, + mut f: impl FnMut(&mut A) -> brk_error::Result<()>, + ) -> brk_error::Result<()> { f(&mut self.average)?; f(&mut self.min)?; f(&mut self.max)?; diff --git a/crates/brk_computer/src/internal/eager_indexes.rs b/crates/brk_computer/src/internal/eager_indexes.rs index b86fa0a3f..a1e14d75f 100644 --- a/crates/brk_computer/src/internal/eager_indexes.rs +++ b/crates/brk_computer/src/internal/eager_indexes.rs @@ -1,14 +1,9 @@ -//! EagerIndexes - newtype on PerPeriod with EagerVec> per field. -//! -//! Used for data eagerly computed and stored per period during indexing, -//! such as timestamp (first value per period) and OHLC (first/min/max per period). - use brk_error::Result; use brk_traversable::Traversable; use brk_types::{ - Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour4, Hour12, - Indexes, Minute10, Minute30, Month1, Month3, Month6, Version, Week1, Year1, Year10, + Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour4, Hour12, Indexes, Minute10, + Minute30, Month1, Month3, Month6, Version, Week1, Year1, Year10, }; use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; @@ -18,7 +13,7 @@ use vecdb::{ }; use crate::{ - indexes, indexes_apply, indexes_from, + indexes, internal::{ComputedVecValue, NumericValue, PerPeriod}, }; @@ -52,16 +47,31 @@ where T: NumericValue + JsonSchema, { pub(crate) fn forced_import(db: &Database, name: &str, version: Version) -> Result { - macro_rules! period { - ($idx:ident) => { + macro_rules! per_period { + () => { ImportableVec::forced_import(db, name, version)? }; } - Ok(Self(indexes_from!(period))) + Ok(Self(PerPeriod { + minute10: per_period!(), + minute30: per_period!(), + hour1: per_period!(), + hour4: per_period!(), + hour12: per_period!(), + day1: per_period!(), + day3: per_period!(), + week1: per_period!(), + month1: per_period!(), + month3: per_period!(), + month6: per_period!(), + year1: per_period!(), + year10: per_period!(), + halvingepoch: per_period!(), + difficultyepoch: per_period!(), + })) } - /// Compute "first value per period" — for each period, looks up `source[first_height[period]]`. pub(crate) fn compute_first( &mut self, starting_indexes: &Indexes, @@ -74,7 +84,11 @@ where macro_rules! period { ($field:ident) => { self.0.$field.compute_indirect_sequential( - indexes.height.$field.collect_one(prev_height).unwrap_or_default(), + indexes + .height + .$field + .collect_one(prev_height) + .unwrap_or_default(), &indexes.$field.first_height, height_source, exit, @@ -82,12 +96,25 @@ where }; } - indexes_apply!(period); + period!(minute10); + period!(minute30); + period!(hour1); + period!(hour4); + period!(hour12); + period!(day1); + period!(day3); + period!(week1); + period!(month1); + period!(month3); + period!(month6); + period!(year1); + period!(year10); + period!(halvingepoch); + period!(difficultyepoch); Ok(()) } - /// Compute "max value per period" — for each period, finds `max(source[first_height[period]..first_height[period+1]])`. pub(crate) fn compute_max( &mut self, starting_indexes: &Indexes, @@ -102,7 +129,11 @@ where ($field:ident) => { compute_period_extremum( &mut self.0.$field, - indexes.height.$field.collect_one(prev_height).unwrap_or_default(), + indexes + .height + .$field + .collect_one(prev_height) + .unwrap_or_default(), &indexes.$field.first_height, height_source, src_len, @@ -112,12 +143,25 @@ where }; } - indexes_apply!(period); + period!(minute10); + period!(minute30); + period!(hour1); + period!(hour4); + period!(hour12); + period!(day1); + period!(day3); + period!(week1); + period!(month1); + period!(month3); + period!(month6); + period!(year1); + period!(year10); + period!(halvingepoch); + period!(difficultyepoch); Ok(()) } - /// Compute "min value per period" — for each period, finds `min(source[first_height[period]..first_height[period+1]])`. pub(crate) fn compute_min( &mut self, starting_indexes: &Indexes, @@ -132,7 +176,11 @@ where ($field:ident) => { compute_period_extremum( &mut self.0.$field, - indexes.height.$field.collect_one(prev_height).unwrap_or_default(), + indexes + .height + .$field + .collect_one(prev_height) + .unwrap_or_default(), &indexes.$field.first_height, height_source, src_len, @@ -142,16 +190,26 @@ where }; } - indexes_apply!(period); + period!(minute10); + period!(minute30); + period!(hour1); + period!(hour4); + period!(hour12); + period!(day1); + period!(day3); + period!(week1); + period!(month1); + period!(month3); + period!(month6); + period!(year1); + period!(year10); + period!(halvingepoch); + period!(difficultyepoch); Ok(()) } } -/// Compute per-period extremum (max or min) of height_source values. -/// -/// Each period's range is `[fh[i]..fh[i+1])` of height_source. -/// Uses a cursor on height_source so each page is decompressed at most once. fn compute_period_extremum( out: &mut EagerVec>, starting_index: I, diff --git a/crates/brk_computer/src/internal/from_height/aggregated.rs b/crates/brk_computer/src/internal/from_height/aggregated.rs index b87e16a51..e69b49c1a 100644 --- a/crates/brk_computer/src/internal/from_height/aggregated.rs +++ b/crates/brk_computer/src/internal/from_height/aggregated.rs @@ -58,12 +58,8 @@ where f64: From, { compute_full(&mut self.full)?; - self.rolling.compute( - max_from, - windows, - &self.full.sum, - exit, - )?; + self.rolling + .compute(max_from, windows, &self.full.sum, exit)?; Ok(()) } } diff --git a/crates/brk_computer/src/internal/from_height/base.rs b/crates/brk_computer/src/internal/from_height/base.rs index 20254fde6..f5b764c7b 100644 --- a/crates/brk_computer/src/internal/from_height/base.rs +++ b/crates/brk_computer/src/internal/from_height/base.rs @@ -1,5 +1,3 @@ -//! ComputedFromHeight using only Last aggregation. - use brk_error::Result; use brk_traversable::Traversable; @@ -66,12 +64,8 @@ where S2T: VecValue, F: BinaryTransform, { - self.height.compute_binary::( - max_from, - source1, - source2, - exit, - )?; + self.height + .compute_binary::(max_from, source1, source2, exit)?; Ok(()) } } diff --git a/crates/brk_computer/src/internal/from_height/by_unit/mod.rs b/crates/brk_computer/src/internal/from_height/by_unit/mod.rs index fc84ecf72..d1f9a23f1 100644 --- a/crates/brk_computer/src/internal/from_height/by_unit/mod.rs +++ b/crates/brk_computer/src/internal/from_height/by_unit/mod.rs @@ -40,12 +40,8 @@ impl ByUnit { &sats, ); - let cents = ComputedFromHeight::forced_import( - db, - &format!("{name}_cents"), - version, - indexes, - )?; + let cents = + ComputedFromHeight::forced_import(db, &format!("{name}_cents"), version, indexes)?; let usd = LazyFromHeight::from_computed::( &format!("{name}_usd"), diff --git a/crates/brk_computer/src/internal/from_height/by_unit/rolling_full.rs b/crates/brk_computer/src/internal/from_height/by_unit/rolling_full.rs index 3eb3e8d95..fe47822fe 100644 --- a/crates/brk_computer/src/internal/from_height/by_unit/rolling_full.rs +++ b/crates/brk_computer/src/internal/from_height/by_unit/rolling_full.rs @@ -6,8 +6,9 @@ use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode}; use crate::{ indexes, - internal::{ByUnit, DistributionStats, WindowStarts, Windows}, - traits::compute_rolling_distribution_from_starts, + internal::{ + ByUnit, DistributionStats, WindowStarts, Windows, compute_rolling_distribution_from_starts, + }, }; /// One window slot: sum + 8 distribution stats, each a ByUnit. @@ -43,19 +44,32 @@ impl RollingFullSlot { cents_source: &impl ReadableVec, exit: &Exit, ) -> Result<()> { - self.sum.sats.height.compute_rolling_sum(max_from, starts, sats_source, exit)?; - self.sum.cents.height.compute_rolling_sum(max_from, starts, cents_source, exit)?; + self.sum + .sats + .height + .compute_rolling_sum(max_from, starts, sats_source, exit)?; + self.sum + .cents + .height + .compute_rolling_sum(max_from, starts, cents_source, exit)?; let d = &mut self.distribution; macro_rules! compute_unit { ($unit:ident, $source:expr) => { compute_rolling_distribution_from_starts( - max_from, starts, $source, - &mut d.average.$unit.height, &mut d.min.$unit.height, - &mut d.max.$unit.height, &mut d.pct10.$unit.height, - &mut d.pct25.$unit.height, &mut d.median.$unit.height, - &mut d.pct75.$unit.height, &mut d.pct90.$unit.height, exit, + max_from, + starts, + $source, + &mut d.average.$unit.height, + &mut d.min.$unit.height, + &mut d.max.$unit.height, + &mut d.pct10.$unit.height, + &mut d.pct25.$unit.height, + &mut d.median.$unit.height, + &mut d.pct75.$unit.height, + &mut d.pct90.$unit.height, + exit, )? }; } diff --git a/crates/brk_computer/src/internal/from_height/by_unit/rolling_sum.rs b/crates/brk_computer/src/internal/from_height/by_unit/rolling_sum.rs index 00babf4f7..186a42b10 100644 --- a/crates/brk_computer/src/internal/from_height/by_unit/rolling_sum.rs +++ b/crates/brk_computer/src/internal/from_height/by_unit/rolling_sum.rs @@ -23,7 +23,12 @@ impl RollingSumByUnit { version: Version, indexes: &indexes::Vecs, ) -> Result { - Ok(Self(Windows::::forced_import(db, &format!("{name}_sum"), version, indexes)?)) + Ok(Self(Windows::::forced_import( + db, + &format!("{name}_sum"), + version, + indexes, + )?)) } pub(crate) fn compute_rolling_sum( @@ -35,8 +40,12 @@ impl RollingSumByUnit { exit: &Exit, ) -> Result<()> { for (w, starts) in self.0.as_mut_array().into_iter().zip(windows.as_array()) { - w.sats.height.compute_rolling_sum(max_from, *starts, sats_source, exit)?; - w.cents.height.compute_rolling_sum(max_from, *starts, cents_source, exit)?; + w.sats + .height + .compute_rolling_sum(max_from, *starts, sats_source, exit)?; + w.cents + .height + .compute_rolling_sum(max_from, *starts, cents_source, exit)?; } Ok(()) } diff --git a/crates/brk_computer/src/internal/from_height/constant.rs b/crates/brk_computer/src/internal/from_height/constant.rs index 4314a4b4b..5a95b4bc4 100644 --- a/crates/brk_computer/src/internal/from_height/constant.rs +++ b/crates/brk_computer/src/internal/from_height/constant.rs @@ -1,16 +1,14 @@ use brk_traversable::Traversable; use brk_types::{ - Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour12, Hour4, - Minute10, Minute30, Month1, Month3, Month6, Version, Week1, Year1, Year10, + Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour4, Hour12, Minute10, Minute30, + Month1, Month3, Month6, Version, Week1, Year1, Year10, }; use schemars::JsonSchema; use serde::Serialize; -use vecdb::{Formattable, ReadableCloneableVec, LazyVecFrom1, UnaryTransform, VecValue}; +use vecdb::{Formattable, LazyVecFrom1, ReadableCloneableVec, UnaryTransform, VecValue}; use crate::indexes; -/// Lazy constant vecs for all index levels. -/// Uses const generic transforms to return the same value for every index. #[derive(Clone, Traversable)] #[traversable(merge)] pub struct ConstantVecs @@ -36,7 +34,6 @@ where } impl ConstantVecs { - /// Create constant vecs using a transform that ignores input and returns a constant. pub(crate) fn new(name: &str, version: Version, indexes: &indexes::Vecs) -> Self where F: UnaryTransform @@ -57,7 +54,7 @@ impl ConstantVecs { + UnaryTransform, { macro_rules! period { - ($idx:ident, $I:ty) => { + ($idx:ident) => { LazyVecFrom1::transformed::( name, version, @@ -67,26 +64,22 @@ impl ConstantVecs { } Self { - height: LazyVecFrom1::transformed::( - name, - version, - indexes.height.identity.read_only_boxed_clone(), - ), - minute10: period!(minute10, Minute10), - minute30: period!(minute30, Minute30), - hour1: period!(hour1, Hour1), - hour4: period!(hour4, Hour4), - hour12: period!(hour12, Hour12), - day1: period!(day1, Day1), - day3: period!(day3, Day3), - week1: period!(week1, Week1), - month1: period!(month1, Month1), - month3: period!(month3, Month3), - month6: period!(month6, Month6), - year1: period!(year1, Year1), - year10: period!(year10, Year10), - halvingepoch: period!(halvingepoch, HalvingEpoch), - difficultyepoch: period!(difficultyepoch, DifficultyEpoch), + height: period!(height), + minute10: period!(minute10), + minute30: period!(minute30), + hour1: period!(hour1), + hour4: period!(hour4), + hour12: period!(hour12), + day1: period!(day1), + day3: period!(day3), + week1: period!(week1), + month1: period!(month1), + month3: period!(month3), + month6: period!(month6), + year1: period!(year1), + year10: period!(year10), + halvingepoch: period!(halvingepoch), + difficultyepoch: period!(difficultyepoch), } } } diff --git a/crates/brk_computer/src/internal/from_height/fiat.rs b/crates/brk_computer/src/internal/from_height/fiat.rs index cfbcfaa3e..a7ada88c3 100644 --- a/crates/brk_computer/src/internal/from_height/fiat.rs +++ b/crates/brk_computer/src/internal/from_height/fiat.rs @@ -38,12 +38,8 @@ impl FiatFromHeight { version: Version, indexes: &indexes::Vecs, ) -> Result { - let cents = ComputedFromHeight::forced_import( - db, - &format!("{name}_cents"), - version, - indexes, - )?; + let cents = + ComputedFromHeight::forced_import(db, &format!("{name}_cents"), version, indexes)?; let usd = LazyFromHeight::from_computed::( &format!("{name}_usd"), version, diff --git a/crates/brk_computer/src/internal/from_height/lazy.rs b/crates/brk_computer/src/internal/from_height/lazy.rs index c3f4dea3b..f2f3f341a 100644 --- a/crates/brk_computer/src/internal/from_height/lazy.rs +++ b/crates/brk_computer/src/internal/from_height/lazy.rs @@ -1,5 +1,3 @@ -//! Lazy unary transform from height with Last aggregation. - use brk_traversable::Traversable; use brk_types::{Height, Version}; use derive_more::{Deref, DerefMut}; @@ -75,7 +73,11 @@ where S2T: ComputedVecValue + JsonSchema, { Self { - height: LazyVecFrom1::transformed::(name, version, source.height.read_only_boxed_clone()), + height: LazyVecFrom1::transformed::( + name, + version, + source.height.read_only_boxed_clone(), + ), rest: Box::new(LazyHeightDerived::from_lazy::( name, version, diff --git a/crates/brk_computer/src/internal/from_height/percent.rs b/crates/brk_computer/src/internal/from_height/percent.rs index 098af48aa..aa715728a 100644 --- a/crates/brk_computer/src/internal/from_height/percent.rs +++ b/crates/brk_computer/src/internal/from_height/percent.rs @@ -1,12 +1,13 @@ use brk_error::Result; use brk_traversable::Traversable; use brk_types::{Height, StoredF32, Version}; -use vecdb::{BinaryTransform, Database, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode, VecValue}; +use vecdb::{ + BinaryTransform, Database, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode, VecValue, +}; use crate::{ indexes, - internal::BpsType, - traits::ComputeDrawdown, + internal::{BpsType, ComputeDrawdown}, }; use super::{ComputedFromHeight, LazyFromHeight}; @@ -47,7 +48,11 @@ impl PercentFromHeight { &bps, ); - Ok(Self { bps, ratio, percent }) + Ok(Self { + bps, + ratio, + percent, + }) } pub(crate) fn compute_binary( @@ -62,7 +67,8 @@ impl PercentFromHeight { S2T: VecValue, F: BinaryTransform, { - self.bps.compute_binary::(max_from, source1, source2, exit) + self.bps + .compute_binary::(max_from, source1, source2, exit) } pub(crate) fn compute_drawdown( @@ -78,6 +84,8 @@ impl PercentFromHeight { f64: From + From, vecdb::EagerVec>: ComputeDrawdown, { - self.bps.height.compute_drawdown(max_from, current, ath, exit) + self.bps + .height + .compute_drawdown(max_from, current, ath, exit) } } diff --git a/crates/brk_computer/src/internal/from_height/percent_distribution.rs b/crates/brk_computer/src/internal/from_height/percent_distribution.rs index 9617b2394..1c5f52608 100644 --- a/crates/brk_computer/src/internal/from_height/percent_distribution.rs +++ b/crates/brk_computer/src/internal/from_height/percent_distribution.rs @@ -3,7 +3,10 @@ use brk_traversable::Traversable; use brk_types::{Height, StoredF32, Version}; use vecdb::{Database, EagerVec, Exit, PcoVec, ReadableCloneableVec, Rw, StorageMode}; -use crate::{indexes, internal::{BpsType, WindowStarts}}; +use crate::{ + indexes, + internal::{BpsType, WindowStarts}, +}; use super::{ComputedFromHeightDistribution, LazyFromHeight}; @@ -22,7 +25,12 @@ impl PercentFromHeightDistribution { version: Version, indexes: &indexes::Vecs, ) -> Result { - let bps = ComputedFromHeightDistribution::forced_import(db, &format!("{name}_bps"), version, indexes)?; + let bps = ComputedFromHeightDistribution::forced_import( + db, + &format!("{name}_bps"), + version, + indexes, + )?; let ratio = LazyFromHeight::from_height_source::( &format!("{name}_ratio"), @@ -38,7 +46,11 @@ impl PercentFromHeightDistribution { indexes, ); - Ok(Self { bps, ratio, percent }) + Ok(Self { + bps, + ratio, + percent, + }) } pub(crate) fn compute( diff --git a/crates/brk_computer/src/internal/from_height/percentiles.rs b/crates/brk_computer/src/internal/from_height/percentiles.rs index e89015f42..57a2ba2c1 100644 --- a/crates/brk_computer/src/internal/from_height/percentiles.rs +++ b/crates/brk_computer/src/internal/from_height/percentiles.rs @@ -109,7 +109,9 @@ impl PercentilesVecs { /// Validate computed versions or reset if mismatched. pub(crate) fn validate_computed_version_or_reset(&mut self, version: Version) -> Result<()> { for vec in self.vecs.iter_mut() { - vec.cents.height.validate_computed_version_or_reset(version)?; + vec.cents + .height + .validate_computed_version_or_reset(version)?; } Ok(()) } @@ -120,10 +122,7 @@ impl ReadOnlyClone for PercentilesVecs { fn read_only_clone(&self) -> Self::ReadOnly { PercentilesVecs { - vecs: self - .vecs - .each_ref() - .map(|v| v.read_only_clone()), + vecs: self.vecs.each_ref().map(|v| v.read_only_clone()), } } } @@ -143,8 +142,6 @@ where } fn iter_any_exportable(&self) -> impl Iterator { - self.vecs - .iter() - .flat_map(|p| p.iter_any_exportable()) + self.vecs.iter().flat_map(|p| p.iter_any_exportable()) } } diff --git a/crates/brk_computer/src/internal/from_height/ratio/extension.rs b/crates/brk_computer/src/internal/from_height/ratio/extension.rs index f572255de..acda024c2 100644 --- a/crates/brk_computer/src/internal/from_height/ratio/extension.rs +++ b/crates/brk_computer/src/internal/from_height/ratio/extension.rs @@ -1,14 +1,17 @@ use brk_error::Result; use brk_traversable::Traversable; use brk_types::{BasisPoints32, Cents, Height, Indexes, StoredF32, Version}; -use vecdb::{AnyStoredVec, AnyVec, Database, EagerVec, Exit, PcoVec, ReadableVec, Rw, StorageMode, VecIndex, WritableVec}; +use vecdb::{ + AnyStoredVec, AnyVec, Database, EagerVec, Exit, PcoVec, ReadableVec, Rw, StorageMode, VecIndex, + WritableVec, +}; use crate::{ blocks, indexes, internal::{ComputedFromHeightStdDevExtended, Price, TDigest}, }; -use super::{ComputedFromHeightRatio, super::ComputedFromHeight}; +use super::{super::ComputedFromHeight, ComputedFromHeightRatio}; #[derive(Traversable)] pub struct ComputedFromHeightRatioExtension { @@ -100,7 +103,6 @@ impl ComputedFromHeightRatioExtension { }) } - /// Compute extended ratio metrics from an externally-provided ratio source. pub(crate) fn compute_rest( &mut self, blocks: &blocks::Vecs, @@ -124,11 +126,10 @@ impl ComputedFromHeightRatioExtension { )?; let ratio_version = ratio_source.version(); - self.mut_pct_vecs() - .try_for_each(|v| -> Result<()> { - v.validate_computed_version_or_reset(ratio_version)?; - Ok(()) - })?; + self.mut_pct_vecs().try_for_each(|v| -> Result<()> { + v.validate_computed_version_or_reset(ratio_version)?; + Ok(()) + })?; let starting_height = self .mut_pct_vecs() @@ -177,19 +178,22 @@ impl ComputedFromHeightRatioExtension { { let _lock = exit.lock(); - self.mut_pct_vecs() - .try_for_each(|v| v.flush())?; + self.mut_pct_vecs().try_for_each(|v| v.flush())?; } // Compute stddev at height level - for sd in [&mut self.ratio_sd, &mut self.ratio_sd_4y, &mut self.ratio_sd_2y, &mut self.ratio_sd_1y] { + for sd in [ + &mut self.ratio_sd, + &mut self.ratio_sd_4y, + &mut self.ratio_sd_2y, + &mut self.ratio_sd_1y, + ] { sd.compute_all(blocks, starting_indexes, exit, ratio_source)?; } Ok(()) } - /// Compute cents ratio bands: cents_band = metric_price_cents * ratio_percentile pub(crate) fn compute_cents_bands( &mut self, starting_indexes: &Indexes, @@ -219,7 +223,12 @@ impl ComputedFromHeightRatioExtension { compute_band!(ratio_pct1_price, &self.ratio_pct1.bps.height); // Stddev cents bands - for sd in [&mut self.ratio_sd, &mut self.ratio_sd_4y, &mut self.ratio_sd_2y, &mut self.ratio_sd_1y] { + for sd in [ + &mut self.ratio_sd, + &mut self.ratio_sd_4y, + &mut self.ratio_sd_2y, + &mut self.ratio_sd_1y, + ] { sd.compute_cents_bands(starting_indexes, metric_price, exit)?; } diff --git a/crates/brk_computer/src/internal/from_height/ratio/mod.rs b/crates/brk_computer/src/internal/from_height/ratio/mod.rs index c8c93c25a..de4b44287 100644 --- a/crates/brk_computer/src/internal/from_height/ratio/mod.rs +++ b/crates/brk_computer/src/internal/from_height/ratio/mod.rs @@ -53,7 +53,6 @@ impl ComputedFromHeightRatio { Ok(Self { bps, ratio }) } - /// Compute ratio = close_price / metric_price at height level (both in cents) pub(crate) fn compute_ratio( &mut self, starting_indexes: &Indexes, diff --git a/crates/brk_computer/src/internal/from_height/stddev/extended.rs b/crates/brk_computer/src/internal/from_height/stddev/extended.rs index fade86999..b6a77d1d7 100644 --- a/crates/brk_computer/src/internal/from_height/stddev/extended.rs +++ b/crates/brk_computer/src/internal/from_height/stddev/extended.rs @@ -77,7 +77,14 @@ impl ComputedFromHeightStdDevExtended { } Ok(Self { - base: ComputedFromHeightStdDev::forced_import(db, name, period, days, parent_version, indexes)?, + base: ComputedFromHeightStdDev::forced_import( + db, + name, + period, + days, + parent_version, + indexes, + )?, zscore: import!("zscore"), p0_5sd: import!("p0_5sd"), p1sd: import!("p1sd"), @@ -162,7 +169,9 @@ impl ComputedFromHeightStdDevExtended { .height .collect_range_at(start, self.base.sd.height.len()); - const MULTIPLIERS: [f32; 12] = [0.5, 1.0, 1.5, 2.0, 2.5, 3.0, -0.5, -1.0, -1.5, -2.0, -2.5, -3.0]; + const MULTIPLIERS: [f32; 12] = [ + 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, -0.5, -1.0, -1.5, -2.0, -2.5, -3.0, + ]; let band_vecs: Vec<_> = self.mut_band_height_vecs().collect(); for (vec, mult) in band_vecs.into_iter().zip(MULTIPLIERS) { for (offset, _) in source_data.iter().enumerate() { @@ -199,7 +208,6 @@ impl ComputedFromHeightStdDevExtended { Ok(()) } - /// Compute cents price bands: cents_band = metric_price_cents * band_ratio pub(crate) fn compute_cents_bands( &mut self, starting_indexes: &Indexes, diff --git a/crates/brk_computer/src/internal/from_height/stddev/mod.rs b/crates/brk_computer/src/internal/from_height/stddev/mod.rs index 521a945f5..ee23d514a 100644 --- a/crates/brk_computer/src/internal/from_height/stddev/mod.rs +++ b/crates/brk_computer/src/internal/from_height/stddev/mod.rs @@ -38,18 +38,9 @@ impl ComputedFromHeightStdDev { let version = parent_version + Version::TWO; let p = period_suffix(period); - let sma = ComputedFromHeight::forced_import( - db, - &format!("{name}_sma{p}"), - version, - indexes, - )?; - let sd = ComputedFromHeight::forced_import( - db, - &format!("{name}_sd{p}"), - version, - indexes, - )?; + let sma = + ComputedFromHeight::forced_import(db, &format!("{name}_sma{p}"), version, indexes)?; + let sd = ComputedFromHeight::forced_import(db, &format!("{name}_sd{p}"), version, indexes)?; Ok(Self { days, sma, sd }) } diff --git a/crates/brk_computer/src/internal/from_height/value/base.rs b/crates/brk_computer/src/internal/from_height/value/base.rs index bd2874dc3..446090a48 100644 --- a/crates/brk_computer/src/internal/from_height/value/base.rs +++ b/crates/brk_computer/src/internal/from_height/value/base.rs @@ -5,8 +5,9 @@ use derive_more::{Deref, DerefMut}; use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode}; use crate::{ - indexes, prices, + indexes, internal::{ByUnit, SatsToCents}, + prices, }; #[derive(Deref, DerefMut, Traversable)] @@ -74,14 +75,18 @@ impl ValueFromHeight { cents_source: &(impl ReadableVec + Sync), exit: &Exit, ) -> Result<()> { - self.base - .sats - .height - .compute_rolling_ema(starting_height, window_starts, sats_source, exit)?; - self.base - .cents - .height - .compute_rolling_ema(starting_height, window_starts, cents_source, exit)?; + self.base.sats.height.compute_rolling_ema( + starting_height, + window_starts, + sats_source, + exit, + )?; + self.base.cents.height.compute_rolling_ema( + starting_height, + window_starts, + cents_source, + exit, + )?; Ok(()) } } diff --git a/crates/brk_computer/src/internal/from_height/value/change.rs b/crates/brk_computer/src/internal/from_height/value/change.rs index 421e841b1..523623232 100644 --- a/crates/brk_computer/src/internal/from_height/value/change.rs +++ b/crates/brk_computer/src/internal/from_height/value/change.rs @@ -7,9 +7,7 @@ use vecdb::{Database, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode}; use crate::{ indexes, - internal::{ - CentsSignedToDollars, ComputedFromHeight, LazyFromHeight, SatsSignedToBitcoin, - }, + internal::{CentsSignedToDollars, ComputedFromHeight, LazyFromHeight, SatsSignedToBitcoin}, }; /// Change values indexed by height - sats (stored), btc (lazy), cents (stored), usd (lazy). @@ -37,12 +35,8 @@ impl ValueFromHeightChange { &sats, ); - let cents = ComputedFromHeight::forced_import( - db, - &format!("{name}_cents"), - version, - indexes, - )?; + let cents = + ComputedFromHeight::forced_import(db, &format!("{name}_cents"), version, indexes)?; let usd = LazyFromHeight::from_computed::( &format!("{name}_usd"), @@ -51,7 +45,12 @@ impl ValueFromHeightChange { ¢s, ); - Ok(Self { sats, btc, cents, usd }) + Ok(Self { + sats, + btc, + cents, + usd, + }) } /// Compute rolling change for both sats and cents in one call. @@ -63,12 +62,18 @@ impl ValueFromHeightChange { cents_source: &(impl ReadableVec + Sync), exit: &Exit, ) -> Result<()> { - self.sats - .height - .compute_rolling_change(starting_height, window_starts, sats_source, exit)?; - self.cents - .height - .compute_rolling_change(starting_height, window_starts, cents_source, exit)?; + self.sats.height.compute_rolling_change( + starting_height, + window_starts, + sats_source, + exit, + )?; + self.cents.height.compute_rolling_change( + starting_height, + window_starts, + cents_source, + exit, + )?; Ok(()) } } diff --git a/crates/brk_computer/src/internal/from_height/value/cumulative.rs b/crates/brk_computer/src/internal/from_height/value/cumulative.rs index 446f769aa..5bc2ab549 100644 --- a/crates/brk_computer/src/internal/from_height/value/cumulative.rs +++ b/crates/brk_computer/src/internal/from_height/value/cumulative.rs @@ -43,14 +43,12 @@ impl ValueFromHeightCumulative { .height .compute_cumulative(max_from, &self.base.sats.height, exit)?; - self.base - .cents - .compute_binary::( - max_from, - &self.base.sats.height, - &prices.price.cents.height, - exit, - )?; + self.base.cents.compute_binary::( + max_from, + &self.base.sats.height, + &prices.price.cents.height, + exit, + )?; self.cumulative .cents diff --git a/crates/brk_computer/src/internal/from_height/value/lazy.rs b/crates/brk_computer/src/internal/from_height/value/lazy.rs index 2a8826fdf..79be366f0 100644 --- a/crates/brk_computer/src/internal/from_height/value/lazy.rs +++ b/crates/brk_computer/src/internal/from_height/value/lazy.rs @@ -20,7 +20,12 @@ pub struct LazyValueFromHeight { } impl LazyValueFromHeight { - pub(crate) fn from_block_source( + pub(crate) fn from_block_source< + SatsTransform, + BitcoinTransform, + CentsTransform, + DollarsTransform, + >( name: &str, source: &ValueFromHeight, version: Version, @@ -31,14 +36,23 @@ impl LazyValueFromHeight { CentsTransform: UnaryTransform, DollarsTransform: UnaryTransform, { - let height = - LazyValue::from_block_source::(name, source, version); + let height = LazyValue::from_block_source::< + SatsTransform, + BitcoinTransform, + CentsTransform, + DollarsTransform, + >(name, source, version); - let rest = - LazyValueHeightDerived::from_block_source::( - name, source, version, - ); + let rest = LazyValueHeightDerived::from_block_source::< + SatsTransform, + BitcoinTransform, + CentsTransform, + DollarsTransform, + >(name, source, version); - Self { height, rest: Box::new(rest) } + Self { + height, + rest: Box::new(rest), + } } } diff --git a/crates/brk_computer/src/internal/from_height/value/rolling.rs b/crates/brk_computer/src/internal/from_height/value/rolling.rs index 2a2cf4537..049eeb983 100644 --- a/crates/brk_computer/src/internal/from_height/value/rolling.rs +++ b/crates/brk_computer/src/internal/from_height/value/rolling.rs @@ -11,7 +11,7 @@ use vecdb::{Database, EagerVec, Exit, PcoVec, Rw, StorageMode}; use crate::{ indexes, - internal::{ValueFromHeightWindows, Value, WindowStarts}, + internal::{Value, ValueFromHeightWindows, WindowStarts}, prices, }; diff --git a/crates/brk_computer/src/internal/from_tx/derived.rs b/crates/brk_computer/src/internal/from_tx/derived.rs index 56591b9b8..0cb386d8b 100644 --- a/crates/brk_computer/src/internal/from_tx/derived.rs +++ b/crates/brk_computer/src/internal/from_tx/derived.rs @@ -30,11 +30,7 @@ impl BlockRollingDistribution where T: NumericValue + JsonSchema, { - pub(crate) fn forced_import( - db: &Database, - name: &str, - version: Version, - ) -> Result { + pub(crate) fn forced_import(db: &Database, name: &str, version: Version) -> Result { Ok(Self { _6b: Distribution::forced_import(db, &format!("{name}_6b"), version)?, }) @@ -74,14 +70,7 @@ where T: Copy + Ord + From + Default, f64: From, { - self.derive_from_with_skip( - indexer, - indexes, - starting_indexes, - txindex_source, - exit, - 0, - ) + self.derive_from_with_skip(indexer, indexes, starting_indexes, txindex_source, exit, 0) } /// Derive from source, skipping first N transactions per block from per-block stats. diff --git a/crates/brk_computer/src/internal/from_tx/lazy_distribution.rs b/crates/brk_computer/src/internal/from_tx/lazy_distribution.rs index 59584858b..1ca6357f6 100644 --- a/crates/brk_computer/src/internal/from_tx/lazy_distribution.rs +++ b/crates/brk_computer/src/internal/from_tx/lazy_distribution.rs @@ -1,5 +1,3 @@ -//! LazyFromTxDistribution - lazy txindex source + computed distribution. - use brk_error::Result; use brk_indexer::Indexer; use brk_traversable::Traversable; @@ -55,12 +53,7 @@ where f64: From, LazyVecFrom2: ReadableVec, { - self.distribution.derive_from( - indexer, - indexes, - starting_indexes, - &self.txindex, - exit, - ) + self.distribution + .derive_from(indexer, indexes, starting_indexes, &self.txindex, exit) } } diff --git a/crates/brk_computer/src/internal/indexes.rs b/crates/brk_computer/src/internal/indexes.rs deleted file mode 100644 index 5cd3f5c9a..000000000 --- a/crates/brk_computer/src/internal/indexes.rs +++ /dev/null @@ -1,86 +0,0 @@ -//! Base generic struct with 15 type parameters — one per time period/epoch index. -//! -//! Foundation for all per-index types. Replaces the repetitive 15-field pattern -//! found throughout height_derived types. - -use brk_traversable::Traversable; - -#[derive(Clone, Traversable)] -#[traversable(merge)] -pub struct PerPeriod { - pub minute10: M10, - pub minute30: M30, - pub hour1: H1, - pub hour4: H4, - pub hour12: H12, - pub day1: D1, - pub day3: D3, - pub week1: W1, - pub month1: Mo1, - pub month3: Mo3, - pub month6: Mo6, - pub year1: Y1, - pub year10: Y10, - pub halvingepoch: HE, - pub difficultyepoch: DE, -} - -/// Helper macro to construct a `PerPeriod` by applying a macro to each field. -/// -/// Usage: -/// ```ignore -/// indexes_from!(period, epoch) -/// ``` -/// where `period!($field)` and `epoch!($field)` are locally-defined macros. -#[macro_export] -macro_rules! indexes_from { - ($period:ident, $epoch:ident) => { - $crate::internal::PerPeriod { - minute10: $period!(minute10), - minute30: $period!(minute30), - hour1: $period!(hour1), - hour4: $period!(hour4), - hour12: $period!(hour12), - day1: $period!(day1), - day3: $period!(day3), - week1: $period!(week1), - month1: $period!(month1), - month3: $period!(month3), - month6: $period!(month6), - year1: $period!(year1), - year10: $period!(year10), - halvingepoch: $epoch!(halvingepoch), - difficultyepoch: $epoch!(difficultyepoch), - } - }; - // Variant where period and epoch use the same macro - ($m:ident) => { - $crate::indexes_from!($m, $m) - }; -} - -/// Imperative counterpart to `indexes_from!` — calls `$period!(field)` for each -/// period field and `$epoch!(field)` for each epoch field. -#[macro_export] -macro_rules! indexes_apply { - ($period:ident, $epoch:ident) => { - $period!(minute10); - $period!(minute30); - $period!(hour1); - $period!(hour4); - $period!(hour12); - $period!(day1); - $period!(day3); - $period!(week1); - $period!(month1); - $period!(month3); - $period!(month6); - $period!(year1); - $period!(year10); - $epoch!(halvingepoch); - $epoch!(difficultyepoch); - }; - ($m:ident) => { - $crate::indexes_apply!($m, $m) - }; -} diff --git a/crates/brk_computer/src/internal/lazy_eager_indexes.rs b/crates/brk_computer/src/internal/lazy_eager_indexes.rs index a04c90649..3f673ba29 100644 --- a/crates/brk_computer/src/internal/lazy_eager_indexes.rs +++ b/crates/brk_computer/src/internal/lazy_eager_indexes.rs @@ -1,21 +1,13 @@ -//! LazyEagerIndexes - lazy per-period transform of EagerIndexes. -//! -//! Used for lazy currency transforms (e.g., cents→dollars, cents→sats) -//! of eagerly computed per-period data like OHLC. - use brk_traversable::Traversable; use brk_types::{ - Day1, Day3, DifficultyEpoch, HalvingEpoch, Hour1, Hour4, Hour12, - Minute10, Minute30, Month1, Month3, Month6, Version, Week1, Year1, Year10, + Day1, Day3, DifficultyEpoch, HalvingEpoch, Hour1, Hour4, Hour12, Minute10, Minute30, Month1, + Month3, Month6, Version, Week1, Year1, Year10, }; use derive_more::{Deref, DerefMut}; use schemars::JsonSchema; use vecdb::{LazyVecFrom1, ReadableCloneableVec, UnaryTransform}; -use crate::{ - indexes_from, - internal::{ComputedVecValue, EagerIndexes, PerPeriod}, -}; +use crate::internal::{ComputedVecValue, EagerIndexes, PerPeriod}; #[derive(Clone, Deref, DerefMut, Traversable)] #[traversable(transparent)] @@ -48,7 +40,6 @@ where T: ComputedVecValue + PartialOrd + JsonSchema, S: ComputedVecValue + PartialOrd + JsonSchema, { - /// Create lazy per-period transforms from an EagerIndexes source. pub(crate) fn from_eager_indexes>( name: &str, version: Version, @@ -64,6 +55,22 @@ where }; } - Self(indexes_from!(period)) + Self(PerPeriod { + minute10: period!(minute10), + minute30: period!(minute30), + hour1: period!(hour1), + hour4: period!(hour4), + hour12: period!(hour12), + day1: period!(day1), + day3: period!(day3), + week1: period!(week1), + month1: period!(month1), + month3: period!(month3), + month6: period!(month6), + year1: period!(year1), + year10: period!(year10), + halvingepoch: period!(halvingepoch), + difficultyepoch: period!(difficultyepoch), + }) } } diff --git a/crates/brk_computer/src/internal/lazy_value.rs b/crates/brk_computer/src/internal/lazy_value.rs index 5ca946123..f56b4f0f5 100644 --- a/crates/brk_computer/src/internal/lazy_value.rs +++ b/crates/brk_computer/src/internal/lazy_value.rs @@ -1,8 +1,6 @@ -//! Fully lazy value type. - use brk_traversable::Traversable; use brk_types::{Bitcoin, Cents, Dollars, Height, Sats, Version}; -use vecdb::{ReadableCloneableVec, LazyVecFrom1, UnaryTransform, VecIndex}; +use vecdb::{LazyVecFrom1, ReadableCloneableVec, UnaryTransform, VecIndex}; use crate::internal::ValueFromHeight; @@ -18,7 +16,12 @@ pub struct LazyValue { } impl LazyValue { - pub(crate) fn from_block_source( + pub(crate) fn from_block_source< + SatsTransform, + BitcoinTransform, + CentsTransform, + DollarsTransform, + >( name: &str, source: &ValueFromHeight, version: Version, @@ -29,8 +32,11 @@ impl LazyValue { CentsTransform: UnaryTransform, DollarsTransform: UnaryTransform, { - let sats = - LazyVecFrom1::transformed::(name, version, source.sats.height.read_only_boxed_clone()); + let sats = LazyVecFrom1::transformed::( + name, + version, + source.sats.height.read_only_boxed_clone(), + ); let btc = LazyVecFrom1::transformed::( &format!("{name}_btc"), @@ -50,6 +56,11 @@ impl LazyValue { source.usd.height.read_only_boxed_clone(), ); - Self { sats, btc, cents, usd } + Self { + sats, + btc, + cents, + usd, + } } } diff --git a/crates/brk_computer/src/internal/mod.rs b/crates/brk_computer/src/internal/mod.rs index 2e31458eb..fa7d9b6fe 100644 --- a/crates/brk_computer/src/internal/mod.rs +++ b/crates/brk_computer/src/internal/mod.rs @@ -1,31 +1,33 @@ -pub(crate) mod algo; mod aggregate; +pub(crate) mod algo; +mod db_utils; mod derived; mod distribution_stats; mod eager_indexes; mod emas; mod from_height; mod from_tx; -mod indexes; mod lazy_eager_indexes; mod lazy_value; +mod per_period; mod rolling; mod traits; -mod transform; +pub mod transform; mod value; mod windows; -pub(crate) use algo::*; pub(crate) use aggregate::*; +pub(crate) use algo::*; +pub(crate) use db_utils::*; pub(crate) use derived::*; pub(crate) use distribution_stats::*; pub(crate) use eager_indexes::*; pub(crate) use emas::*; pub(crate) use from_height::*; pub(crate) use from_tx::*; -pub(crate) use indexes::*; pub(crate) use lazy_eager_indexes::*; pub(crate) use lazy_value::*; +pub(crate) use per_period::*; pub(crate) use rolling::*; pub(crate) use traits::*; pub use transform::*; diff --git a/crates/brk_computer/src/internal/per_period.rs b/crates/brk_computer/src/internal/per_period.rs new file mode 100644 index 000000000..038a93566 --- /dev/null +++ b/crates/brk_computer/src/internal/per_period.rs @@ -0,0 +1,21 @@ +use brk_traversable::Traversable; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct PerPeriod { + pub minute10: M10, + pub minute30: M30, + pub hour1: H1, + pub hour4: H4, + pub hour12: H12, + pub day1: D1, + pub day3: D3, + pub week1: W1, + pub month1: Mo1, + pub month3: Mo3, + pub month6: Mo6, + pub year1: Y1, + pub year10: Y10, + pub halvingepoch: HE, + pub difficultyepoch: DE, +} diff --git a/crates/brk_computer/src/internal/rolling/distribution.rs b/crates/brk_computer/src/internal/rolling/distribution.rs index b4aa58f44..f57457d76 100644 --- a/crates/brk_computer/src/internal/rolling/distribution.rs +++ b/crates/brk_computer/src/internal/rolling/distribution.rs @@ -1,8 +1,3 @@ -//! RollingDistribution - 8 distribution stats, each a RollingWindows. -//! -//! Computes average, min, max, p10, p25, median, p75, p90 rolling windows -//! from a single source vec in a single sorted-vec pass per window. - use brk_error::Result; use brk_traversable::Traversable; @@ -13,11 +8,12 @@ use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode}; use crate::{ indexes, - internal::{ComputedVecValue, DistributionStats, NumericValue, RollingWindows, WindowStarts}, - traits::compute_rolling_distribution_from_starts, + internal::{ + ComputedVecValue, DistributionStats, NumericValue, RollingWindows, WindowStarts, + compute_rolling_distribution_from_starts, + }, }; -/// 8 distribution stats × 4 windows = 32 stored height vecs, each with 17 index views. #[derive(Deref, DerefMut, Traversable)] #[traversable(transparent)] pub struct RollingDistribution(pub DistributionStats>) @@ -39,12 +35,6 @@ where })?)) } - /// Compute all 8 distribution stats across all 4 windows from a single source. - /// - /// Uses a single sorted-vec pass per window that extracts all 8 stats: - /// - average: running sum / count - /// - min/max: first/last of sorted vec - /// - p10/p25/median/p75/p90: percentile interpolation from sorted vec pub(crate) fn compute_distribution( &mut self, max_from: Height, @@ -59,11 +49,18 @@ where macro_rules! compute_window { ($w:ident) => { compute_rolling_distribution_from_starts( - max_from, windows.$w, source, - &mut self.0.average.$w.height, &mut self.0.min.$w.height, - &mut self.0.max.$w.height, &mut self.0.pct10.$w.height, - &mut self.0.pct25.$w.height, &mut self.0.median.$w.height, - &mut self.0.pct75.$w.height, &mut self.0.pct90.$w.height, exit, + max_from, + windows.$w, + source, + &mut self.0.average.$w.height, + &mut self.0.min.$w.height, + &mut self.0.max.$w.height, + &mut self.0.pct10.$w.height, + &mut self.0.pct25.$w.height, + &mut self.0.median.$w.height, + &mut self.0.pct75.$w.height, + &mut self.0.pct90.$w.height, + exit, )? }; } diff --git a/crates/brk_computer/src/internal/rolling/emas/percent_1w_1m.rs b/crates/brk_computer/src/internal/rolling/emas/percent_1w_1m.rs index 5e5d0e9cf..f0992e0f1 100644 --- a/crates/brk_computer/src/internal/rolling/emas/percent_1w_1m.rs +++ b/crates/brk_computer/src/internal/rolling/emas/percent_1w_1m.rs @@ -13,7 +13,9 @@ use crate::{ /// each storing basis points with lazy ratio and percent float views. #[derive(Deref, DerefMut, Traversable)] #[traversable(transparent)] -pub struct PercentRollingEmas1w1m(pub Emas1w1m>); +pub struct PercentRollingEmas1w1m( + pub Emas1w1m>, +); impl PercentRollingEmas1w1m { pub(crate) fn forced_import( @@ -23,12 +25,7 @@ impl PercentRollingEmas1w1m { indexes: &indexes::Vecs, ) -> Result { Ok(Self(Emas1w1m::try_from_fn(|suffix| { - PercentFromHeight::forced_import( - db, - &format!("{name}_{suffix}"), - version, - indexes, - ) + PercentFromHeight::forced_import(db, &format!("{name}_{suffix}"), version, indexes) })?)) } diff --git a/crates/brk_computer/src/internal/rolling/percent_windows.rs b/crates/brk_computer/src/internal/rolling/percent_windows.rs index b7b658327..58e7ee69d 100644 --- a/crates/brk_computer/src/internal/rolling/percent_windows.rs +++ b/crates/brk_computer/src/internal/rolling/percent_windows.rs @@ -13,7 +13,9 @@ use crate::{ /// with lazy ratio and percent float views. #[derive(Deref, DerefMut, Traversable)] #[traversable(transparent)] -pub struct PercentRollingWindows(pub Windows>); +pub struct PercentRollingWindows( + pub Windows>, +); impl PercentRollingWindows { pub(crate) fn forced_import( @@ -23,12 +25,7 @@ impl PercentRollingWindows { indexes: &indexes::Vecs, ) -> Result { Ok(Self(Windows::try_from_fn(|suffix| { - PercentFromHeight::forced_import( - db, - &format!("{name}_{suffix}"), - version, - indexes, - ) + PercentFromHeight::forced_import(db, &format!("{name}_{suffix}"), version, indexes) })?)) } } diff --git a/crates/brk_computer/src/internal/rolling/value_windows.rs b/crates/brk_computer/src/internal/rolling/value_windows.rs index 946a60fab..d9bfdb6b2 100644 --- a/crates/brk_computer/src/internal/rolling/value_windows.rs +++ b/crates/brk_computer/src/internal/rolling/value_windows.rs @@ -22,9 +22,7 @@ use crate::{ /// Each window contains `ValueFromHeight` (sats + btc lazy + usd). #[derive(Deref, DerefMut, Traversable)] #[traversable(transparent)] -pub struct ValueFromHeightWindows( - pub Windows>, -); +pub struct ValueFromHeightWindows(pub Windows>); impl ValueFromHeightWindows { pub(crate) fn forced_import( diff --git a/crates/brk_computer/src/internal/rolling/windows.rs b/crates/brk_computer/src/internal/rolling/windows.rs index 681324dcd..3bd9c7a69 100644 --- a/crates/brk_computer/src/internal/rolling/windows.rs +++ b/crates/brk_computer/src/internal/rolling/windows.rs @@ -54,7 +54,8 @@ where T: Default + SubAssign, { for (w, starts) in self.0.as_mut_array().into_iter().zip(windows.as_array()) { - w.height.compute_rolling_sum(max_from, *starts, source, exit)?; + w.height + .compute_rolling_sum(max_from, *starts, source, exit)?; } Ok(()) } diff --git a/crates/brk_computer/src/internal/transform/arithmetic.rs b/crates/brk_computer/src/internal/transform/arithmetic.rs new file mode 100644 index 000000000..abb43e392 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/arithmetic.rs @@ -0,0 +1,89 @@ +use std::marker::PhantomData; + +use brk_types::{Bitcoin, Cents, Dollars, Sats, StoredF32, StoredI8, StoredU16, StoredU32}; +use vecdb::{BinaryTransform, UnaryTransform, VecValue}; + +pub struct Identity(PhantomData); + +impl UnaryTransform for Identity { + #[inline(always)] + fn apply(v: T) -> T { + v + } +} + +pub struct HalveSats; + +impl UnaryTransform for HalveSats { + #[inline(always)] + fn apply(sats: Sats) -> Sats { + sats / 2 + } +} + +pub struct HalveSatsToBitcoin; + +impl UnaryTransform for HalveSatsToBitcoin { + #[inline(always)] + fn apply(sats: Sats) -> Bitcoin { + Bitcoin::from(sats / 2) + } +} + +pub struct HalveCents; + +impl UnaryTransform for HalveCents { + #[inline(always)] + fn apply(cents: Cents) -> Cents { + cents / 2u64 + } +} + +pub struct HalveDollars; + +impl UnaryTransform for HalveDollars { + #[inline(always)] + fn apply(dollars: Dollars) -> Dollars { + dollars.halved() + } +} + +pub struct MaskSats; + +impl BinaryTransform for MaskSats { + #[inline(always)] + fn apply(mask: StoredU32, value: Sats) -> Sats { + if mask == StoredU32::ONE { + value + } else { + Sats::ZERO + } + } +} + +pub struct ReturnF32Tenths; + +impl UnaryTransform for ReturnF32Tenths { + #[inline(always)] + fn apply(_: S) -> StoredF32 { + StoredF32::from(V as f32 / 10.0) + } +} + +pub struct ReturnU16; + +impl UnaryTransform for ReturnU16 { + #[inline(always)] + fn apply(_: S) -> StoredU16 { + StoredU16::new(V) + } +} + +pub struct ReturnI8; + +impl UnaryTransform for ReturnI8 { + #[inline(always)] + fn apply(_: S) -> StoredI8 { + StoredI8::new(V) + } +} diff --git a/crates/brk_computer/src/internal/transform/bps_to_float.rs b/crates/brk_computer/src/internal/transform/bps.rs similarity index 52% rename from crates/brk_computer/src/internal/transform/bps_to_float.rs rename to crates/brk_computer/src/internal/transform/bps.rs index 8122186fd..0f75ffeb5 100644 --- a/crates/brk_computer/src/internal/transform/bps_to_float.rs +++ b/crates/brk_computer/src/internal/transform/bps.rs @@ -1,4 +1,6 @@ -use brk_types::{BasisPoints16, BasisPoints32, BasisPointsSigned16, BasisPointsSigned32, StoredF32}; +use brk_types::{ + BasisPoints16, BasisPoints32, BasisPointsSigned16, BasisPointsSigned32, StoredF32, +}; use vecdb::UnaryTransform; pub struct Bp16ToFloat; @@ -36,3 +38,30 @@ impl UnaryTransform for Bps32ToFloat { StoredF32::from(bp.to_f32()) } } + +pub struct Bp16ToPercent; + +impl UnaryTransform for Bp16ToPercent { + #[inline(always)] + fn apply(bp: BasisPoints16) -> StoredF32 { + StoredF32::from(bp.inner() as f32 / 100.0) + } +} + +pub struct Bps16ToPercent; + +impl UnaryTransform for Bps16ToPercent { + #[inline(always)] + fn apply(bp: BasisPointsSigned16) -> StoredF32 { + StoredF32::from(bp.inner() as f32 / 100.0) + } +} + +pub struct Bps32ToPercent; + +impl UnaryTransform for Bps32ToPercent { + #[inline(always)] + fn apply(bp: BasisPointsSigned32) -> StoredF32 { + StoredF32::from(bp.inner() as f32 / 100.0) + } +} diff --git a/crates/brk_computer/src/internal/transform/bps_to_percent.rs b/crates/brk_computer/src/internal/transform/bps_to_percent.rs deleted file mode 100644 index 229cc2356..000000000 --- a/crates/brk_computer/src/internal/transform/bps_to_percent.rs +++ /dev/null @@ -1,29 +0,0 @@ -use brk_types::{BasisPoints16, BasisPointsSigned16, BasisPointsSigned32, StoredF32}; -use vecdb::UnaryTransform; - -pub struct Bp16ToPercent; - -impl UnaryTransform for Bp16ToPercent { - #[inline(always)] - fn apply(bp: BasisPoints16) -> StoredF32 { - StoredF32::from(bp.inner() as f32 / 100.0) - } -} - -pub struct Bps16ToPercent; - -impl UnaryTransform for Bps16ToPercent { - #[inline(always)] - fn apply(bp: BasisPointsSigned16) -> StoredF32 { - StoredF32::from(bp.inner() as f32 / 100.0) - } -} - -pub struct Bps32ToPercent; - -impl UnaryTransform for Bps32ToPercent { - #[inline(always)] - fn apply(bp: BasisPointsSigned32) -> StoredF32 { - StoredF32::from(bp.inner() as f32 / 100.0) - } -} diff --git a/crates/brk_computer/src/internal/transform/cents_convert.rs b/crates/brk_computer/src/internal/transform/cents_convert.rs deleted file mode 100644 index ed1402113..000000000 --- a/crates/brk_computer/src/internal/transform/cents_convert.rs +++ /dev/null @@ -1,48 +0,0 @@ -use brk_types::{Cents, CentsSigned, Dollars, Sats}; -use vecdb::UnaryTransform; - -/// CentsUnsigned -> Dollars (convert cents to dollars for display) -pub struct CentsUnsignedToDollars; - -impl UnaryTransform for CentsUnsignedToDollars { - #[inline(always)] - fn apply(cents: Cents) -> Dollars { - cents.into() - } -} - -/// Cents -> -Dollars (negate after converting to dollars) -/// Avoids lazy-from-lazy by combining both transforms. -pub struct NegCentsUnsignedToDollars; - -impl UnaryTransform for NegCentsUnsignedToDollars { - #[inline(always)] - fn apply(cents: Cents) -> Dollars { - -Dollars::from(cents) - } -} - -/// CentsSigned -> Dollars (convert signed cents to dollars for display) -pub struct CentsSignedToDollars; - -impl UnaryTransform for CentsSignedToDollars { - #[inline(always)] - fn apply(cents: CentsSigned) -> Dollars { - cents.into() - } -} - -/// CentsUnsigned -> Sats (sats per dollar: 1 BTC / price) -pub struct CentsUnsignedToSats; - -impl UnaryTransform for CentsUnsignedToSats { - #[inline(always)] - fn apply(cents: Cents) -> Sats { - let dollars = Dollars::from(cents); - if dollars == Dollars::ZERO { - Sats::ZERO - } else { - Sats::ONE_BTC / dollars - } - } -} diff --git a/crates/brk_computer/src/internal/transform/cents_plus.rs b/crates/brk_computer/src/internal/transform/cents_plus.rs deleted file mode 100644 index 1592885cd..000000000 --- a/crates/brk_computer/src/internal/transform/cents_plus.rs +++ /dev/null @@ -1,13 +0,0 @@ -use brk_types::Cents; -use vecdb::BinaryTransform; - -/// (Cents, Cents) -> Cents addition -/// Used for computing total = profit + loss -pub struct CentsPlus; - -impl BinaryTransform for CentsPlus { - #[inline(always)] - fn apply(lhs: Cents, rhs: Cents) -> Cents { - lhs + rhs - } -} diff --git a/crates/brk_computer/src/internal/transform/cents_subtract_to_cents_signed.rs b/crates/brk_computer/src/internal/transform/cents_subtract_to_cents_signed.rs deleted file mode 100644 index cbe816f8e..000000000 --- a/crates/brk_computer/src/internal/transform/cents_subtract_to_cents_signed.rs +++ /dev/null @@ -1,13 +0,0 @@ -use brk_types::{Cents, CentsSigned}; -use vecdb::BinaryTransform; - -/// (Cents, Cents) -> CentsSigned (a - b) -/// Produces a signed result from two unsigned inputs. -pub struct CentsSubtractToCentsSigned; - -impl BinaryTransform for CentsSubtractToCentsSigned { - #[inline(always)] - fn apply(a: Cents, b: Cents) -> CentsSigned { - CentsSigned::from(a.inner() as i64 - b.inner() as i64) - } -} diff --git a/crates/brk_computer/src/internal/transform/cents_times_tenths.rs b/crates/brk_computer/src/internal/transform/cents_times_tenths.rs deleted file mode 100644 index 140be80c1..000000000 --- a/crates/brk_computer/src/internal/transform/cents_times_tenths.rs +++ /dev/null @@ -1,13 +0,0 @@ -use brk_types::Cents; -use vecdb::UnaryTransform; - -/// Cents * (V/10) -> Cents (e.g., V=8 -> * 0.8, V=24 -> * 2.4) -pub struct CentsTimesTenths; - -impl UnaryTransform for CentsTimesTenths { - #[inline(always)] - fn apply(c: Cents) -> Cents { - // Use u128 to avoid overflow: c * V / 10 - Cents::from(c.as_u128() * V as u128 / 10) - } -} diff --git a/crates/brk_computer/src/internal/transform/currency.rs b/crates/brk_computer/src/internal/transform/currency.rs new file mode 100644 index 000000000..3c2540a1c --- /dev/null +++ b/crates/brk_computer/src/internal/transform/currency.rs @@ -0,0 +1,106 @@ +use brk_types::{Bitcoin, Cents, CentsSigned, Dollars, Sats, SatsFract, SatsSigned}; +use vecdb::{BinaryTransform, UnaryTransform}; + +pub struct SatsToBitcoin; + +impl UnaryTransform for SatsToBitcoin { + #[inline(always)] + fn apply(sats: Sats) -> Bitcoin { + Bitcoin::from(sats) + } +} + +pub struct SatsSignedToBitcoin; + +impl UnaryTransform for SatsSignedToBitcoin { + #[inline(always)] + fn apply(sats: SatsSigned) -> Bitcoin { + Bitcoin::from(sats) + } +} + +pub struct SatsToCents; + +impl BinaryTransform for SatsToCents { + #[inline(always)] + fn apply(sats: Sats, price_cents: Cents) -> Cents { + Cents::from(sats.as_u128() * price_cents.as_u128() / Sats::ONE_BTC_U128) + } +} + +pub struct CentsUnsignedToDollars; + +impl UnaryTransform for CentsUnsignedToDollars { + #[inline(always)] + fn apply(cents: Cents) -> Dollars { + cents.into() + } +} + +pub struct NegCentsUnsignedToDollars; + +impl UnaryTransform for NegCentsUnsignedToDollars { + #[inline(always)] + fn apply(cents: Cents) -> Dollars { + -Dollars::from(cents) + } +} + +pub struct CentsSignedToDollars; + +impl UnaryTransform for CentsSignedToDollars { + #[inline(always)] + fn apply(cents: CentsSigned) -> Dollars { + cents.into() + } +} + +pub struct CentsUnsignedToSats; + +impl UnaryTransform for CentsUnsignedToSats { + #[inline(always)] + fn apply(cents: Cents) -> Sats { + let dollars = Dollars::from(cents); + if dollars == Dollars::ZERO { + Sats::ZERO + } else { + Sats::ONE_BTC / dollars + } + } +} + +pub struct CentsPlus; + +impl BinaryTransform for CentsPlus { + #[inline(always)] + fn apply(lhs: Cents, rhs: Cents) -> Cents { + lhs + rhs + } +} + +pub struct CentsSubtractToCentsSigned; + +impl BinaryTransform for CentsSubtractToCentsSigned { + #[inline(always)] + fn apply(a: Cents, b: Cents) -> CentsSigned { + CentsSigned::from(a.inner() as i64 - b.inner() as i64) + } +} + +pub struct CentsTimesTenths; + +impl UnaryTransform for CentsTimesTenths { + #[inline(always)] + fn apply(c: Cents) -> Cents { + Cents::from(c.as_u128() * V as u128 / 10) + } +} + +pub struct DollarsToSatsFract; + +impl UnaryTransform for DollarsToSatsFract { + #[inline(always)] + fn apply(usd: Dollars) -> SatsFract { + SatsFract::ONE_BTC / usd + } +} diff --git a/crates/brk_computer/src/internal/transform/days_to_years.rs b/crates/brk_computer/src/internal/transform/days_to_years.rs deleted file mode 100644 index 15cc970d9..000000000 --- a/crates/brk_computer/src/internal/transform/days_to_years.rs +++ /dev/null @@ -1,11 +0,0 @@ -use brk_types::StoredF32; -use vecdb::UnaryTransform; - -pub struct DaysToYears; - -impl UnaryTransform for DaysToYears { - #[inline(always)] - fn apply(v: StoredF32) -> StoredF32 { - StoredF32::from(*v / 365.0) - } -} diff --git a/crates/brk_computer/src/internal/transform/derived.rs b/crates/brk_computer/src/internal/transform/derived.rs new file mode 100644 index 000000000..352f10ab7 --- /dev/null +++ b/crates/brk_computer/src/internal/transform/derived.rs @@ -0,0 +1,86 @@ +use std::marker::PhantomData; + +use brk_types::{BasisPoints32, Cents, StoredF32, StoredF64, StoredU64, Timestamp}; +use vecdb::{BinaryTransform, UnaryTransform}; + +pub struct PerSec; + +impl BinaryTransform for PerSec { + #[inline(always)] + fn apply(count: StoredU64, interval: Timestamp) -> StoredF32 { + let interval_f64 = f64::from(*interval); + if interval_f64 > 0.0 { + StoredF32::from(*count as f64 / interval_f64) + } else { + StoredF32::NAN + } + } +} + +pub struct DaysToYears; + +impl UnaryTransform for DaysToYears { + #[inline(always)] + fn apply(v: StoredF32) -> StoredF32 { + StoredF32::from(*v / 365.0) + } +} + +pub trait SqrtDays { + const FACTOR: f32; +} + +pub struct Days7; +impl SqrtDays for Days7 { + const FACTOR: f32 = 2.6457513; // 7.0_f32.sqrt() +} + +pub struct Days30; +impl SqrtDays for Days30 { + const FACTOR: f32 = 5.477226; // 30.0_f32.sqrt() +} + +pub struct Days365; +impl SqrtDays for Days365 { + const FACTOR: f32 = 19.104973; // 365.0_f32.sqrt() +} + +pub struct TimesSqrt(PhantomData); + +impl UnaryTransform for TimesSqrt { + #[inline(always)] + fn apply(v: StoredF32) -> StoredF32 { + (*v * D::FACTOR).into() + } +} + +pub struct PriceTimesRatioCents; + +impl BinaryTransform for PriceTimesRatioCents { + #[inline(always)] + fn apply(price: Cents, ratio: StoredF32) -> Cents { + Cents::from(f64::from(price) * f64::from(ratio)) + } +} + +pub struct PriceTimesRatioBp32Cents; + +impl BinaryTransform for PriceTimesRatioBp32Cents { + #[inline(always)] + fn apply(price: Cents, ratio: BasisPoints32) -> Cents { + Cents::from(f64::from(price) * f64::from(ratio)) + } +} + +pub struct RatioCents64; + +impl BinaryTransform for RatioCents64 { + #[inline(always)] + fn apply(numerator: Cents, denominator: Cents) -> StoredF64 { + if denominator == Cents::ZERO { + StoredF64::from(1.0) + } else { + StoredF64::from(numerator.inner() as f64 / denominator.inner() as f64) + } + } +} diff --git a/crates/brk_computer/src/internal/transform/dollars_to_sats_fract.rs b/crates/brk_computer/src/internal/transform/dollars_to_sats_fract.rs deleted file mode 100644 index 9e6209a07..000000000 --- a/crates/brk_computer/src/internal/transform/dollars_to_sats_fract.rs +++ /dev/null @@ -1,13 +0,0 @@ -use brk_types::{Dollars, SatsFract}; -use vecdb::UnaryTransform; - -/// Dollars -> SatsFract (exchange rate: sats per dollar at this price level) -/// Formula: sats = 100_000_000 / usd_price -pub struct DollarsToSatsFract; - -impl UnaryTransform for DollarsToSatsFract { - #[inline(always)] - fn apply(usd: Dollars) -> SatsFract { - SatsFract::ONE_BTC / usd - } -} diff --git a/crates/brk_computer/src/internal/transform/halve.rs b/crates/brk_computer/src/internal/transform/halve.rs deleted file mode 100644 index 157c780d2..000000000 --- a/crates/brk_computer/src/internal/transform/halve.rs +++ /dev/null @@ -1,43 +0,0 @@ -use brk_types::{Bitcoin, Cents, Dollars, Sats}; -use vecdb::UnaryTransform; - -/// Sats -> Sats/2 (for supply_halved) -pub struct HalveSats; - -impl UnaryTransform for HalveSats { - #[inline(always)] - fn apply(sats: Sats) -> Sats { - sats / 2 - } -} - -/// Sats -> Bitcoin/2 (halve then convert to bitcoin) -/// Avoids lazy-from-lazy by combining both transforms -pub struct HalveSatsToBitcoin; - -impl UnaryTransform for HalveSatsToBitcoin { - #[inline(always)] - fn apply(sats: Sats) -> Bitcoin { - Bitcoin::from(sats / 2) - } -} - -/// Cents -> Cents/2 (for supply_halved_cents) -pub struct HalveCents; - -impl UnaryTransform for HalveCents { - #[inline(always)] - fn apply(cents: Cents) -> Cents { - cents / 2u64 - } -} - -/// Dollars -> Dollars/2 (for supply_halved_usd) -pub struct HalveDollars; - -impl UnaryTransform for HalveDollars { - #[inline(always)] - fn apply(dollars: Dollars) -> Dollars { - dollars.halved() - } -} diff --git a/crates/brk_computer/src/internal/transform/identity.rs b/crates/brk_computer/src/internal/transform/identity.rs deleted file mode 100644 index 6d387f6f8..000000000 --- a/crates/brk_computer/src/internal/transform/identity.rs +++ /dev/null @@ -1,13 +0,0 @@ -use std::marker::PhantomData; - -use vecdb::{UnaryTransform, VecValue}; - -/// T -> T (identity transform for lazy references) -pub struct Identity(PhantomData); - -impl UnaryTransform for Identity { - #[inline(always)] - fn apply(v: T) -> T { - v - } -} diff --git a/crates/brk_computer/src/internal/transform/mod.rs b/crates/brk_computer/src/internal/transform/mod.rs index c287a410b..6c05187b7 100644 --- a/crates/brk_computer/src/internal/transform/mod.rs +++ b/crates/brk_computer/src/internal/transform/mod.rs @@ -1,43 +1,30 @@ -mod block_count_target; -mod bps_to_float; -mod bps_to_percent; -mod cents_convert; -mod cents_plus; -mod cents_subtract_to_cents_signed; -mod cents_times_tenths; -mod days_to_years; -mod dollars_to_sats_fract; -mod halve; -mod identity; -mod ohlc; -mod per_sec; -mod price_times_ratio_cents; +mod arithmetic; +mod bps; +mod currency; +mod derived; mod ratio; -mod ratio_cents64; -mod return_const; -mod sat_mask; -mod sat_to_bitcoin; -mod sats_to_cents; -mod volatility; +mod specialized; -pub use block_count_target::*; -pub use bps_to_float::*; -pub use bps_to_percent::*; -pub use cents_convert::*; -pub use cents_plus::*; -pub use cents_subtract_to_cents_signed::*; -pub use cents_times_tenths::*; -pub use days_to_years::*; -pub use dollars_to_sats_fract::*; -pub use halve::*; -pub use identity::*; -pub use ohlc::*; -pub use per_sec::*; -pub use price_times_ratio_cents::*; -pub use ratio::*; -pub use ratio_cents64::*; -pub use return_const::*; -pub use sat_mask::*; -pub use sat_to_bitcoin::*; -pub use sats_to_cents::*; -pub use volatility::*; +pub use arithmetic::{ + HalveCents, HalveDollars, HalveSats, HalveSatsToBitcoin, Identity, MaskSats, ReturnF32Tenths, + ReturnI8, ReturnU16, +}; +pub use bps::{ + Bp16ToFloat, Bp16ToPercent, Bp32ToFloat, Bps16ToFloat, Bps16ToPercent, Bps32ToFloat, + Bps32ToPercent, +}; +pub use currency::{ + CentsPlus, CentsSignedToDollars, CentsSubtractToCentsSigned, CentsTimesTenths, + CentsUnsignedToDollars, CentsUnsignedToSats, DollarsToSatsFract, NegCentsUnsignedToDollars, + SatsSignedToBitcoin, SatsToBitcoin, SatsToCents, +}; +pub use derived::{ + Days7, Days30, Days365, DaysToYears, PerSec, PriceTimesRatioBp32Cents, PriceTimesRatioCents, + RatioCents64, TimesSqrt, +}; +pub use ratio::{ + NegRatioDollarsBps16, RatioCentsBp16, RatioCentsSignedCentsBps16, RatioCentsSignedDollarsBps16, + RatioDiffCentsBps32, RatioDiffDollarsBps32, RatioDiffF32Bps32, RatioDollarsBp16, + RatioDollarsBp32, RatioDollarsBps16, RatioSatsBp16, RatioU32Bp16, RatioU64Bp16, +}; +pub use specialized::{BlockCountTarget, OhlcCentsToDollars, OhlcCentsToSats}; diff --git a/crates/brk_computer/src/internal/transform/ohlc.rs b/crates/brk_computer/src/internal/transform/ohlc.rs deleted file mode 100644 index 8e471c150..000000000 --- a/crates/brk_computer/src/internal/transform/ohlc.rs +++ /dev/null @@ -1,28 +0,0 @@ -use brk_types::{Close, High, Low, OHLCCents, OHLCDollars, OHLCSats, Open}; -use vecdb::UnaryTransform; - -use super::CentsUnsignedToSats; - -pub struct OhlcCentsToDollars; - -impl UnaryTransform for OhlcCentsToDollars { - #[inline(always)] - fn apply(cents: OHLCCents) -> OHLCDollars { - OHLCDollars::from(cents) - } -} - -/// OHLCCents -> OHLCSats with high/low swapped (inverse price relationship). -pub struct OhlcCentsToSats; - -impl UnaryTransform for OhlcCentsToSats { - #[inline(always)] - fn apply(cents: OHLCCents) -> OHLCSats { - OHLCSats { - open: Open::new(CentsUnsignedToSats::apply(*cents.open)), - high: High::new(CentsUnsignedToSats::apply(*cents.low)), - low: Low::new(CentsUnsignedToSats::apply(*cents.high)), - close: Close::new(CentsUnsignedToSats::apply(*cents.close)), - } - } -} diff --git a/crates/brk_computer/src/internal/transform/per_sec.rs b/crates/brk_computer/src/internal/transform/per_sec.rs deleted file mode 100644 index 9383f34b1..000000000 --- a/crates/brk_computer/src/internal/transform/per_sec.rs +++ /dev/null @@ -1,17 +0,0 @@ -use brk_types::{StoredF32, StoredU64, Timestamp}; -use vecdb::BinaryTransform; - -/// (StoredU64, Timestamp) -> StoredF32 rate (count / interval_seconds) -pub struct PerSec; - -impl BinaryTransform for PerSec { - #[inline(always)] - fn apply(count: StoredU64, interval: Timestamp) -> StoredF32 { - let interval_f64 = f64::from(*interval); - if interval_f64 > 0.0 { - StoredF32::from(*count as f64 / interval_f64) - } else { - StoredF32::NAN - } - } -} diff --git a/crates/brk_computer/src/internal/transform/price_times_ratio_cents.rs b/crates/brk_computer/src/internal/transform/price_times_ratio_cents.rs deleted file mode 100644 index 9523f0709..000000000 --- a/crates/brk_computer/src/internal/transform/price_times_ratio_cents.rs +++ /dev/null @@ -1,20 +0,0 @@ -use brk_types::{BasisPoints32, Cents, StoredF32}; -use vecdb::BinaryTransform; - -pub struct PriceTimesRatioCents; - -impl BinaryTransform for PriceTimesRatioCents { - #[inline(always)] - fn apply(price: Cents, ratio: StoredF32) -> Cents { - Cents::from(f64::from(price) * f64::from(ratio)) - } -} - -pub struct PriceTimesRatioBp32Cents; - -impl BinaryTransform for PriceTimesRatioBp32Cents { - #[inline(always)] - fn apply(price: Cents, ratio: BasisPoints32) -> Cents { - Cents::from(f64::from(price) * f64::from(ratio)) - } -} diff --git a/crates/brk_computer/src/internal/transform/ratio.rs b/crates/brk_computer/src/internal/transform/ratio.rs index 06062c3a1..d4e6ede96 100644 --- a/crates/brk_computer/src/internal/transform/ratio.rs +++ b/crates/brk_computer/src/internal/transform/ratio.rs @@ -4,9 +4,6 @@ use brk_types::{ }; use vecdb::BinaryTransform; -// === BasisPoints16 (unsigned) ratios === - -/// (StoredU64, StoredU64) -> BasisPoints16 ratio (a/b × 10000) pub struct RatioU64Bp16; impl BinaryTransform for RatioU64Bp16 { @@ -20,7 +17,6 @@ impl BinaryTransform for RatioU64Bp16 { } } -/// (Sats, Sats) -> BasisPoints16 ratio (a/b × 10000) pub struct RatioSatsBp16; impl BinaryTransform for RatioSatsBp16 { @@ -34,7 +30,6 @@ impl BinaryTransform for RatioSatsBp16 { } } -/// (Cents, Cents) -> BasisPoints16 ratio (a/b × 10000) pub struct RatioCentsBp16; impl BinaryTransform for RatioCentsBp16 { @@ -48,7 +43,6 @@ impl BinaryTransform for RatioCentsBp16 { } } -/// (StoredU32, StoredU32) -> BasisPoints16 ratio (a/b × 10000) pub struct RatioU32Bp16; impl BinaryTransform for RatioU32Bp16 { @@ -62,7 +56,6 @@ impl BinaryTransform for RatioU32Bp16 { } } -/// (Dollars, Dollars) -> BasisPoints16 ratio (a/b × 10000) pub struct RatioDollarsBp16; impl BinaryTransform for RatioDollarsBp16 { @@ -77,9 +70,6 @@ impl BinaryTransform for RatioDollarsBp16 { } } -// === BasisPointsSigned16 (signed) ratios === - -/// (Dollars, Dollars) -> BasisPointsSigned16 ratio (a/b × 10000) pub struct RatioDollarsBps16; impl BinaryTransform for RatioDollarsBps16 { @@ -94,7 +84,6 @@ impl BinaryTransform for RatioDollarsBps1 } } -/// (Dollars, Dollars) -> BasisPointsSigned16 negated ratio (-(a/b) × 10000) pub struct NegRatioDollarsBps16; impl BinaryTransform for NegRatioDollarsBps16 { @@ -109,7 +98,6 @@ impl BinaryTransform for NegRatioDollarsB } } -/// (CentsSigned, Cents) -> BasisPointsSigned16 ratio (a/b × 10000) pub struct RatioCentsSignedCentsBps16; impl BinaryTransform for RatioCentsSignedCentsBps16 { @@ -123,7 +111,6 @@ impl BinaryTransform for RatioCentsSign } } -/// (CentsSigned, Dollars) -> BasisPointsSigned16 ratio (a/b × 10000) pub struct RatioCentsSignedDollarsBps16; impl BinaryTransform for RatioCentsSignedDollarsBps16 { @@ -138,9 +125,6 @@ impl BinaryTransform for RatioCentsSi } } -// === BasisPoints32 (unsigned) ratios === - -/// (Dollars, Dollars) -> BasisPoints32 ratio (a / b × 10000) pub struct RatioDollarsBp32; impl BinaryTransform for RatioDollarsBp32 { @@ -150,9 +134,6 @@ impl BinaryTransform for RatioDollarsBp32 { } } -// === BasisPointsSigned32 (signed) ratio diffs === - -/// (StoredF32, StoredF32) -> BasisPointsSigned32 ratio diff ((a/b - 1) × 10000) pub struct RatioDiffF32Bps32; impl BinaryTransform for RatioDiffF32Bps32 { @@ -166,7 +147,6 @@ impl BinaryTransform for RatioDiffF32 } } -/// (Dollars, Dollars) -> BasisPointsSigned32 ratio diff ((a/b - 1) × 10000) pub struct RatioDiffDollarsBps32; impl BinaryTransform for RatioDiffDollarsBps32 { @@ -181,7 +161,6 @@ impl BinaryTransform for RatioDiffDollars } } -/// (Cents, Cents) -> BasisPointsSigned32 ratio diff ((a/b - 1) × 10000) pub struct RatioDiffCentsBps32; impl BinaryTransform for RatioDiffCentsBps32 { diff --git a/crates/brk_computer/src/internal/transform/ratio_cents64.rs b/crates/brk_computer/src/internal/transform/ratio_cents64.rs deleted file mode 100644 index 6984ec202..000000000 --- a/crates/brk_computer/src/internal/transform/ratio_cents64.rs +++ /dev/null @@ -1,17 +0,0 @@ -use brk_types::{Cents, StoredF64}; -use vecdb::BinaryTransform; - -/// (Cents, Cents) -> StoredF64 ratio -/// Used for computing ratios like SOPR where f64 precision is needed. -pub struct RatioCents64; - -impl BinaryTransform for RatioCents64 { - #[inline(always)] - fn apply(numerator: Cents, denominator: Cents) -> StoredF64 { - if denominator == Cents::ZERO { - StoredF64::from(1.0) - } else { - StoredF64::from(numerator.inner() as f64 / denominator.inner() as f64) - } - } -} diff --git a/crates/brk_computer/src/internal/transform/return_const.rs b/crates/brk_computer/src/internal/transform/return_const.rs deleted file mode 100644 index 8e738d88c..000000000 --- a/crates/brk_computer/src/internal/transform/return_const.rs +++ /dev/null @@ -1,32 +0,0 @@ -use brk_types::{StoredF32, StoredI8, StoredU16}; -use vecdb::UnaryTransform; - -/// Returns a constant f32 value from tenths (V=382 -> 38.2), ignoring the input. -pub struct ReturnF32Tenths; - -impl UnaryTransform for ReturnF32Tenths { - #[inline(always)] - fn apply(_: S) -> StoredF32 { - StoredF32::from(V as f32 / 10.0) - } -} - -/// Returns a constant u16 value, ignoring the input. -pub struct ReturnU16; - -impl UnaryTransform for ReturnU16 { - #[inline(always)] - fn apply(_: S) -> StoredU16 { - StoredU16::new(V) - } -} - -/// Returns a constant i8 value, ignoring the input. -pub struct ReturnI8; - -impl UnaryTransform for ReturnI8 { - #[inline(always)] - fn apply(_: S) -> StoredI8 { - StoredI8::new(V) - } -} diff --git a/crates/brk_computer/src/internal/transform/sat_mask.rs b/crates/brk_computer/src/internal/transform/sat_mask.rs deleted file mode 100644 index 7c27155ae..000000000 --- a/crates/brk_computer/src/internal/transform/sat_mask.rs +++ /dev/null @@ -1,17 +0,0 @@ -use brk_types::{Sats, StoredU32}; -use vecdb::BinaryTransform; - -/// (StoredU32, Sats) -> Sats mask -/// Returns value if mask == 1, else 0. Used for pool fee/subsidy from chain data. -pub struct MaskSats; - -impl BinaryTransform for MaskSats { - #[inline(always)] - fn apply(mask: StoredU32, value: Sats) -> Sats { - if mask == StoredU32::ONE { - value - } else { - Sats::ZERO - } - } -} diff --git a/crates/brk_computer/src/internal/transform/sat_to_bitcoin.rs b/crates/brk_computer/src/internal/transform/sat_to_bitcoin.rs deleted file mode 100644 index 2509913b5..000000000 --- a/crates/brk_computer/src/internal/transform/sat_to_bitcoin.rs +++ /dev/null @@ -1,22 +0,0 @@ -use brk_types::{Bitcoin, Sats, SatsSigned}; -use vecdb::UnaryTransform; - -/// Sats -> Bitcoin (divide by 1e8) -pub struct SatsToBitcoin; - -impl UnaryTransform for SatsToBitcoin { - #[inline(always)] - fn apply(sats: Sats) -> Bitcoin { - Bitcoin::from(sats) - } -} - -/// SatsSigned -> Bitcoin (divide by 1e8, preserves sign) -pub struct SatsSignedToBitcoin; - -impl UnaryTransform for SatsSignedToBitcoin { - #[inline(always)] - fn apply(sats: SatsSigned) -> Bitcoin { - Bitcoin::from(sats) - } -} diff --git a/crates/brk_computer/src/internal/transform/sats_to_cents.rs b/crates/brk_computer/src/internal/transform/sats_to_cents.rs deleted file mode 100644 index 6fb7bf58a..000000000 --- a/crates/brk_computer/src/internal/transform/sats_to_cents.rs +++ /dev/null @@ -1,13 +0,0 @@ -use brk_types::{Cents, Sats}; -use vecdb::BinaryTransform; - -/// Sats × Cents → Cents (sats × price_cents / 1e8) -/// Uses u128 intermediate to avoid overflow. -pub struct SatsToCents; - -impl BinaryTransform for SatsToCents { - #[inline(always)] - fn apply(sats: Sats, price_cents: Cents) -> Cents { - Cents::from(sats.as_u128() * price_cents.as_u128() / Sats::ONE_BTC_U128) - } -} diff --git a/crates/brk_computer/src/internal/transform/block_count_target.rs b/crates/brk_computer/src/internal/transform/specialized.rs similarity index 72% rename from crates/brk_computer/src/internal/transform/block_count_target.rs rename to crates/brk_computer/src/internal/transform/specialized.rs index 88d5b569e..8fded075f 100644 --- a/crates/brk_computer/src/internal/transform/block_count_target.rs +++ b/crates/brk_computer/src/internal/transform/specialized.rs @@ -1,16 +1,17 @@ use brk_types::{ - Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour12, Hour4, - Minute10, Minute30, Month1, Month3, Month6, StoredU64, Week1, Year1, Year10, + Close, Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, High, Hour1, Hour4, Hour12, Low, + Minute10, Minute30, Month1, Month3, Month6, OHLCCents, OHLCDollars, OHLCSats, Open, StoredU64, + Week1, Year1, Year10, }; use vecdb::UnaryTransform; +use super::CentsUnsignedToSats; use crate::blocks::{ TARGET_BLOCKS_PER_DAY, TARGET_BLOCKS_PER_DAY3, TARGET_BLOCKS_PER_DECADE, - TARGET_BLOCKS_PER_HALVING, TARGET_BLOCKS_PER_HOUR1, TARGET_BLOCKS_PER_HOUR12, - TARGET_BLOCKS_PER_HOUR4, TARGET_BLOCKS_PER_MINUTE10, - TARGET_BLOCKS_PER_MINUTE30, TARGET_BLOCKS_PER_MONTH, - TARGET_BLOCKS_PER_QUARTER, TARGET_BLOCKS_PER_SEMESTER, TARGET_BLOCKS_PER_WEEK, - TARGET_BLOCKS_PER_YEAR, + TARGET_BLOCKS_PER_HALVING, TARGET_BLOCKS_PER_HOUR1, TARGET_BLOCKS_PER_HOUR4, + TARGET_BLOCKS_PER_HOUR12, TARGET_BLOCKS_PER_MINUTE10, TARGET_BLOCKS_PER_MINUTE30, + TARGET_BLOCKS_PER_MONTH, TARGET_BLOCKS_PER_QUARTER, TARGET_BLOCKS_PER_SEMESTER, + TARGET_BLOCKS_PER_WEEK, TARGET_BLOCKS_PER_YEAR, }; pub struct BlockCountTarget; @@ -126,3 +127,26 @@ impl UnaryTransform for BlockCountTarget { StoredU64::from(2016u64) } } + +pub struct OhlcCentsToDollars; + +impl UnaryTransform for OhlcCentsToDollars { + #[inline(always)] + fn apply(cents: OHLCCents) -> OHLCDollars { + OHLCDollars::from(cents) + } +} + +pub struct OhlcCentsToSats; + +impl UnaryTransform for OhlcCentsToSats { + #[inline(always)] + fn apply(cents: OHLCCents) -> OHLCSats { + OHLCSats { + open: Open::new(CentsUnsignedToSats::apply(*cents.open)), + high: High::new(CentsUnsignedToSats::apply(*cents.low)), + low: Low::new(CentsUnsignedToSats::apply(*cents.high)), + close: Close::new(CentsUnsignedToSats::apply(*cents.close)), + } + } +} diff --git a/crates/brk_computer/src/internal/transform/volatility.rs b/crates/brk_computer/src/internal/transform/volatility.rs deleted file mode 100644 index 8b280e403..000000000 --- a/crates/brk_computer/src/internal/transform/volatility.rs +++ /dev/null @@ -1,33 +0,0 @@ -use std::marker::PhantomData; - -use brk_types::StoredF32; -use vecdb::UnaryTransform; - -pub trait SqrtDays { - const FACTOR: f32; -} - -pub struct Days7; -impl SqrtDays for Days7 { - const FACTOR: f32 = 2.6457513; // 7.0_f32.sqrt() -} - -pub struct Days30; -impl SqrtDays for Days30 { - const FACTOR: f32 = 5.477226; // 30.0_f32.sqrt() -} - -pub struct Days365; -impl SqrtDays for Days365 { - const FACTOR: f32 = 19.104973; // 365.0_f32.sqrt() -} - -/// StoredF32 × sqrt(D) -> StoredF32 (annualize daily volatility to D-day period) -pub struct TimesSqrt(PhantomData); - -impl UnaryTransform for TimesSqrt { - #[inline(always)] - fn apply(v: StoredF32) -> StoredF32 { - (*v * D::FACTOR).into() - } -} diff --git a/crates/brk_computer/src/internal/value.rs b/crates/brk_computer/src/internal/value.rs index 7466ad9cf..b040548e4 100644 --- a/crates/brk_computer/src/internal/value.rs +++ b/crates/brk_computer/src/internal/value.rs @@ -11,7 +11,10 @@ use vecdb::{ StorageMode, VecIndex, }; -use crate::{internal::{CentsUnsignedToDollars, SatsToBitcoin, SatsToCents}, prices}; +use crate::{ + internal::{CentsUnsignedToDollars, SatsToBitcoin, SatsToCents}, + prices, +}; const VERSION: Version = Version::TWO; // Match ValueFromHeight versioning @@ -24,11 +27,7 @@ pub struct Value { } impl Value { - pub(crate) fn forced_import( - db: &Database, - name: &str, - version: Version, - ) -> Result { + pub(crate) fn forced_import(db: &Database, name: &str, version: Version) -> Result { let v = version + VERSION; let sats: EagerVec> = EagerVec::forced_import(db, name, v)?; @@ -45,7 +44,12 @@ impl Value { cents.read_only_boxed_clone(), ); - Ok(Self { sats, btc, cents, usd }) + Ok(Self { + sats, + btc, + cents, + usd, + }) } /// Eagerly compute cents height values: sats[h] * price_cents[h] / 1e8. diff --git a/crates/brk_computer/src/lib.rs b/crates/brk_computer/src/lib.rs index 39d2f2893..c4e26d867 100644 --- a/crates/brk_computer/src/lib.rs +++ b/crates/brk_computer/src/lib.rs @@ -25,10 +25,8 @@ mod positions; pub mod prices; mod scripts; mod supply; -mod traits; mod transactions; - #[derive(Traversable)] pub struct Computer { pub blocks: Box>, @@ -51,7 +49,6 @@ pub struct Computer { const VERSION: Version = Version::new(5); impl Computer { - /// Do NOT import multiple times or things will break !!! pub fn forced_import(outputs_path: &Path, indexer: &Indexer) -> Result { info!("Importing computer..."); let import_start = Instant::now(); @@ -61,152 +58,143 @@ impl Computer { const STACK_SIZE: usize = 8 * 1024 * 1024; let big_thread = || thread::Builder::new().stack_size(STACK_SIZE); - let i = Instant::now(); - let (indexes, positions) = thread::scope(|s| -> Result<_> { - let positions_handle = big_thread().spawn_scoped(s, || -> Result<_> { - Ok(Box::new(positions::Vecs::forced_import( + let (indexes, positions) = timed("Imported indexes/positions", || { + thread::scope(|s| -> Result<_> { + let positions_handle = big_thread().spawn_scoped(s, || -> Result<_> { + Ok(Box::new(positions::Vecs::forced_import( + &computed_path, + VERSION, + )?)) + })?; + + let indexes = Box::new(indexes::Vecs::forced_import( &computed_path, VERSION, - )?)) - })?; + indexer, + )?); + let positions = positions_handle.join().unwrap()?; - let indexes = Box::new(indexes::Vecs::forced_import( + Ok((indexes, positions)) + }) + })?; + + let (inputs, outputs) = timed("Imported inputs/outputs", || { + thread::scope(|s| -> Result<_> { + let inputs_handle = big_thread().spawn_scoped(s, || -> Result<_> { + Ok(Box::new(inputs::Vecs::forced_import( + &computed_path, + VERSION, + &indexes, + )?)) + })?; + + let outputs_handle = big_thread().spawn_scoped(s, || -> Result<_> { + Ok(Box::new(outputs::Vecs::forced_import( + &computed_path, + VERSION, + &indexes, + )?)) + })?; + + let inputs = inputs_handle.join().unwrap()?; + let outputs = outputs_handle.join().unwrap()?; + + Ok((inputs, outputs)) + }) + })?; + + let (constants, prices) = timed("Imported prices/constants", || -> Result<_> { + let constants = Box::new(constants::Vecs::new(VERSION, &indexes)); + let prices = Box::new(prices::Vecs::forced_import( &computed_path, VERSION, - indexer, + &indexes, )?); - let positions = positions_handle.join().unwrap()?; - - Ok((indexes, positions)) + Ok((constants, prices)) })?; - info!("Imported indexes/positions in {:?}", i.elapsed()); - // inputs/outputs need indexes for count imports - let i = Instant::now(); - let (inputs, outputs) = thread::scope(|s| -> Result<_> { - let inputs_handle = big_thread().spawn_scoped(s, || -> Result<_> { - Ok(Box::new(inputs::Vecs::forced_import( - &computed_path, - VERSION, - &indexes, - )?)) - })?; - - let outputs_handle = big_thread().spawn_scoped(s, || -> Result<_> { - Ok(Box::new(outputs::Vecs::forced_import( - &computed_path, - VERSION, - &indexes, - )?)) - })?; - - let inputs = inputs_handle.join().unwrap()?; - let outputs = outputs_handle.join().unwrap()?; - - Ok((inputs, outputs)) - })?; - info!("Imported inputs/outputs in {:?}", i.elapsed()); - - let i = Instant::now(); - let constants = Box::new(constants::Vecs::new(VERSION, &indexes)); - // Price must be created before market since market's lazy vecs reference price - let prices = Box::new(prices::Vecs::forced_import( - &computed_path, - VERSION, - &indexes, - )?); - info!("Imported price/constants in {:?}", i.elapsed()); - - let i = Instant::now(); let (blocks, mining, transactions, scripts, pools, cointime) = - thread::scope(|s| -> Result<_> { - // Import blocks module (no longer needs prices) - let blocks_handle = big_thread().spawn_scoped(s, || -> Result<_> { - Ok(Box::new(blocks::Vecs::forced_import( - &computed_path, - VERSION, - indexer, - &indexes, - )?)) - })?; + timed("Imported blocks/mining/tx/scripts/pools/cointime", || { + thread::scope(|s| -> Result<_> { + let blocks_handle = big_thread().spawn_scoped(s, || -> Result<_> { + Ok(Box::new(blocks::Vecs::forced_import( + &computed_path, + VERSION, + indexer, + &indexes, + )?)) + })?; - // Import mining module (separate database) - let mining_handle = big_thread().spawn_scoped(s, || -> Result<_> { - Ok(Box::new(mining::Vecs::forced_import( + let mining_handle = big_thread().spawn_scoped(s, || -> Result<_> { + Ok(Box::new(mining::Vecs::forced_import( + &computed_path, + VERSION, + &indexes, + )?)) + })?; + + let transactions_handle = big_thread().spawn_scoped(s, || -> Result<_> { + Ok(Box::new(transactions::Vecs::forced_import( + &computed_path, + VERSION, + indexer, + &indexes, + )?)) + })?; + + let scripts_handle = big_thread().spawn_scoped(s, || -> Result<_> { + Ok(Box::new(scripts::Vecs::forced_import( + &computed_path, + VERSION, + &indexes, + )?)) + })?; + + let cointime = Box::new(cointime::Vecs::forced_import( &computed_path, VERSION, &indexes, - )?)) - })?; + )?); - // Import transactions module - let transactions_handle = big_thread().spawn_scoped(s, || -> Result<_> { - Ok(Box::new(transactions::Vecs::forced_import( - &computed_path, - VERSION, - indexer, - &indexes, - )?)) - })?; + let blocks = blocks_handle.join().unwrap()?; + let mining = mining_handle.join().unwrap()?; + let transactions = transactions_handle.join().unwrap()?; + let scripts = scripts_handle.join().unwrap()?; - let scripts_handle = big_thread().spawn_scoped(s, || -> Result<_> { - Ok(Box::new(scripts::Vecs::forced_import( + let pools = Box::new(pools::Vecs::forced_import( &computed_path, VERSION, &indexes, - )?)) - })?; + )?); - let cointime = Box::new(cointime::Vecs::forced_import( - &computed_path, - VERSION, - &indexes, - )?); - - let blocks = blocks_handle.join().unwrap()?; - let mining = mining_handle.join().unwrap()?; - let transactions = transactions_handle.join().unwrap()?; - let scripts = scripts_handle.join().unwrap()?; - - let pools = Box::new(pools::Vecs::forced_import( - &computed_path, - VERSION, - &indexes, - )?); - - Ok((blocks, mining, transactions, scripts, pools, cointime)) + Ok((blocks, mining, transactions, scripts, pools, cointime)) + }) })?; - info!( - "Imported blocks/mining/transactions/scripts/pools/cointime in {:?}", - i.elapsed() - ); - // Threads inside - let i = Instant::now(); - let distribution = Box::new(distribution::Vecs::forced_import( - &computed_path, - VERSION, - &indexes, - )?); - info!("Imported distribution in {:?}", i.elapsed()); + let distribution = timed("Imported distribution", || -> Result<_> { + Ok(Box::new(distribution::Vecs::forced_import( + &computed_path, + VERSION, + &indexes, + )?)) + })?; - // Supply must be imported after distribution (references distribution's supply) - let i = Instant::now(); - let supply = Box::new(supply::Vecs::forced_import( - &computed_path, - VERSION, - &indexes, - &distribution, - )?); - info!("Imported supply in {:?}", i.elapsed()); + let supply = timed("Imported supply", || -> Result<_> { + Ok(Box::new(supply::Vecs::forced_import( + &computed_path, + VERSION, + &indexes, + &distribution, + )?)) + })?; - let i = Instant::now(); - let market = Box::new(market::Vecs::forced_import( - &computed_path, - VERSION, - &indexes, - )?); - info!("Imported market in {:?}", i.elapsed()); + let market = timed("Imported market", || -> Result<_> { + Ok(Box::new(market::Vecs::forced_import( + &computed_path, + VERSION, + &indexes, + )?)) + })?; info!("Total import time: {:?}", import_start.elapsed()); @@ -284,201 +272,169 @@ impl Computer { ) -> Result<()> { let compute_start = Instant::now(); - // 1. Indexes (absorbs blocks.time.compute — timestamp_monotonic) - info!("Computing indexes..."); - let i = Instant::now(); - let mut starting_indexes = + let mut starting_indexes = timed("Computed indexes", || { self.indexes - .compute(indexer, &mut self.blocks, starting_indexes, exit)?; - info!("Computed indexes in {:?}", i.elapsed()); + .compute(indexer, &mut self.blocks, starting_indexes, exit) + })?; - // 2. Prices - info!("Computing prices..."); - let i = Instant::now(); - self.prices - .compute(indexer, &self.indexes, &starting_indexes, exit)?; - info!("Computed prices in {:?}", i.elapsed()); + timed("Computed prices", || { + self.prices + .compute(indexer, &self.indexes, &starting_indexes, exit) + })?; - // 3. Main scope thread::scope(|scope| -> Result<()> { - let positions = scope.spawn(|| -> Result<()> { - info!("Computing positions metadata..."); - let i = Instant::now(); - self.positions - .compute(indexer, &starting_indexes, reader, exit)?; - info!("Computed positions in {:?}", i.elapsed()); - Ok(()) + let positions = scope.spawn(|| { + timed("Computed positions", || { + self.positions + .compute(indexer, &starting_indexes, reader, exit) + }) }); - // Blocks first (needed for window starts used by scripts, transactions, etc.) - info!("Computing blocks..."); - let i = Instant::now(); - self.blocks - .compute(indexer, &self.indexes, &starting_indexes, exit)?; - info!("Computed blocks in {:?}", i.elapsed()); + timed("Computed blocks", || { + self.blocks + .compute(indexer, &self.indexes, &starting_indexes, exit) + })?; - // Inputs → scripts → outputs (sequential) - info!("Computing inputs..."); - let i = Instant::now(); - self.inputs.compute( - indexer, - &self.indexes, - &self.blocks, - &starting_indexes, - exit, - )?; - info!("Computed inputs in {:?}", i.elapsed()); + timed("Computed inputs", || { + self.inputs.compute( + indexer, + &self.indexes, + &self.blocks, + &starting_indexes, + exit, + ) + })?; - info!("Computing scripts..."); - let i = Instant::now(); - self.scripts.compute( - indexer, - &self.blocks, - &self.outputs, - &self.prices, - &starting_indexes, - exit, - )?; - info!("Computed scripts in {:?}", i.elapsed()); + timed("Computed scripts", || { + self.scripts.compute( + indexer, + &self.blocks, + &self.outputs, + &self.prices, + &starting_indexes, + exit, + ) + })?; - info!("Computing outputs..."); - let i = Instant::now(); - self.outputs.compute( - indexer, - &self.indexes, - &self.inputs, - &self.scripts, - &self.blocks, - &starting_indexes, - exit, - )?; - info!("Computed outputs in {:?}", i.elapsed()); + timed("Computed outputs", || { + self.outputs.compute( + indexer, + &self.indexes, + &self.inputs, + &self.scripts, + &self.blocks, + &starting_indexes, + exit, + ) + })?; - // Transactions (needs blocks for count/interval, prices for USD conversion) - info!("Computing transactions..."); - let i = Instant::now(); - self.transactions.compute( - indexer, - &self.indexes, - &self.blocks, - &self.inputs, - &self.outputs, - &self.prices, - &starting_indexes, - exit, - )?; - info!("Computed transactions in {:?}", i.elapsed()); + timed("Computed transactions", || { + self.transactions.compute( + indexer, + &self.indexes, + &self.blocks, + &self.inputs, + &self.outputs, + &self.prices, + &starting_indexes, + exit, + ) + })?; - // Mining (needs blocks + transactions) - info!("Computing mining..."); - let i = Instant::now(); - self.mining.compute( - indexer, - &self.indexes, - &self.blocks, - &self.transactions, - &self.prices, - &starting_indexes, - exit, - )?; - info!("Computed mining in {:?}", i.elapsed()); + timed("Computed mining", || { + self.mining.compute( + indexer, + &self.indexes, + &self.blocks, + &self.transactions, + &self.prices, + &starting_indexes, + exit, + ) + })?; positions.join().unwrap()?; Ok(()) })?; - if true { - return Ok(()); - } - - // 4. Pools || distribution let starting_indexes_clone = starting_indexes.clone(); thread::scope(|scope| -> Result<()> { - let pools = scope.spawn(|| -> Result<()> { - info!("Computing pools..."); - let i = Instant::now(); - self.pools.compute( - indexer, - &self.indexes, - &self.blocks, - &self.prices, - &self.mining, - &starting_indexes_clone, - exit, - )?; - info!("Computed pools in {:?}", i.elapsed()); - Ok(()) + let pools = scope.spawn(|| { + timed("Computed pools", || { + self.pools.compute( + indexer, + &self.indexes, + &self.blocks, + &self.prices, + &self.mining, + &starting_indexes_clone, + exit, + ) + }) }); - info!("Computing distribution..."); - let i = Instant::now(); - self.distribution.compute( - indexer, - &self.indexes, - &self.inputs, - &self.outputs, - &self.transactions, - &self.blocks, - &self.prices, - &mut starting_indexes, - exit, - )?; - info!("Computed distribution in {:?}", i.elapsed()); + timed("Computed distribution", || { + self.distribution.compute( + indexer, + &self.indexes, + &self.inputs, + &self.outputs, + &self.transactions, + &self.blocks, + &self.prices, + &mut starting_indexes, + exit, + ) + })?; pools.join().unwrap()?; Ok(()) })?; - // 5. Market and supply are independent — both depend on distribution but not each other thread::scope(|scope| -> Result<()> { - let market = scope.spawn(|| -> Result<()> { - info!("Computing market..."); - let i = Instant::now(); - self.market.compute( - &self.indexes, - &self.prices, - &self.blocks, - &self.mining, - &self.distribution, - &self.transactions, - &starting_indexes, - exit, - )?; - info!("Computed market in {:?}", i.elapsed()); - Ok(()) + let market = scope.spawn(|| { + timed("Computed market", || { + self.market.compute( + &self.indexes, + &self.prices, + &self.blocks, + &self.mining, + &self.distribution, + &self.transactions, + &starting_indexes, + exit, + ) + }) }); - info!("Computing supply..."); - let i = Instant::now(); - self.supply.compute( - &self.scripts, - &self.blocks, - &self.mining, - &self.transactions, - &self.prices, - &self.distribution, - &starting_indexes, - exit, - )?; - info!("Computed supply in {:?}", i.elapsed()); + timed("Computed supply", || { + self.supply.compute( + &self.scripts, + &self.blocks, + &self.mining, + &self.transactions, + &self.prices, + &self.distribution, + &starting_indexes, + exit, + ) + })?; market.join().unwrap()?; Ok(()) })?; - // 6. Cointime (depends on supply, distribution, mining) - info!("Computing cointime..."); - let i = Instant::now(); - self.cointime.compute( - &starting_indexes, - &self.prices, - &self.blocks, - &self.mining, - &self.supply, - &self.distribution, - exit, - )?; - info!("Computed cointime in {:?}", i.elapsed()); + timed("Computed cointime", || { + self.cointime.compute( + &starting_indexes, + &self.prices, + &self.blocks, + &self.mining, + &self.supply, + &self.distribution, + exit, + ) + })?; info!("Total compute time: {:?}", compute_start.elapsed()); Ok(()) @@ -492,81 +448,36 @@ impl Computer { ) -> impl Iterator { use brk_traversable::Traversable; - std::iter::empty() - .chain( - self.blocks - .iter_any_exportable() - .map(|v| (blocks::DB_NAME, v)), - ) - .chain( - self.mining - .iter_any_exportable() - .map(|v| (mining::DB_NAME, v)), - ) - .chain( - self.transactions - .iter_any_exportable() - .map(|v| (transactions::DB_NAME, v)), - ) - .chain( - self.scripts - .iter_any_exportable() - .map(|v| (scripts::DB_NAME, v)), - ) - .chain( - self.positions - .iter_any_exportable() - .map(|v| (positions::DB_NAME, v)), - ) - .chain( - self.cointime - .iter_any_exportable() - .map(|v| (cointime::DB_NAME, v)), - ) - .chain( - self.constants - .iter_any_exportable() - .map(|v| (constants::DB_NAME, v)), - ) - .chain( - self.indexes - .iter_any_exportable() - .map(|v| (indexes::DB_NAME, v)), - ) - .chain( - self.market - .iter_any_exportable() - .map(|v| (market::DB_NAME, v)), - ) - .chain( - self.pools - .iter_any_exportable() - .map(|v| (pools::DB_NAME, v)), - ) - .chain( - self.prices - .iter_any_exportable() - .map(|v| (prices::DB_NAME, v)), - ) - .chain( - self.distribution - .iter_any_exportable() - .map(|v| (distribution::DB_NAME, v)), - ) - .chain( - self.supply - .iter_any_exportable() - .map(|v| (supply::DB_NAME, v)), - ) - .chain( - self.inputs - .iter_any_exportable() - .map(|v| (inputs::DB_NAME, v)), - ) - .chain( - self.outputs - .iter_any_exportable() - .map(|v| (outputs::DB_NAME, v)), - ) + macro_rules! named { + ($($field:ident),+ $(,)?) => { + std::iter::empty() + $(.chain(self.$field.iter_any_exportable().map(|v| ($field::DB_NAME, v))))+ + }; + } + + named!( + blocks, + mining, + transactions, + scripts, + positions, + cointime, + constants, + indexes, + market, + pools, + prices, + distribution, + supply, + inputs, + outputs, + ) } } + +fn timed(label: &str, f: impl FnOnce() -> T) -> T { + let start = Instant::now(); + let result = f(); + info!("{label} in {:?}", start.elapsed()); + result +} diff --git a/crates/brk_computer/src/market/ath/import.rs b/crates/brk_computer/src/market/ath/import.rs index 49620fce8..4e13e0037 100644 --- a/crates/brk_computer/src/market/ath/import.rs +++ b/crates/brk_computer/src/market/ath/import.rs @@ -23,12 +23,11 @@ impl Vecs { let max_days_between_price_ath = ComputedFromHeight::forced_import(db, "max_days_between_price_ath", v, indexes)?; - let max_years_between_price_ath = - LazyHeightDerived::from_computed::( - "max_years_between_price_ath", - v, - &max_days_between_price_ath, - ); + let max_years_between_price_ath = LazyHeightDerived::from_computed::( + "max_years_between_price_ath", + v, + &max_days_between_price_ath, + ); let days_since_price_ath = ComputedFromHeight::forced_import(db, "days_since_price_ath", v, indexes)?; @@ -39,8 +38,7 @@ impl Vecs { &days_since_price_ath, ); - let price_drawdown = - PercentFromHeight::forced_import(db, "price_drawdown", v, indexes)?; + let price_drawdown = PercentFromHeight::forced_import(db, "price_drawdown", v, indexes)?; Ok(Self { price_ath, diff --git a/crates/brk_computer/src/market/compute.rs b/crates/brk_computer/src/market/compute.rs index 8d033a453..5fd95ebee 100644 --- a/crates/brk_computer/src/market/compute.rs +++ b/crates/brk_computer/src/market/compute.rs @@ -34,16 +34,21 @@ impl Vecs { .compute(&self.returns, starting_indexes.height, exit)?; // Range metrics (independent) - self.range - .compute(prices, blocks, starting_indexes, exit)?; + self.range.compute(prices, blocks, starting_indexes, exit)?; // Moving average metrics (independent) self.moving_average .compute(blocks, prices, starting_indexes, exit)?; // DCA metrics (depends on lookback for lump sum comparison) - self.dca - .compute(indexes, prices, blocks, &self.lookback, starting_indexes, exit)?; + self.dca.compute( + indexes, + prices, + blocks, + &self.lookback, + starting_indexes, + exit, + )?; self.indicators.compute( &mining.rewards, diff --git a/crates/brk_computer/src/market/dca/by_period.rs b/crates/brk_computer/src/market/dca/by_period.rs index 83db063cc..01462f2d0 100644 --- a/crates/brk_computer/src/market/dca/by_period.rs +++ b/crates/brk_computer/src/market/dca/by_period.rs @@ -171,7 +171,6 @@ impl ByDcaPeriod { ] .into_iter() } - } /// Generic wrapper for DCA CAGR data (periods >= 2 years) diff --git a/crates/brk_computer/src/market/dca/compute.rs b/crates/brk_computer/src/market/dca/compute.rs index 9cde2b38a..ce901c9be 100644 --- a/crates/brk_computer/src/market/dca/compute.rs +++ b/crates/brk_computer/src/market/dca/compute.rs @@ -3,9 +3,7 @@ use brk_types::{BasisPointsSigned32, Bitcoin, Cents, Date, Day1, Dollars, Indexe use vecdb::{AnyVec, Exit, ReadableOptionVec, ReadableVec, VecIndex}; use super::Vecs; -use crate::{ - blocks, indexes, internal::RatioDiffCentsBps32, market::lookback, prices, -}; +use crate::{blocks, indexes, internal::RatioDiffCentsBps32, market::lookback, prices}; const DCA_AMOUNT: Dollars = Dollars::mint(100.0); @@ -64,9 +62,8 @@ impl Vecs { // DCA by period - average price (derived from stack) let sh = starting_indexes.height.to_usize(); - for (average_price, stack, days) in self - .period_cost_basis - .zip_mut_with_days(&self.period_stack) + for (average_price, stack, days) in + self.period_cost_basis.zip_mut_with_days(&self.period_stack) { let days = days as usize; let stack_data = stack diff --git a/crates/brk_computer/src/market/dca/import.rs b/crates/brk_computer/src/market/dca/import.rs index 0e94e6cd3..448233fb0 100644 --- a/crates/brk_computer/src/market/dca/import.rs +++ b/crates/brk_computer/src/market/dca/import.rs @@ -23,21 +23,11 @@ impl Vecs { })?; let period_return = ByDcaPeriod::try_new(|name, _days| { - PercentFromHeight::forced_import( - db, - &format!("dca_return_{name}"), - version, - indexes, - ) + PercentFromHeight::forced_import(db, &format!("dca_return_{name}"), version, indexes) })?; let period_cagr = ByDcaCagr::try_new(|name, _days| { - PercentFromHeight::forced_import( - db, - &format!("dca_cagr_{name}"), - version, - indexes, - ) + PercentFromHeight::forced_import(db, &format!("dca_cagr_{name}"), version, indexes) })?; let period_lump_sum_stack = ByDcaPeriod::try_new(|name, _days| { @@ -62,12 +52,7 @@ impl Vecs { })?; let class_return = ByDcaClass::try_new(|name, _year, _day1| { - PercentFromHeight::forced_import( - db, - &format!("dca_return_{name}"), - version, - indexes, - ) + PercentFromHeight::forced_import(db, &format!("dca_return_{name}"), version, indexes) })?; Ok(Self { diff --git a/crates/brk_computer/src/market/dca/vecs.rs b/crates/brk_computer/src/market/dca/vecs.rs index c07d9d960..0703320c2 100644 --- a/crates/brk_computer/src/market/dca/vecs.rs +++ b/crates/brk_computer/src/market/dca/vecs.rs @@ -4,8 +4,6 @@ use vecdb::{EagerVec, PcoVec, Rw, StorageMode}; use super::{ByDcaCagr, ByDcaClass, ByDcaPeriod}; use crate::internal::{ComputedFromHeight, PercentFromHeight, Price, ValueFromHeight}; - -/// Dollar-cost averaging metrics by time period and year class #[derive(Traversable)] pub struct Vecs { /// Per-height DCA sats contribution: sats_from_dca(close) on day boundaries, 0 otherwise. diff --git a/crates/brk_computer/src/market/import.rs b/crates/brk_computer/src/market/import.rs index 952297921..6f04a6f34 100644 --- a/crates/brk_computer/src/market/import.rs +++ b/crates/brk_computer/src/market/import.rs @@ -1,11 +1,12 @@ use std::path::Path; use brk_error::Result; -use brk_traversable::Traversable; use brk_types::Version; -use vecdb::{Database, PAGE_SIZE}; -use crate::indexes; +use crate::{ + indexes, + internal::{finalize_db, open_db}, +}; use super::{ AthVecs, DcaVecs, IndicatorsVecs, LookbackVecs, MovingAverageVecs, RangeVecs, ReturnsVecs, @@ -18,9 +19,7 @@ impl Vecs { parent_version: Version, indexes: &indexes::Vecs, ) -> Result { - let db = Database::open(&parent_path.join(super::DB_NAME))?; - db.set_min_len(PAGE_SIZE * 1_000_000)?; - + let db = open_db(parent_path, super::DB_NAME, 1_000_000)?; let version = parent_version; let ath = AthVecs::forced_import(&db, version, indexes)?; @@ -30,11 +29,7 @@ impl Vecs { let range = RangeVecs::forced_import(&db, version, indexes)?; let moving_average = MovingAverageVecs::forced_import(&db, version, indexes)?; let dca = DcaVecs::forced_import(&db, version, indexes)?; - let indicators = IndicatorsVecs::forced_import( - &db, - version, - indexes, - )?; + let indicators = IndicatorsVecs::forced_import(&db, version, indexes)?; let this = Self { db, @@ -47,14 +42,7 @@ impl Vecs { dca, indicators, }; - - this.db.retain_regions( - this.iter_any_exportable() - .flat_map(|v| v.region_names()) - .collect(), - )?; - this.db.compact()?; - + finalize_db(&this.db, &this)?; Ok(this) } } diff --git a/crates/brk_computer/src/market/indicators/gini.rs b/crates/brk_computer/src/market/indicators/gini.rs index 715bf988d..952680a5d 100644 --- a/crates/brk_computer/src/market/indicators/gini.rs +++ b/crates/brk_computer/src/market/indicators/gini.rs @@ -32,10 +32,15 @@ pub(super) fn compute( .iter() .fold(Version::ZERO, |acc, v| acc + v.version()); - gini.bps.height + gini.bps + .height .validate_computed_version_or_reset(source_version)?; - gini.bps.height - .truncate_if_needed_at(gini.bps.height.len().min(starting_indexes.height.to_usize()))?; + gini.bps.height.truncate_if_needed_at( + gini.bps + .height + .len() + .min(starting_indexes.height.to_usize()), + )?; let total_heights = supply_vecs .iter() @@ -68,8 +73,7 @@ pub(super) fn compute( let count: u64 = count_data[c][offset].into(); buckets.push((count, supply)); } - gini.bps.height - .push(gini_from_lorenz(&buckets)); + gini.bps.height.push(gini_from_lorenz(&buckets)); } { diff --git a/crates/brk_computer/src/market/indicators/import.rs b/crates/brk_computer/src/market/indicators/import.rs index 6cce6cf1a..62886f606 100644 --- a/crates/brk_computer/src/market/indicators/import.rs +++ b/crates/brk_computer/src/market/indicators/import.rs @@ -5,10 +5,7 @@ use vecdb::Database; use super::{MacdChain, RsiChain, Vecs}; use crate::{ indexes, - internal::{ - ComputedFromHeight, ComputedFromHeightRatio, - PercentFromHeight, Windows, - }, + internal::{ComputedFromHeight, ComputedFromHeightRatio, PercentFromHeight, Windows}, }; const VERSION: Version = Version::ONE; @@ -45,12 +42,7 @@ impl RsiChain { let average_gain = import!("average_gain"); let average_loss = import!("average_loss"); - let rsi = PercentFromHeight::forced_import( - db, - &format!("rsi_{tf}"), - version, - indexes, - )?; + let rsi = PercentFromHeight::forced_import(db, &format!("rsi_{tf}"), version, indexes)?; Ok(Self { gains: import!("gains"), @@ -74,18 +66,10 @@ impl MacdChain { version: Version, indexes: &indexes::Vecs, ) -> Result { - let line = ComputedFromHeight::forced_import( - db, - &format!("macd_line_{tf}"), - version, - indexes, - )?; - let signal = ComputedFromHeight::forced_import( - db, - &format!("macd_signal_{tf}"), - version, - indexes, - )?; + let line = + ComputedFromHeight::forced_import(db, &format!("macd_line_{tf}"), version, indexes)?; + let signal = + ComputedFromHeight::forced_import(db, &format!("macd_signal_{tf}"), version, indexes)?; let histogram = ComputedFromHeight::forced_import( db, @@ -134,7 +118,12 @@ impl Vecs { let pi_cycle = ComputedFromHeightRatio::forced_import_raw(db, "pi_cycle", v, indexes)?; Ok(Self { - puell_multiple: ComputedFromHeightRatio::forced_import_raw(db, "puell_multiple", v, indexes)?, + puell_multiple: ComputedFromHeightRatio::forced_import_raw( + db, + "puell_multiple", + v, + indexes, + )?, nvt, rsi, stoch_k, diff --git a/crates/brk_computer/src/market/lookback/by_period.rs b/crates/brk_computer/src/market/lookback/by_period.rs index a43df7a16..f2fe102f4 100644 --- a/crates/brk_computer/src/market/lookback/by_period.rs +++ b/crates/brk_computer/src/market/lookback/by_period.rs @@ -135,5 +135,4 @@ impl ByLookbackPeriod { _10y: &self._10y, } } - } diff --git a/crates/brk_computer/src/market/lookback/import.rs b/crates/brk_computer/src/market/lookback/import.rs index 989bfa8c8..68fb481b6 100644 --- a/crates/brk_computer/src/market/lookback/import.rs +++ b/crates/brk_computer/src/market/lookback/import.rs @@ -6,7 +6,11 @@ use super::{ByLookbackPeriod, Vecs}; use crate::{indexes, internal::Price}; impl Vecs { - pub(crate) fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { + pub(crate) fn forced_import( + db: &Database, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { let price_lookback = ByLookbackPeriod::try_new(|name, _days| { Price::forced_import(db, &format!("price_lookback_{name}"), version, indexes) })?; diff --git a/crates/brk_computer/src/market/lookback/vecs.rs b/crates/brk_computer/src/market/lookback/vecs.rs index 404100bf0..b92d17138 100644 --- a/crates/brk_computer/src/market/lookback/vecs.rs +++ b/crates/brk_computer/src/market/lookback/vecs.rs @@ -4,8 +4,6 @@ use vecdb::{Rw, StorageMode}; use super::ByLookbackPeriod; use crate::internal::{ComputedFromHeight, Price}; - -/// Price lookback metrics #[derive(Traversable)] pub struct Vecs { #[traversable(flatten)] diff --git a/crates/brk_computer/src/market/mod.rs b/crates/brk_computer/src/market/mod.rs index bf1fd025e..df2db2562 100644 --- a/crates/brk_computer/src/market/mod.rs +++ b/crates/brk_computer/src/market/mod.rs @@ -22,8 +22,6 @@ pub use returns::Vecs as ReturnsVecs; pub use volatility::Vecs as VolatilityVecs; pub const DB_NAME: &str = "market"; - -/// Main market metrics struct composed of sub-modules #[derive(Traversable)] pub struct Vecs { #[traversable(skip)] diff --git a/crates/brk_computer/src/market/moving_average/import.rs b/crates/brk_computer/src/market/moving_average/import.rs index 7186f9589..b9852b79f 100644 --- a/crates/brk_computer/src/market/moving_average/import.rs +++ b/crates/brk_computer/src/market/moving_average/import.rs @@ -17,10 +17,7 @@ impl Vecs { macro_rules! import { ($name:expr) => { ComputedFromHeightPriceWithRatioExtended::forced_import( - db, - $name, - version, - indexes, + db, $name, version, indexes, )? }; } diff --git a/crates/brk_computer/src/market/moving_average/vecs.rs b/crates/brk_computer/src/market/moving_average/vecs.rs index 7e0349e86..c8989e486 100644 --- a/crates/brk_computer/src/market/moving_average/vecs.rs +++ b/crates/brk_computer/src/market/moving_average/vecs.rs @@ -3,8 +3,6 @@ use brk_types::Cents; use vecdb::{Rw, StorageMode}; use crate::internal::{ComputedFromHeightPriceWithRatioExtended, LazyFromHeight, Price}; - -/// Simple and exponential moving average metrics #[derive(Traversable)] pub struct Vecs { pub price_sma_1w: ComputedFromHeightPriceWithRatioExtended, diff --git a/crates/brk_computer/src/market/range/compute.rs b/crates/brk_computer/src/market/range/compute.rs index daae024c8..e44c1fb92 100644 --- a/crates/brk_computer/src/market/range/compute.rs +++ b/crates/brk_computer/src/market/range/compute.rs @@ -16,13 +16,39 @@ impl Vecs { let price = &prices.price.cents.height; for (min_vec, max_vec, starts) in [ - (&mut self.price_min_1w.cents.height, &mut self.price_max_1w.cents.height, &blocks.count.height_1w_ago), - (&mut self.price_min_2w.cents.height, &mut self.price_max_2w.cents.height, &blocks.count.height_2w_ago), - (&mut self.price_min_1m.cents.height, &mut self.price_max_1m.cents.height, &blocks.count.height_1m_ago), - (&mut self.price_min_1y.cents.height, &mut self.price_max_1y.cents.height, &blocks.count.height_1y_ago), + ( + &mut self.price_min_1w.cents.height, + &mut self.price_max_1w.cents.height, + &blocks.count.height_1w_ago, + ), + ( + &mut self.price_min_2w.cents.height, + &mut self.price_max_2w.cents.height, + &blocks.count.height_2w_ago, + ), + ( + &mut self.price_min_1m.cents.height, + &mut self.price_max_1m.cents.height, + &blocks.count.height_1m_ago, + ), + ( + &mut self.price_min_1y.cents.height, + &mut self.price_max_1y.cents.height, + &blocks.count.height_1y_ago, + ), ] { - min_vec.compute_rolling_min_from_starts(starting_indexes.height, starts, price, exit)?; - max_vec.compute_rolling_max_from_starts(starting_indexes.height, starts, price, exit)?; + min_vec.compute_rolling_min_from_starts( + starting_indexes.height, + starts, + price, + exit, + )?; + max_vec.compute_rolling_max_from_starts( + starting_indexes.height, + starts, + price, + exit, + )?; } // True range at block level: |price[h] - price[h-1]| @@ -54,26 +80,29 @@ impl Vecs { exit, )?; - self.price_choppiness_index_2w.bps.height.compute_transform4( - starting_indexes.height, - &self.price_true_range_sum_2w.height, - &self.price_max_2w.cents.height, - &self.price_min_2w.cents.height, - &blocks.count.height_2w_ago, - |(h, tr_sum, max, min, window_start, ..)| { - let range = f64::from(max) - f64::from(min); - let n = (h.to_usize() - window_start.to_usize() + 1) as f32; - let ci = if range > 0.0 && n > 1.0 { - BasisPoints16::from( - (*tr_sum / range as f32).log10() as f64 / n.log10() as f64, - ) - } else { - BasisPoints16::ZERO - }; - (h, ci) - }, - exit, - )?; + self.price_choppiness_index_2w + .bps + .height + .compute_transform4( + starting_indexes.height, + &self.price_true_range_sum_2w.height, + &self.price_max_2w.cents.height, + &self.price_min_2w.cents.height, + &blocks.count.height_2w_ago, + |(h, tr_sum, max, min, window_start, ..)| { + let range = f64::from(max) - f64::from(min); + let n = (h.to_usize() - window_start.to_usize() + 1) as f32; + let ci = if range > 0.0 && n > 1.0 { + BasisPoints16::from( + (*tr_sum / range as f32).log10() as f64 / n.log10() as f64, + ) + } else { + BasisPoints16::ZERO + }; + (h, ci) + }, + exit, + )?; Ok(()) } diff --git a/crates/brk_computer/src/market/range/import.rs b/crates/brk_computer/src/market/range/import.rs index 7dfbb42a8..ab7e6e4aa 100644 --- a/crates/brk_computer/src/market/range/import.rs +++ b/crates/brk_computer/src/market/range/import.rs @@ -3,10 +3,17 @@ use brk_types::Version; use vecdb::Database; use super::Vecs; -use crate::{indexes, internal::{ComputedFromHeight, PercentFromHeight, Price}}; +use crate::{ + indexes, + internal::{ComputedFromHeight, PercentFromHeight, Price}, +}; impl Vecs { - pub(crate) fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { + pub(crate) fn forced_import( + db: &Database, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { let v1 = Version::ONE; Ok(Self { @@ -19,13 +26,22 @@ impl Vecs { price_min_1y: Price::forced_import(db, "price_min_1y", version + v1, indexes)?, price_max_1y: Price::forced_import(db, "price_max_1y", version + v1, indexes)?, price_true_range: ComputedFromHeight::forced_import( - db, "price_true_range", version + v1, indexes, + db, + "price_true_range", + version + v1, + indexes, )?, price_true_range_sum_2w: ComputedFromHeight::forced_import( - db, "price_true_range_sum_2w", version + v1, indexes, + db, + "price_true_range_sum_2w", + version + v1, + indexes, )?, price_choppiness_index_2w: PercentFromHeight::forced_import( - db, "price_choppiness_index_2w", version + v1, indexes, + db, + "price_choppiness_index_2w", + version + v1, + indexes, )?, }) } diff --git a/crates/brk_computer/src/market/range/vecs.rs b/crates/brk_computer/src/market/range/vecs.rs index cf4c73cfd..1a847f7c3 100644 --- a/crates/brk_computer/src/market/range/vecs.rs +++ b/crates/brk_computer/src/market/range/vecs.rs @@ -3,8 +3,6 @@ use brk_types::{BasisPoints16, Cents, StoredF32}; use vecdb::{Rw, StorageMode}; use crate::internal::{ComputedFromHeight, PercentFromHeight, Price}; - -/// Price range and choppiness metrics #[derive(Traversable)] pub struct Vecs { pub price_min_1w: Price>, diff --git a/crates/brk_computer/src/market/returns/compute.rs b/crates/brk_computer/src/market/returns/compute.rs index f4b8a1e8b..81845b63f 100644 --- a/crates/brk_computer/src/market/returns/compute.rs +++ b/crates/brk_computer/src/market/returns/compute.rs @@ -46,12 +46,24 @@ impl Vecs { let _24h_price_return_ratio = &self.price_return._24h.ratio.height; - self.price_return_24h_sd_1w - .compute_all(blocks, starting_indexes, exit, _24h_price_return_ratio)?; - self.price_return_24h_sd_1m - .compute_all(blocks, starting_indexes, exit, _24h_price_return_ratio)?; - self.price_return_24h_sd_1y - .compute_all(blocks, starting_indexes, exit, _24h_price_return_ratio)?; + self.price_return_24h_sd_1w.compute_all( + blocks, + starting_indexes, + exit, + _24h_price_return_ratio, + )?; + self.price_return_24h_sd_1m.compute_all( + blocks, + starting_indexes, + exit, + _24h_price_return_ratio, + )?; + self.price_return_24h_sd_1y.compute_all( + blocks, + starting_indexes, + exit, + _24h_price_return_ratio, + )?; // Downside returns: min(return, 0) self.price_downside_24h.compute_transform( @@ -65,12 +77,24 @@ impl Vecs { )?; // Downside deviation (SD of downside returns) - self.price_downside_24h_sd_1w - .compute_all(blocks, starting_indexes, exit, &self.price_downside_24h)?; - self.price_downside_24h_sd_1m - .compute_all(blocks, starting_indexes, exit, &self.price_downside_24h)?; - self.price_downside_24h_sd_1y - .compute_all(blocks, starting_indexes, exit, &self.price_downside_24h)?; + self.price_downside_24h_sd_1w.compute_all( + blocks, + starting_indexes, + exit, + &self.price_downside_24h, + )?; + self.price_downside_24h_sd_1m.compute_all( + blocks, + starting_indexes, + exit, + &self.price_downside_24h, + )?; + self.price_downside_24h_sd_1y.compute_all( + blocks, + starting_indexes, + exit, + &self.price_downside_24h, + )?; Ok(()) } diff --git a/crates/brk_computer/src/market/returns/import.rs b/crates/brk_computer/src/market/returns/import.rs index 6d9fc5b40..399283f01 100644 --- a/crates/brk_computer/src/market/returns/import.rs +++ b/crates/brk_computer/src/market/returns/import.rs @@ -19,22 +19,12 @@ impl Vecs { let v1 = Version::ONE; let price_return = ByLookbackPeriod::try_new(|name, _days| { - PercentFromHeight::forced_import( - db, - &format!("price_return_{name}"), - version, - indexes, - ) + PercentFromHeight::forced_import(db, &format!("price_return_{name}"), version, indexes) })?; // CAGR (computed, 2y+ only) let price_cagr = ByDcaCagr::try_new(|name, _days| { - PercentFromHeight::forced_import( - db, - &format!("price_cagr_{name}"), - version, - indexes, - ) + PercentFromHeight::forced_import(db, &format!("price_cagr_{name}"), version, indexes) })?; let price_return_24h_sd_1w = ComputedFromHeightStdDev::forced_import( diff --git a/crates/brk_computer/src/market/returns/vecs.rs b/crates/brk_computer/src/market/returns/vecs.rs index 85bbe73d1..0535c6400 100644 --- a/crates/brk_computer/src/market/returns/vecs.rs +++ b/crates/brk_computer/src/market/returns/vecs.rs @@ -6,8 +6,6 @@ use crate::{ internal::{ComputedFromHeightStdDev, PercentFromHeight}, market::{dca::ByDcaCagr, lookback::ByLookbackPeriod}, }; - -/// Price returns, CAGR, and returns standard deviation metrics #[derive(Traversable)] pub struct Vecs { pub price_return: ByLookbackPeriod>, diff --git a/crates/brk_computer/src/market/volatility/import.rs b/crates/brk_computer/src/market/volatility/import.rs index f8242fcd5..fc2f9dfb5 100644 --- a/crates/brk_computer/src/market/volatility/import.rs +++ b/crates/brk_computer/src/market/volatility/import.rs @@ -5,9 +5,7 @@ use vecdb::{Database, ReadableCloneableVec}; use super::super::returns; use super::Vecs; use crate::indexes; -use crate::internal::{ - ComputedFromHeight, Days30, Days365, Days7, LazyFromHeight, TimesSqrt, -}; +use crate::internal::{ComputedFromHeight, Days7, Days30, Days365, LazyFromHeight, TimesSqrt}; impl Vecs { pub(crate) fn forced_import( @@ -21,21 +19,33 @@ impl Vecs { let price_volatility_1w = LazyFromHeight::from_computed::>( "price_volatility_1w", version + v2, - returns.price_return_24h_sd_1w.sd.height.read_only_boxed_clone(), + returns + .price_return_24h_sd_1w + .sd + .height + .read_only_boxed_clone(), &returns.price_return_24h_sd_1w.sd, ); let price_volatility_1m = LazyFromHeight::from_computed::>( "price_volatility_1m", version + v2, - returns.price_return_24h_sd_1m.sd.height.read_only_boxed_clone(), + returns + .price_return_24h_sd_1m + .sd + .height + .read_only_boxed_clone(), &returns.price_return_24h_sd_1m.sd, ); let price_volatility_1y = LazyFromHeight::from_computed::>( "price_volatility_1y", version + v2, - returns.price_return_24h_sd_1y.sd.height.read_only_boxed_clone(), + returns + .price_return_24h_sd_1y + .sd + .height + .read_only_boxed_clone(), &returns.price_return_24h_sd_1y.sd, ); diff --git a/crates/brk_computer/src/market/volatility/vecs.rs b/crates/brk_computer/src/market/volatility/vecs.rs index b2578b169..bdc4630e9 100644 --- a/crates/brk_computer/src/market/volatility/vecs.rs +++ b/crates/brk_computer/src/market/volatility/vecs.rs @@ -4,8 +4,6 @@ use vecdb::{Rw, StorageMode}; use crate::internal::{ComputedFromHeight, LazyFromHeight}; use brk_types::StoredF32; - -/// Price volatility metrics (derived from returns standard deviation) #[derive(Traversable)] pub struct Vecs { pub price_volatility_1w: LazyFromHeight, diff --git a/crates/brk_computer/src/mining/hashrate/import.rs b/crates/brk_computer/src/mining/hashrate/import.rs index 3ff8b2b91..8f4e1c8e7 100644 --- a/crates/brk_computer/src/mining/hashrate/import.rs +++ b/crates/brk_computer/src/mining/hashrate/import.rs @@ -5,10 +5,7 @@ use vecdb::Database; use super::Vecs; use crate::{ indexes, - internal::{ - ComputedFromHeight, - PercentFromHeight, - }, + internal::{ComputedFromHeight, PercentFromHeight}, }; impl Vecs { diff --git a/crates/brk_computer/src/mining/hashrate/vecs.rs b/crates/brk_computer/src/mining/hashrate/vecs.rs index 5480a3bf4..8f7b6afc4 100644 --- a/crates/brk_computer/src/mining/hashrate/vecs.rs +++ b/crates/brk_computer/src/mining/hashrate/vecs.rs @@ -4,7 +4,6 @@ use vecdb::{Rw, StorageMode}; use crate::internal::{ComputedFromHeight, PercentFromHeight}; -/// Mining-related metrics: hash rate, hash price, hash value #[derive(Traversable)] pub struct Vecs { pub hash_rate: ComputedFromHeight, diff --git a/crates/brk_computer/src/mining/import.rs b/crates/brk_computer/src/mining/import.rs index 472ee425d..60a9d8725 100644 --- a/crates/brk_computer/src/mining/import.rs +++ b/crates/brk_computer/src/mining/import.rs @@ -1,11 +1,12 @@ use std::path::Path; use brk_error::Result; -use brk_traversable::Traversable; use brk_types::Version; -use vecdb::{Database, PAGE_SIZE}; -use crate::indexes; +use crate::{ + indexes, + internal::{finalize_db, open_db}, +}; use super::{HashrateVecs, RewardsVecs, Vecs}; @@ -15,9 +16,7 @@ impl Vecs { parent_version: Version, indexes: &indexes::Vecs, ) -> Result { - let db = Database::open(&parent_path.join(super::DB_NAME))?; - db.set_min_len(PAGE_SIZE * 50_000_000)?; - + let db = open_db(parent_path, super::DB_NAME, 50_000_000)?; let version = parent_version; let rewards = RewardsVecs::forced_import(&db, version, indexes)?; @@ -28,14 +27,7 @@ impl Vecs { rewards, hashrate, }; - - this.db.retain_regions( - this.iter_any_exportable() - .flat_map(|v| v.region_names()) - .collect(), - )?; - this.db.compact()?; - + finalize_db(&this.db, &this)?; Ok(this) } } diff --git a/crates/brk_computer/src/mining/rewards/compute.rs b/crates/brk_computer/src/mining/rewards/compute.rs index eadf662ee..1d797e506 100644 --- a/crates/brk_computer/src/mining/rewards/compute.rs +++ b/crates/brk_computer/src/mining/rewards/compute.rs @@ -122,12 +122,13 @@ impl Vecs { )?; // All-time cumulative fee dominance - self.fee_dominance.compute_binary::( - starting_indexes.height, - &self.fees.cumulative.sats.height, - &self.coinbase.cumulative.sats.height, - exit, - )?; + self.fee_dominance + .compute_binary::( + starting_indexes.height, + &self.fees.cumulative.sats.height, + &self.coinbase.cumulative.sats.height, + exit, + )?; // Rolling fee dominance = sum(fees) / sum(coinbase) for ((fee_dom, fees_w), coinbase_w) in self @@ -146,12 +147,13 @@ impl Vecs { } // All-time cumulative subsidy dominance - self.subsidy_dominance.compute_binary::( - starting_indexes.height, - &self.subsidy.cumulative.sats.height, - &self.coinbase.cumulative.sats.height, - exit, - )?; + self.subsidy_dominance + .compute_binary::( + starting_indexes.height, + &self.subsidy.cumulative.sats.height, + &self.coinbase.cumulative.sats.height, + exit, + )?; // Rolling subsidy dominance = 1 - fee_dominance for (sub_dom, fee_dom) in self diff --git a/crates/brk_computer/src/mining/rewards/import.rs b/crates/brk_computer/src/mining/rewards/import.rs index e8477e88c..36198cd45 100644 --- a/crates/brk_computer/src/mining/rewards/import.rs +++ b/crates/brk_computer/src/mining/rewards/import.rs @@ -6,8 +6,8 @@ use super::Vecs; use crate::{ indexes, internal::{ - FiatFromHeight, PercentFromHeight, PercentRollingWindows, - ValueFromHeightFull, ValueFromHeightCumulativeSum, + FiatFromHeight, PercentFromHeight, PercentRollingWindows, ValueFromHeightCumulativeSum, + ValueFromHeightFull, }, }; @@ -27,12 +27,7 @@ impl Vecs { version, indexes, )?, - fee_dominance: PercentFromHeight::forced_import( - db, - "fee_dominance", - version, - indexes, - )?, + fee_dominance: PercentFromHeight::forced_import(db, "fee_dominance", version, indexes)?, fee_dominance_rolling: PercentRollingWindows::forced_import( db, "fee_dominance", @@ -51,12 +46,7 @@ impl Vecs { version, indexes, )?, - subsidy_sma_1y: FiatFromHeight::forced_import( - db, - "subsidy_sma_1y", - version, - indexes, - )?, + subsidy_sma_1y: FiatFromHeight::forced_import(db, "subsidy_sma_1y", version, indexes)?, }) } } diff --git a/crates/brk_computer/src/mining/rewards/vecs.rs b/crates/brk_computer/src/mining/rewards/vecs.rs index 2f6bcb6c8..0ef1ec081 100644 --- a/crates/brk_computer/src/mining/rewards/vecs.rs +++ b/crates/brk_computer/src/mining/rewards/vecs.rs @@ -3,11 +3,10 @@ use brk_types::{BasisPoints16, Cents}; use vecdb::{Rw, StorageMode}; use crate::internal::{ - FiatFromHeight, PercentFromHeight, PercentRollingWindows, - ValueFromHeightFull, ValueFromHeightCumulativeSum, + FiatFromHeight, PercentFromHeight, PercentRollingWindows, ValueFromHeightCumulativeSum, + ValueFromHeightFull, }; -/// Coinbase/subsidy/rewards metrics #[derive(Traversable)] pub struct Vecs { pub coinbase: ValueFromHeightFull, diff --git a/crates/brk_computer/src/outputs/count/import.rs b/crates/brk_computer/src/outputs/count/import.rs index e9b36e7fe..3452c0941 100644 --- a/crates/brk_computer/src/outputs/count/import.rs +++ b/crates/brk_computer/src/outputs/count/import.rs @@ -5,7 +5,7 @@ use vecdb::Database; use super::Vecs; use crate::{ indexes, - internal::{ComputedFromHeightAggregated, ComputedFromHeight}, + internal::{ComputedFromHeight, ComputedFromHeightAggregated}, }; impl Vecs { diff --git a/crates/brk_computer/src/outputs/count/vecs.rs b/crates/brk_computer/src/outputs/count/vecs.rs index c3807d151..e2bc72c62 100644 --- a/crates/brk_computer/src/outputs/count/vecs.rs +++ b/crates/brk_computer/src/outputs/count/vecs.rs @@ -2,7 +2,7 @@ use brk_traversable::Traversable; use brk_types::StoredU64; use vecdb::{Rw, StorageMode}; -use crate::internal::{ComputedFromHeightAggregated, ComputedFromHeight}; +use crate::internal::{ComputedFromHeight, ComputedFromHeightAggregated}; #[derive(Traversable)] pub struct Vecs { diff --git a/crates/brk_computer/src/outputs/import.rs b/crates/brk_computer/src/outputs/import.rs index f291bb609..b0acd3f15 100644 --- a/crates/brk_computer/src/outputs/import.rs +++ b/crates/brk_computer/src/outputs/import.rs @@ -1,12 +1,14 @@ use std::path::Path; use brk_error::Result; -use brk_traversable::Traversable; use brk_types::Version; -use vecdb::{Database, PAGE_SIZE}; + +use crate::{ + indexes, + internal::{finalize_db, open_db}, +}; use super::{CountVecs, SpentVecs, Vecs}; -use crate::indexes; impl Vecs { pub(crate) fn forced_import( @@ -14,23 +16,14 @@ impl Vecs { parent_version: Version, indexes: &indexes::Vecs, ) -> Result { - let db = Database::open(&parent_path.join(super::DB_NAME))?; - db.set_min_len(PAGE_SIZE * 10_000_000)?; - + let db = open_db(parent_path, super::DB_NAME, 10_000_000)?; let version = parent_version; let spent = SpentVecs::forced_import(&db, version)?; let count = CountVecs::forced_import(&db, version, indexes)?; let this = Self { db, spent, count }; - - this.db.retain_regions( - this.iter_any_exportable() - .flat_map(|v| v.region_names()) - .collect(), - )?; - this.db.compact()?; - + finalize_db(&this.db, &this)?; Ok(this) } } diff --git a/crates/brk_computer/src/outputs/spent/compute.rs b/crates/brk_computer/src/outputs/spent/compute.rs index 43f2aaef7..b5382a6b1 100644 --- a/crates/brk_computer/src/outputs/spent/compute.rs +++ b/crates/brk_computer/src/outputs/spent/compute.rs @@ -2,9 +2,7 @@ use brk_error::Result; use brk_indexer::Indexer; use brk_types::{Height, Indexes, TxInIndex, TxOutIndex}; use tracing::info; -use vecdb::{ - AnyStoredVec, AnyVec, Database, Exit, WritableVec, ReadableVec, Stamp, VecIndex, -}; +use vecdb::{AnyStoredVec, AnyVec, Database, Exit, ReadableVec, Stamp, VecIndex, WritableVec}; use super::Vecs; use crate::inputs; @@ -59,8 +57,8 @@ impl Vecs { // Only collect from min_height onward (not from 0) let offset = min_height.to_usize(); - let first_txoutindex_data = first_txoutindex_vec - .collect_range_at(offset, target_height.to_usize() + 1); + let first_txoutindex_data = + first_txoutindex_vec.collect_range_at(offset, target_height.to_usize() + 1); let first_txinindex_data = indexer .vecs .inputs @@ -91,7 +89,8 @@ impl Vecs { .fill_to(batch_txoutindex, TxInIndex::UNSPENT)?; // Get txin range for this height batch - let txin_start = first_txinindex_data[batch_start_height.to_usize() - offset].to_usize(); + let txin_start = + first_txinindex_data[batch_start_height.to_usize() - offset].to_usize(); let txin_end = if batch_end_height >= target_height { inputs.spent.txoutindex.len() } else { @@ -101,12 +100,16 @@ impl Vecs { // Stream txins directly into pairs — avoids intermediate Vec allocation pairs.clear(); let mut j = txin_start; - txinindex_to_txoutindex.for_each_range_at(txin_start, txin_end, |txoutindex: TxOutIndex| { - if !txoutindex.is_coinbase() { - pairs.push((txoutindex, TxInIndex::from(j))); - } - j += 1; - }); + txinindex_to_txoutindex.for_each_range_at( + txin_start, + txin_end, + |txoutindex: TxOutIndex| { + if !txoutindex.is_coinbase() { + pairs.push((txoutindex, TxInIndex::from(j))); + } + j += 1; + }, + ); pairs.sort_unstable_by_key(|(txoutindex, _)| *txoutindex); diff --git a/crates/brk_computer/src/pools/mod.rs b/crates/brk_computer/src/pools/mod.rs index 8928d8015..6ca6b0431 100644 --- a/crates/brk_computer/src/pools/mod.rs +++ b/crates/brk_computer/src/pools/mod.rs @@ -4,18 +4,20 @@ use brk_error::Result; use brk_indexer::Indexer; use brk_store::AnyStore; use brk_traversable::Traversable; -use brk_types::{Address, AddressBytes, Height, Indexes, OutputType, PoolSlug, Pools, TxOutIndex, pools}; +use brk_types::{ + Address, AddressBytes, Height, Indexes, OutputType, PoolSlug, Pools, TxOutIndex, pools, +}; use rayon::prelude::*; use vecdb::{ - AnyStoredVec, AnyVec, BytesVec, Database, Exit, ImportableVec, PAGE_SIZE, ReadableVec, Rw, - StorageMode, VecIndex, Version, WritableVec, + AnyStoredVec, AnyVec, BytesVec, Database, Exit, ImportableVec, ReadableVec, Rw, StorageMode, + VecIndex, Version, WritableVec, }; mod vecs; use crate::{ - blocks, - indexes, + blocks, indexes, + internal::{finalize_db, open_db}, mining, prices, }; @@ -36,8 +38,7 @@ impl Vecs { parent_version: Version, indexes: &indexes::Vecs, ) -> Result { - let db = Database::open(&parent_path.join(DB_NAME))?; - db.set_min_len(PAGE_SIZE * 1_000_000)?; + let db = open_db(parent_path, DB_NAME, 1_000_000)?; let pools = pools(); let version = parent_version + Version::new(3) + Version::new(pools.len() as u32); @@ -55,13 +56,7 @@ impl Vecs { db, }; - this.db.retain_regions( - this.iter_any_exportable() - .flat_map(|v| v.region_names()) - .collect(), - )?; - this.db.compact()?; - + finalize_db(&this.db, &this)?; Ok(this) } @@ -75,31 +70,6 @@ impl Vecs { mining: &mining::Vecs, starting_indexes: &Indexes, exit: &Exit, - ) -> Result<()> { - self.compute_( - indexer, - indexes, - blocks, - prices, - mining, - starting_indexes, - exit, - )?; - let _lock = exit.lock(); - self.db.compact()?; - Ok(()) - } - - #[allow(clippy::too_many_arguments)] - fn compute_( - &mut self, - indexer: &Indexer, - indexes: &indexes::Vecs, - blocks: &blocks::Vecs, - prices: &prices::Vecs, - mining: &mining::Vecs, - starting_indexes: &Indexes, - exit: &Exit, ) -> Result<()> { self.compute_height_to_pool(indexer, indexes, starting_indexes, exit)?; @@ -114,6 +84,8 @@ impl Vecs { ) })?; + let _lock = exit.lock(); + self.db.compact()?; Ok(()) } @@ -127,18 +99,17 @@ impl Vecs { self.height_to_pool .validate_computed_version_or_reset(indexer.stores.height_to_coinbase_tag.version())?; - let txindex_to_first_txoutindex_reader = - indexer.vecs.transactions.first_txoutindex.reader(); - let txoutindex_to_outputtype_reader = indexer.vecs.outputs.outputtype.reader(); - let txoutindex_to_typeindex_reader = indexer.vecs.outputs.typeindex.reader(); - let p2pk65addressindex_to_p2pk65bytes_reader = indexer.vecs.addresses.p2pk65bytes.reader(); - let p2pk33addressindex_to_p2pk33bytes_reader = indexer.vecs.addresses.p2pk33bytes.reader(); - let p2pkhaddressindex_to_p2pkhbytes_reader = indexer.vecs.addresses.p2pkhbytes.reader(); - let p2shaddressindex_to_p2shbytes_reader = indexer.vecs.addresses.p2shbytes.reader(); - let p2wpkhaddressindex_to_p2wpkhbytes_reader = indexer.vecs.addresses.p2wpkhbytes.reader(); - let p2wshaddressindex_to_p2wshbytes_reader = indexer.vecs.addresses.p2wshbytes.reader(); - let p2traddressindex_to_p2trbytes_reader = indexer.vecs.addresses.p2trbytes.reader(); - let p2aaddressindex_to_p2abytes_reader = indexer.vecs.addresses.p2abytes.reader(); + let first_txoutindex = indexer.vecs.transactions.first_txoutindex.reader(); + let outputtype = indexer.vecs.outputs.outputtype.reader(); + let typeindex = indexer.vecs.outputs.typeindex.reader(); + let p2pk65 = indexer.vecs.addresses.p2pk65bytes.reader(); + let p2pk33 = indexer.vecs.addresses.p2pk33bytes.reader(); + let p2pkh = indexer.vecs.addresses.p2pkhbytes.reader(); + let p2sh = indexer.vecs.addresses.p2shbytes.reader(); + let p2wpkh = indexer.vecs.addresses.p2wpkhbytes.reader(); + let p2wsh = indexer.vecs.addresses.p2wshbytes.reader(); + let p2tr = indexer.vecs.addresses.p2trbytes.reader(); + let p2a = indexer.vecs.addresses.p2abytes.reader(); let unknown = self.pools.get_unknown(); @@ -161,44 +132,26 @@ impl Vecs { .skip(min) .try_for_each(|(height, coinbase_tag)| -> Result<()> { let txindex = first_txindex_cursor.next().unwrap(); - let txoutindex = txindex_to_first_txoutindex_reader.get(txindex.to_usize()); + let out_start = first_txoutindex.get(txindex.to_usize()); let ti = txindex.to_usize(); output_count_cursor.advance(ti - output_count_cursor.position()); let outputcount = output_count_cursor.next().unwrap(); - let pool = (*txoutindex..(*txoutindex + *outputcount)) + let pool = (*out_start..(*out_start + *outputcount)) .map(TxOutIndex::from) .find_map(|txoutindex| { - let outputtype = txoutindex_to_outputtype_reader.get(txoutindex.to_usize()); - let typeindex = txoutindex_to_typeindex_reader.get(txoutindex.to_usize()); - - let ti = usize::from(typeindex); - match outputtype { - OutputType::P2PK65 => Some(AddressBytes::from( - p2pk65addressindex_to_p2pk65bytes_reader.get(ti), - )), - OutputType::P2PK33 => Some(AddressBytes::from( - p2pk33addressindex_to_p2pk33bytes_reader.get(ti), - )), - OutputType::P2PKH => Some(AddressBytes::from( - p2pkhaddressindex_to_p2pkhbytes_reader.get(ti), - )), - OutputType::P2SH => Some(AddressBytes::from( - p2shaddressindex_to_p2shbytes_reader.get(ti), - )), - OutputType::P2WPKH => Some(AddressBytes::from( - p2wpkhaddressindex_to_p2wpkhbytes_reader.get(ti), - )), - OutputType::P2WSH => Some(AddressBytes::from( - p2wshaddressindex_to_p2wshbytes_reader.get(ti), - )), - OutputType::P2TR => Some(AddressBytes::from( - p2traddressindex_to_p2trbytes_reader.get(ti), - )), - OutputType::P2A => Some(AddressBytes::from( - p2aaddressindex_to_p2abytes_reader.get(ti), - )), + let ot = outputtype.get(txoutindex.to_usize()); + let ti = usize::from(typeindex.get(txoutindex.to_usize())); + match ot { + OutputType::P2PK65 => Some(AddressBytes::from(p2pk65.get(ti))), + OutputType::P2PK33 => Some(AddressBytes::from(p2pk33.get(ti))), + OutputType::P2PKH => Some(AddressBytes::from(p2pkh.get(ti))), + OutputType::P2SH => Some(AddressBytes::from(p2sh.get(ti))), + OutputType::P2WPKH => Some(AddressBytes::from(p2wpkh.get(ti))), + OutputType::P2WSH => Some(AddressBytes::from(p2wsh.get(ti))), + OutputType::P2TR => Some(AddressBytes::from(p2tr.get(ti))), + OutputType::P2A => Some(AddressBytes::from(p2a.get(ti))), _ => None, } .map(|bytes| Address::try_from(&bytes).unwrap()) diff --git a/crates/brk_computer/src/pools/vecs.rs b/crates/brk_computer/src/pools/vecs.rs index ec32f16f2..7ef498665 100644 --- a/crates/brk_computer/src/pools/vecs.rs +++ b/crates/brk_computer/src/pools/vecs.rs @@ -1,15 +1,15 @@ use brk_error::Result; use brk_traversable::Traversable; use brk_types::{BasisPoints16, Height, Indexes, PoolSlug, StoredU32}; -use vecdb::{AnyVec, BinaryTransform, Database, Exit, ReadableVec, Rw, StorageMode, VecIndex, Version}; +use vecdb::{ + AnyVec, BinaryTransform, Database, Exit, ReadableVec, Rw, StorageMode, VecIndex, Version, +}; use crate::{ - blocks, - indexes, + blocks, indexes, internal::{ - ComputedFromHeightCumulativeSum, ComputedFromHeight, MaskSats, - PercentFromHeight, PercentRollingWindows, RatioU32Bp16, RollingWindows, - ValueFromHeightCumulativeSum, + ComputedFromHeight, ComputedFromHeightCumulativeSum, MaskSats, PercentFromHeight, + PercentRollingWindows, RatioU32Bp16, RollingWindows, ValueFromHeightCumulativeSum, }, mining, prices, }; diff --git a/crates/brk_computer/src/positions.rs b/crates/brk_computer/src/positions.rs index 21d402a1c..4e64b26a8 100644 --- a/crates/brk_computer/src/positions.rs +++ b/crates/brk_computer/src/positions.rs @@ -7,10 +7,12 @@ use brk_traversable::Traversable; use brk_types::{BlkPosition, Height, Indexes, TxIndex, Version}; use tracing::info; use vecdb::{ - AnyStoredVec, AnyVec, Database, Exit, ImportableVec, PAGE_SIZE, PcoVec, ReadableVec, Rw, - StorageMode, VecIndex, WritableVec, + AnyStoredVec, AnyVec, Database, Exit, ImportableVec, PcoVec, ReadableVec, Rw, StorageMode, + VecIndex, WritableVec, }; +use crate::internal::{finalize_db, open_db}; + pub const DB_NAME: &str = "positions"; #[derive(Traversable)] @@ -23,25 +25,15 @@ pub struct Vecs { impl Vecs { pub(crate) fn forced_import(parent_path: &Path, parent_version: Version) -> Result { - let db = Database::open(&parent_path.join(DB_NAME))?; - db.set_min_len(PAGE_SIZE * 1_000_000)?; - + let db = open_db(parent_path, DB_NAME, 1_000_000)?; let version = parent_version; let this = Self { block_position: PcoVec::forced_import(&db, "position", version + Version::TWO)?, tx_position: PcoVec::forced_import(&db, "position", version + Version::TWO)?, - db, }; - - this.db.retain_regions( - this.iter_any_exportable() - .flat_map(|v| v.region_names()) - .collect(), - )?; - this.db.compact()?; - + finalize_db(&this.db, &this)?; Ok(this) } diff --git a/crates/brk_computer/src/prices/by_unit.rs b/crates/brk_computer/src/prices/by_unit.rs index f257f15d4..d006ebc6b 100644 --- a/crates/brk_computer/src/prices/by_unit.rs +++ b/crates/brk_computer/src/prices/by_unit.rs @@ -3,14 +3,11 @@ use brk_types::{Cents, Dollars, OHLCCents, OHLCDollars, OHLCSats, Sats}; use vecdb::{Rw, StorageMode}; use crate::internal::{ - ComputedFromHeight, ComputedHeightDerived, EagerIndexes, LazyEagerIndexes, - LazyFromHeight, + ComputedFromHeight, ComputedHeightDerived, EagerIndexes, LazyEagerIndexes, LazyFromHeight, }; use super::ohlcs::{LazyOhlcVecs, OhlcVecs}; -// ── SplitByUnit ───────────────────────────────────────────────────── - #[derive(Traversable)] pub struct SplitByUnit { pub open: SplitIndexesByUnit, @@ -33,8 +30,6 @@ pub struct SplitCloseByUnit { pub sats: ComputedHeightDerived, } -// ── OhlcByUnit ────────────────────────────────────────────────────── - #[derive(Traversable)] pub struct OhlcByUnit { pub cents: OhlcVecs, @@ -42,8 +37,6 @@ pub struct OhlcByUnit { pub sats: LazyOhlcVecs, } -// ── PriceByUnit ───────────────────────────────────────────────────── - #[derive(Traversable)] pub struct PriceByUnit { pub cents: ComputedFromHeight, diff --git a/crates/brk_computer/src/prices/compute.rs b/crates/brk_computer/src/prices/compute.rs index bb76ee260..254d0b576 100644 --- a/crates/brk_computer/src/prices/compute.rs +++ b/crates/brk_computer/src/prices/compute.rs @@ -19,18 +19,24 @@ impl Vecs { exit: &Exit, ) -> Result<()> { self.compute_prices(indexer, starting_indexes, exit)?; - self.split - .open - .cents - .compute_first(starting_indexes, &self.price.cents.height, indexes, exit)?; - self.split - .high - .cents - .compute_max(starting_indexes, &self.price.cents.height, indexes, exit)?; - self.split - .low - .cents - .compute_min(starting_indexes, &self.price.cents.height, indexes, exit)?; + self.split.open.cents.compute_first( + starting_indexes, + &self.price.cents.height, + indexes, + exit, + )?; + self.split.high.cents.compute_max( + starting_indexes, + &self.price.cents.height, + indexes, + exit, + )?; + self.split.low.cents.compute_min( + starting_indexes, + &self.price.cents.height, + indexes, + exit, + )?; self.ohlc.cents.compute_from_split( starting_indexes, indexes, @@ -75,7 +81,10 @@ impl Vecs { self.price.cents.height.truncate_if_needed_at(truncate_to)?; if self.price.cents.height.len() < START_HEIGHT { - for line in brk_oracle::PRICES.lines().skip(self.price.cents.height.len()) { + for line in brk_oracle::PRICES + .lines() + .skip(self.price.cents.height.len()) + { if self.price.cents.height.len() >= START_HEIGHT { break; } @@ -91,7 +100,12 @@ impl Vecs { let config = Config::default(); let committed = self.price.cents.height.len(); - let prev_cents = self.price.cents.height.collect_one_at(committed - 1).unwrap(); + let prev_cents = self + .price + .cents + .height + .collect_one_at(committed - 1) + .unwrap(); let seed_bin = cents_to_bin(prev_cents.inner() as f64); let warmup = config.window_size.min(committed - START_HEIGHT); let mut oracle = Oracle::from_checkpoint(seed_bin, config, |o| { @@ -107,7 +121,10 @@ impl Vecs { let ref_bins = Self::feed_blocks(&mut oracle, indexer, committed..total_heights); for (i, ref_bin) in ref_bins.into_iter().enumerate() { - self.price.cents.height.push(Cents::new(bin_to_cents(ref_bin))); + self.price + .cents + .height + .push(Cents::new(bin_to_cents(ref_bin))); let progress = ((i + 1) * 100 / num_new) as u8; if i > 0 && progress > ((i * 100 / num_new) as u8) { @@ -188,8 +205,16 @@ impl Vecs { .unwrap_or(TxOutIndex::from(total_outputs)) .to_usize(); - indexer.vecs.outputs.value.collect_range_into_at(out_start, out_end, &mut values); - indexer.vecs.outputs.outputtype.collect_range_into_at(out_start, out_end, &mut output_types); + indexer + .vecs + .outputs + .value + .collect_range_into_at(out_start, out_end, &mut values); + indexer.vecs.outputs.outputtype.collect_range_into_at( + out_start, + out_end, + &mut output_types, + ); let mut hist = [0u32; NUM_BINS]; for i in 0..values.len() { diff --git a/crates/brk_computer/src/prices/mod.rs b/crates/brk_computer/src/prices/mod.rs index d6c16e13d..daefb5c72 100644 --- a/crates/brk_computer/src/prices/mod.rs +++ b/crates/brk_computer/src/prices/mod.rs @@ -6,20 +6,18 @@ use std::path::Path; use brk_traversable::Traversable; use brk_types::Version; -use vecdb::{Database, ReadableCloneableVec, Rw, StorageMode, PAGE_SIZE}; +use vecdb::{Database, ReadableCloneableVec, Rw, StorageMode}; use crate::{ indexes, internal::{ - CentsUnsignedToDollars, CentsUnsignedToSats, ComputedFromHeight, - ComputedHeightDerived, EagerIndexes, LazyEagerIndexes, LazyFromHeight, - OhlcCentsToDollars, OhlcCentsToSats, + CentsUnsignedToDollars, CentsUnsignedToSats, ComputedFromHeight, ComputedHeightDerived, + EagerIndexes, LazyEagerIndexes, LazyFromHeight, OhlcCentsToDollars, OhlcCentsToSats, + finalize_db, open_db, }, }; -use by_unit::{ - OhlcByUnit, PriceByUnit, SplitByUnit, SplitCloseByUnit, SplitIndexesByUnit, -}; +use by_unit::{OhlcByUnit, PriceByUnit, SplitByUnit, SplitCloseByUnit, SplitIndexesByUnit}; use ohlcs::{LazyOhlcVecs, OhlcVecs}; pub const DB_NAME: &str = "prices"; @@ -40,18 +38,9 @@ impl Vecs { version: Version, indexes: &indexes::Vecs, ) -> brk_error::Result { - let db = Database::open(&parent.join(DB_NAME))?; - db.set_min_len(PAGE_SIZE * 1_000_000)?; - + let db = open_db(parent, DB_NAME, 1_000_000)?; let this = Self::forced_import_inner(&db, version, indexes)?; - - this.db.retain_regions( - this.iter_any_exportable() - .flat_map(|v| v.region_names()) - .collect(), - )?; - this.db.compact()?; - + finalize_db(&this.db, &this)?; Ok(this) } @@ -62,10 +51,7 @@ impl Vecs { ) -> brk_error::Result { let version = version + Version::new(11); - // ── Cents (eager, stored) ─────────────────────────────────── - - let price_cents = - ComputedFromHeight::forced_import(db, "price_cents", version, indexes)?; + let price_cents = ComputedFromHeight::forced_import(db, "price_cents", version, indexes)?; let open_cents = EagerIndexes::forced_import(db, "price_open_cents", version)?; let high_cents = EagerIndexes::forced_import(db, "price_high_cents", version)?; @@ -80,8 +66,6 @@ impl Vecs { let ohlc_cents = OhlcVecs::forced_import(db, "price_ohlc_cents", version)?; - // ── USD (lazy from cents) ─────────────────────────────────── - let price_usd = LazyFromHeight::from_computed::( "price", version, @@ -118,8 +102,6 @@ impl Vecs { &ohlc_cents, ); - // ── Sats (lazy from cents, high↔low swapped) ─────────────── - let price_sats = LazyFromHeight::from_computed::( "price_sats", version, @@ -158,8 +140,6 @@ impl Vecs { &ohlc_cents, ); - // ── Assemble pivoted structure ────────────────────────────── - let split = SplitByUnit { open: SplitIndexesByUnit { cents: open_cents, diff --git a/crates/brk_computer/src/prices/ohlcs.rs b/crates/brk_computer/src/prices/ohlcs.rs index 6c60e6cda..2be84b8d1 100644 --- a/crates/brk_computer/src/prices/ohlcs.rs +++ b/crates/brk_computer/src/prices/ohlcs.rs @@ -14,12 +14,10 @@ use vecdb::{ }; use crate::{ - indexes, indexes_apply, indexes_from, + indexes, internal::{ComputedHeightDerived, EagerIndexes, PerPeriod}, }; -// ── EagerOhlcIndexes ───────────────────────────────────────────────── - #[derive(Deref, DerefMut, Traversable)] #[traversable(merge)] pub struct OhlcVecs( @@ -54,13 +52,29 @@ where pub(crate) fn forced_import(db: &Database, name: &str, version: Version) -> Result { let v = version + EAGER_VERSION; - macro_rules! period { - ($idx:ident) => { + macro_rules! per_period { + () => { ImportableVec::forced_import(db, name, v)? }; } - Ok(Self(indexes_from!(period))) + Ok(Self(PerPeriod { + minute10: per_period!(), + minute30: per_period!(), + hour1: per_period!(), + hour4: per_period!(), + hour12: per_period!(), + day1: per_period!(), + day3: per_period!(), + week1: per_period!(), + month1: per_period!(), + month3: per_period!(), + month6: per_period!(), + year1: per_period!(), + year10: per_period!(), + halvingepoch: per_period!(), + difficultyepoch: per_period!(), + })) } } @@ -141,14 +155,26 @@ impl OhlcVecs { }; } - indexes_apply!(period, epoch); + period!(minute10); + period!(minute30); + period!(hour1); + period!(hour4); + period!(hour12); + period!(day1); + period!(day3); + period!(week1); + period!(month1); + period!(month3); + period!(month6); + period!(year1); + period!(year10); + epoch!(halvingepoch); + epoch!(difficultyepoch); Ok(()) } } -// ── LazyOhlcIndexes ────────────────────────────────────────────────── - #[derive(Clone, Deref, DerefMut, Traversable)] #[traversable(merge)] pub struct LazyOhlcVecs( @@ -195,6 +221,22 @@ where }; } - Self(indexes_from!(period)) + Self(PerPeriod { + minute10: period!(minute10), + minute30: period!(minute30), + hour1: period!(hour1), + hour4: period!(hour4), + hour12: period!(hour12), + day1: period!(day1), + day3: period!(day3), + week1: period!(week1), + month1: period!(month1), + month3: period!(month3), + month6: period!(month6), + year1: period!(year1), + year10: period!(year10), + halvingepoch: period!(halvingepoch), + difficultyepoch: period!(difficultyepoch), + }) } } diff --git a/crates/brk_computer/src/scripts/adoption.rs b/crates/brk_computer/src/scripts/adoption.rs index a9197dca7..d58f87f50 100644 --- a/crates/brk_computer/src/scripts/adoption.rs +++ b/crates/brk_computer/src/scripts/adoption.rs @@ -24,18 +24,8 @@ impl Vecs { indexes: &indexes::Vecs, ) -> Result { Ok(Self { - taproot: PercentFromHeight::forced_import( - db, - "taproot_adoption", - version, - indexes, - )?, - segwit: PercentFromHeight::forced_import( - db, - "segwit_adoption", - version, - indexes, - )?, + taproot: PercentFromHeight::forced_import(db, "taproot_adoption", version, indexes)?, + segwit: PercentFromHeight::forced_import(db, "segwit_adoption", version, indexes)?, }) } diff --git a/crates/brk_computer/src/scripts/count/import.rs b/crates/brk_computer/src/scripts/count/import.rs index b61351433..b5003ee1d 100644 --- a/crates/brk_computer/src/scripts/count/import.rs +++ b/crates/brk_computer/src/scripts/count/import.rs @@ -11,18 +11,24 @@ impl Vecs { version: Version, indexes: &indexes::Vecs, ) -> Result { - let p2a = ComputedFromHeightCumulativeSum::forced_import(db, "p2a_count", version, indexes)?; - let p2ms = ComputedFromHeightCumulativeSum::forced_import(db, "p2ms_count", version, indexes)?; + let p2a = + ComputedFromHeightCumulativeSum::forced_import(db, "p2a_count", version, indexes)?; + let p2ms = + ComputedFromHeightCumulativeSum::forced_import(db, "p2ms_count", version, indexes)?; let p2pk33 = ComputedFromHeightCumulativeSum::forced_import(db, "p2pk33_count", version, indexes)?; let p2pk65 = ComputedFromHeightCumulativeSum::forced_import(db, "p2pk65_count", version, indexes)?; - let p2pkh = ComputedFromHeightCumulativeSum::forced_import(db, "p2pkh_count", version, indexes)?; - let p2sh = ComputedFromHeightCumulativeSum::forced_import(db, "p2sh_count", version, indexes)?; - let p2tr = ComputedFromHeightCumulativeSum::forced_import(db, "p2tr_count", version, indexes)?; + let p2pkh = + ComputedFromHeightCumulativeSum::forced_import(db, "p2pkh_count", version, indexes)?; + let p2sh = + ComputedFromHeightCumulativeSum::forced_import(db, "p2sh_count", version, indexes)?; + let p2tr = + ComputedFromHeightCumulativeSum::forced_import(db, "p2tr_count", version, indexes)?; let p2wpkh = ComputedFromHeightCumulativeSum::forced_import(db, "p2wpkh_count", version, indexes)?; - let p2wsh = ComputedFromHeightCumulativeSum::forced_import(db, "p2wsh_count", version, indexes)?; + let p2wsh = + ComputedFromHeightCumulativeSum::forced_import(db, "p2wsh_count", version, indexes)?; let segwit = ComputedFromHeightCumulativeSum::forced_import(db, "segwit_count", version, indexes)?; diff --git a/crates/brk_computer/src/scripts/count/vecs.rs b/crates/brk_computer/src/scripts/count/vecs.rs index 3ad6f7a00..15aaccec5 100644 --- a/crates/brk_computer/src/scripts/count/vecs.rs +++ b/crates/brk_computer/src/scripts/count/vecs.rs @@ -6,7 +6,6 @@ use crate::internal::ComputedFromHeightCumulativeSum; #[derive(Traversable)] pub struct Vecs { - // Per-type output counts pub p2a: ComputedFromHeightCumulativeSum, pub p2ms: ComputedFromHeightCumulativeSum, pub p2pk33: ComputedFromHeightCumulativeSum, @@ -20,7 +19,5 @@ pub struct Vecs { pub emptyoutput: ComputedFromHeightCumulativeSum, pub unknownoutput: ComputedFromHeightCumulativeSum, - // Aggregate counts - /// SegWit output count (p2wpkh + p2wsh + p2tr) pub segwit: ComputedFromHeightCumulativeSum, } diff --git a/crates/brk_computer/src/scripts/import.rs b/crates/brk_computer/src/scripts/import.rs index 750624e9e..7ac4ad0e6 100644 --- a/crates/brk_computer/src/scripts/import.rs +++ b/crates/brk_computer/src/scripts/import.rs @@ -1,11 +1,12 @@ use std::path::Path; use brk_error::Result; -use brk_traversable::Traversable; use brk_types::Version; -use vecdb::{Database, PAGE_SIZE}; -use crate::indexes; +use crate::{ + indexes, + internal::{finalize_db, open_db}, +}; use super::{AdoptionVecs, CountVecs, ValueVecs, Vecs}; @@ -15,24 +16,20 @@ impl Vecs { parent_version: Version, indexes: &indexes::Vecs, ) -> Result { - let db = Database::open(&parent_path.join(super::DB_NAME))?; - db.set_min_len(PAGE_SIZE * 50_000_000)?; - + let db = open_db(parent_path, super::DB_NAME, 50_000_000)?; let version = parent_version; let count = CountVecs::forced_import(&db, version, indexes)?; let value = ValueVecs::forced_import(&db, version, indexes)?; let adoption = AdoptionVecs::forced_import(&db, version, indexes)?; - let this = Self { db, count, value, adoption }; - - this.db.retain_regions( - this.iter_any_exportable() - .flat_map(|v| v.region_names()) - .collect(), - )?; - this.db.compact()?; - + let this = Self { + db, + count, + value, + adoption, + }; + finalize_db(&this.db, &this)?; Ok(this) } } diff --git a/crates/brk_computer/src/scripts/value/compute.rs b/crates/brk_computer/src/scripts/value/compute.rs index 81749d64f..bc33485e7 100644 --- a/crates/brk_computer/src/scripts/value/compute.rs +++ b/crates/brk_computer/src/scripts/value/compute.rs @@ -1,7 +1,7 @@ use brk_error::Result; use brk_indexer::Indexer; use brk_types::{Height, Indexes, OutputType, Sats, TxOutIndex}; -use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, WritableVec, VecIndex}; +use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, VecIndex, WritableVec}; use super::Vecs; use crate::{blocks, prices}; @@ -17,9 +17,12 @@ impl Vecs { ) -> Result<()> { let window_starts = count_vecs.window_starts(); - self.opreturn - .compute(starting_indexes.height, &window_starts, prices, exit, |height_vec| { - + self.opreturn.compute( + starting_indexes.height, + &window_starts, + prices, + exit, + |height_vec| { // Validate computed versions against dependencies let dep_version = indexer.vecs.outputs.first_txoutindex.version() + indexer.vecs.outputs.outputtype.version() @@ -43,8 +46,12 @@ impl Vecs { } // Pre-collect height-indexed data - let first_txoutindexes: Vec = indexer.vecs.outputs.first_txoutindex - .collect_range_at(starting_height.to_usize(), target_height.to_usize() + 2.min(indexer.vecs.outputs.first_txoutindex.len())); + let first_txoutindexes: Vec = + indexer.vecs.outputs.first_txoutindex.collect_range_at( + starting_height.to_usize(), + target_height.to_usize() + + 2.min(indexer.vecs.outputs.first_txoutindex.len()), + ); // Iterate blocks for h in starting_height.to_usize()..=target_height.to_usize() { @@ -53,28 +60,35 @@ impl Vecs { // Get output range for this block let first_txoutindex = first_txoutindexes[local_idx]; - let next_first_txoutindex = if let Some(&next) = first_txoutindexes.get(local_idx + 1) { - next - } else { - TxOutIndex::from(indexer.vecs.outputs.value.len()) - }; + let next_first_txoutindex = + if let Some(&next) = first_txoutindexes.get(local_idx + 1) { + next + } else { + TxOutIndex::from(indexer.vecs.outputs.value.len()) + }; let out_start = first_txoutindex.to_usize(); let out_end = next_first_txoutindex.to_usize(); // Sum opreturn values — fold over both vecs without allocation - let opreturn_value = indexer.vecs.outputs.outputtype.fold_range_at( - out_start, out_end, - (Sats::ZERO, out_start), - |(sum, vi), ot| { - let new_sum = if ot == OutputType::OpReturn { - sum + indexer.vecs.outputs.value.collect_one_at(vi).unwrap() - } else { - sum - }; - (new_sum, vi + 1) - }, - ).0; + let opreturn_value = indexer + .vecs + .outputs + .outputtype + .fold_range_at( + out_start, + out_end, + (Sats::ZERO, out_start), + |(sum, vi), ot| { + let new_sum = if ot == OutputType::OpReturn { + sum + indexer.vecs.outputs.value.collect_one_at(vi).unwrap() + } else { + sum + }; + (new_sum, vi + 1) + }, + ) + .0; height_vec.truncate_push(height, opreturn_value)?; } @@ -82,7 +96,8 @@ impl Vecs { height_vec.write()?; Ok(()) - })?; + }, + )?; Ok(()) } diff --git a/crates/brk_computer/src/scripts/value/import.rs b/crates/brk_computer/src/scripts/value/import.rs index ce5729694..1837470c7 100644 --- a/crates/brk_computer/src/scripts/value/import.rs +++ b/crates/brk_computer/src/scripts/value/import.rs @@ -12,12 +12,7 @@ impl Vecs { indexes: &indexes::Vecs, ) -> Result { Ok(Self { - opreturn: ValueFromHeightFull::forced_import( - db, - "opreturn_value", - version, - indexes, - )?, + opreturn: ValueFromHeightFull::forced_import(db, "opreturn_value", version, indexes)?, }) } } diff --git a/crates/brk_computer/src/supply/burned/compute.rs b/crates/brk_computer/src/supply/burned/compute.rs index dc9fbd7e1..991d194d4 100644 --- a/crates/brk_computer/src/supply/burned/compute.rs +++ b/crates/brk_computer/src/supply/burned/compute.rs @@ -1,6 +1,6 @@ use brk_error::Result; use brk_types::{Height, Indexes, Sats}; -use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, WritableVec, VecIndex}; +use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, VecIndex, WritableVec}; use super::Vecs; use crate::{blocks, mining, prices, scripts}; @@ -18,8 +18,12 @@ impl Vecs { let window_starts = count_vecs.window_starts(); // 1. Compute opreturn supply - copy per-block opreturn values from scripts - self.opreturn - .compute(starting_indexes.height, &window_starts, prices, exit, |height_vec| { + self.opreturn.compute( + starting_indexes.height, + &window_starts, + prices, + exit, + |height_vec| { // Validate computed versions against dependencies let opreturn_dep_version = scripts.value.opreturn.base.sats.height.version(); @@ -37,7 +41,9 @@ impl Vecs { let start = starting_height.to_usize(); let end = target_height.to_usize() + 1; scripts.value.opreturn.base.sats.height.fold_range_at( - start, end, start, + start, + end, + start, |idx, value| { height_vec.truncate_push(Height::from(idx), value).unwrap(); idx + 1 @@ -48,15 +54,20 @@ impl Vecs { height_vec.write()?; Ok(()) - })?; + }, + )?; // 2. Compute unspendable supply = opreturn + unclaimed_rewards + genesis (at height 0) // Get reference to opreturn height vec for computing unspendable let opreturn_height = &self.opreturn.base.sats.height; let unclaimed_height = &mining.rewards.unclaimed_rewards.base.sats.height; - self.unspendable - .compute(starting_indexes.height, &window_starts, prices, exit, |height_vec| { + self.unspendable.compute( + starting_indexes.height, + &window_starts, + prices, + exit, + |height_vec| { let unspendable_dep_version = opreturn_height.version() + unclaimed_height.version(); height_vec.validate_computed_version_or_reset(unspendable_dep_version)?; @@ -72,22 +83,26 @@ impl Vecs { let start = starting_height.to_usize(); let end = target_height.to_usize() + 1; let unclaimed_data = unclaimed_height.collect_range_at(start, end); - opreturn_height.fold_range_at( - start, end, start, - |idx, opreturn| { - let unclaimed = unclaimed_data[idx - start]; - let genesis = if idx == 0 { Sats::FIFTY_BTC } else { Sats::ZERO }; - let unspendable = genesis + opreturn + unclaimed; - height_vec.truncate_push(Height::from(idx), unspendable).unwrap(); - idx + 1 - }, - ); + opreturn_height.fold_range_at(start, end, start, |idx, opreturn| { + let unclaimed = unclaimed_data[idx - start]; + let genesis = if idx == 0 { + Sats::FIFTY_BTC + } else { + Sats::ZERO + }; + let unspendable = genesis + opreturn + unclaimed; + height_vec + .truncate_push(Height::from(idx), unspendable) + .unwrap(); + idx + 1 + }); } } height_vec.write()?; Ok(()) - })?; + }, + )?; Ok(()) } diff --git a/crates/brk_computer/src/supply/burned/vecs.rs b/crates/brk_computer/src/supply/burned/vecs.rs index 3f21fff21..acb0a43ec 100644 --- a/crates/brk_computer/src/supply/burned/vecs.rs +++ b/crates/brk_computer/src/supply/burned/vecs.rs @@ -3,7 +3,6 @@ use vecdb::{Rw, StorageMode}; use crate::internal::ValueFromHeightCumulativeSum; -/// Burned/unspendable supply metrics #[derive(Traversable)] pub struct Vecs { pub opreturn: ValueFromHeightCumulativeSum, diff --git a/crates/brk_computer/src/supply/compute.rs b/crates/brk_computer/src/supply/compute.rs index 571d9ad9b..3db46c840 100644 --- a/crates/brk_computer/src/supply/compute.rs +++ b/crates/brk_computer/src/supply/compute.rs @@ -19,17 +19,26 @@ impl Vecs { exit: &Exit, ) -> Result<()> { // 1. Compute burned/unspendable supply - self.burned - .compute(scripts, mining, &blocks.count, prices, starting_indexes, exit)?; + self.burned.compute( + scripts, + mining, + &blocks.count, + prices, + starting_indexes, + exit, + )?; // 2. Compute inflation rate: (supply[h] / supply[1y_ago]) - 1 let circulating_supply = &distribution.utxo_cohorts.all.metrics.supply.total.sats; - self.inflation_rate.bps.height.compute_rolling_ratio_change( - starting_indexes.height, - &blocks.count.height_1y_ago, - &circulating_supply.height, - exit, - )?; + self.inflation_rate + .bps + .height + .compute_rolling_ratio_change( + starting_indexes.height, + &blocks.count.height_1y_ago, + &circulating_supply.height, + exit, + )?; // 3. Compute velocity at height level self.velocity @@ -52,17 +61,25 @@ impl Vecs { .compute_rolling_ratio_change( starting_indexes.height, &blocks.count.height_1y_ago, - &distribution.utxo_cohorts.all.metrics.realized.realized_cap.height, + &distribution + .utxo_cohorts + .all + .metrics + .realized + .realized_cap + .height, exit, )?; // 5. Compute cap growth rate diff: market - realized - self.market_minus_realized_cap_growth_rate.height.compute_subtract( - starting_indexes.height, - &self.market_cap_growth_rate.bps.height, - &self.realized_cap_growth_rate.bps.height, - exit, - )?; + self.market_minus_realized_cap_growth_rate + .height + .compute_subtract( + starting_indexes.height, + &self.market_cap_growth_rate.bps.height, + &self.realized_cap_growth_rate.bps.height, + exit, + )?; let _lock = exit.lock(); self.db.compact()?; diff --git a/crates/brk_computer/src/supply/import.rs b/crates/brk_computer/src/supply/import.rs index 94579088a..cdb3ea82c 100644 --- a/crates/brk_computer/src/supply/import.rs +++ b/crates/brk_computer/src/supply/import.rs @@ -1,19 +1,18 @@ use std::path::Path; use brk_error::Result; -use brk_traversable::Traversable; use brk_types::{Cents, Dollars, Sats, Version}; -use vecdb::{Database, PAGE_SIZE}; -use super::Vecs; use crate::{ distribution, indexes, internal::{ - ComputedFromHeight, Identity, LazyFromHeight, - LazyValueFromHeight, PercentFromHeight, SatsToBitcoin, + ComputedFromHeight, Identity, LazyFromHeight, LazyValueFromHeight, PercentFromHeight, + SatsToBitcoin, finalize_db, open_db, }, }; +use super::Vecs; + const VERSION: Version = Version::ONE; impl Vecs { @@ -23,8 +22,7 @@ impl Vecs { indexes: &indexes::Vecs, distribution: &distribution::Vecs, ) -> Result { - let db = Database::open(&parent.join(super::DB_NAME))?; - db.set_min_len(PAGE_SIZE * 10_000_000)?; + let db = open_db(parent, super::DB_NAME, 10_000_000)?; let version = parent_version + VERSION; let supply_metrics = &distribution.utxo_cohorts.all.metrics.supply; @@ -67,8 +65,12 @@ impl Vecs { version + Version::ONE, indexes, )?; - let market_minus_realized_cap_growth_rate = - ComputedFromHeight::forced_import(&db, "market_minus_realized_cap_growth_rate", version, indexes)?; + let market_minus_realized_cap_growth_rate = ComputedFromHeight::forced_import( + &db, + "market_minus_realized_cap_growth_rate", + version, + indexes, + )?; let this = Self { db, @@ -81,14 +83,7 @@ impl Vecs { realized_cap_growth_rate, market_minus_realized_cap_growth_rate, }; - - this.db.retain_regions( - this.iter_any_exportable() - .flat_map(|v| v.region_names()) - .collect(), - )?; - this.db.compact()?; - + finalize_db(&this.db, &this)?; Ok(this) } } diff --git a/crates/brk_computer/src/supply/vecs.rs b/crates/brk_computer/src/supply/vecs.rs index 4eec0ee01..8aaa1d961 100644 --- a/crates/brk_computer/src/supply/vecs.rs +++ b/crates/brk_computer/src/supply/vecs.rs @@ -3,9 +3,7 @@ use brk_types::{BasisPointsSigned32, Dollars}; use vecdb::{Database, Rw, StorageMode}; use super::{burned, velocity}; -use crate::internal::{ - ComputedFromHeight, LazyFromHeight, LazyValueFromHeight, PercentFromHeight, -}; +use crate::internal::{ComputedFromHeight, LazyFromHeight, LazyValueFromHeight, PercentFromHeight}; #[derive(Traversable)] pub struct Vecs { diff --git a/crates/brk_computer/src/supply/velocity/vecs.rs b/crates/brk_computer/src/supply/velocity/vecs.rs index 46b1d87eb..20412f8aa 100644 --- a/crates/brk_computer/src/supply/velocity/vecs.rs +++ b/crates/brk_computer/src/supply/velocity/vecs.rs @@ -4,7 +4,6 @@ use vecdb::{Rw, StorageMode}; use crate::internal::ComputedFromHeight; -/// Velocity metrics (annualized volume / circulating supply) #[derive(Traversable)] pub struct Vecs { pub btc: ComputedFromHeight, diff --git a/crates/brk_computer/src/traits/mod.rs b/crates/brk_computer/src/traits/mod.rs deleted file mode 100644 index cf3725f37..000000000 --- a/crates/brk_computer/src/traits/mod.rs +++ /dev/null @@ -1,245 +0,0 @@ -use brk_error::Result; -use brk_types::BasisPointsSigned16; -use vecdb::{ - AnyStoredVec, AnyVec, EagerVec, Exit, PcoVec, PcoVecValue, ReadableVec, VecIndex, VecValue, - WritableVec, -}; - -use crate::internal::algo::sliding_window::SlidingWindowSorted; - -pub trait ComputeRollingMedianFromStarts { - fn compute_rolling_median_from_starts( - &mut self, - max_from: I, - window_starts: &impl ReadableVec, - values: &impl ReadableVec, - exit: &Exit, - ) -> Result<()> - where - A: VecValue + Copy, - f64: From; -} - -impl ComputeRollingMedianFromStarts for EagerVec> -where - I: VecIndex, - T: PcoVecValue + From, -{ - fn compute_rolling_median_from_starts( - &mut self, - max_from: I, - window_starts: &impl ReadableVec, - values: &impl ReadableVec, - exit: &Exit, - ) -> Result<()> - where - A: VecValue + Copy, - f64: From, - { - self.validate_and_truncate(window_starts.version() + values.version(), max_from)?; - - self.repeat_until_complete(exit, |this| { - let skip = this.len(); - let end = window_starts.len().min(values.len()); - - let range_start = if skip > 0 { - window_starts.collect_one_at(skip - 1).unwrap().to_usize() - } else { - 0 - }; - let partial_values: Vec = values - .collect_range_at(range_start, end) - .into_iter() - .map(|a| f64::from(a)) - .collect(); - - let capacity = if skip > 0 && skip < end { - let first_start = window_starts.collect_one_at(skip).unwrap().to_usize(); - (skip + 1).saturating_sub(first_start) - } else if !partial_values.is_empty() { - partial_values.len().min(1024) - } else { - 0 - }; - - let mut window = SlidingWindowSorted::with_capacity(capacity); - - if skip > 0 { - window.reconstruct(&partial_values, range_start, skip); - } - - let starts_batch = window_starts.collect_range_at(skip, end); - - for (j, start) in starts_batch.into_iter().enumerate() { - let i = skip + j; - let v = partial_values[i - range_start]; - let start_usize = start.to_usize(); - window.advance(v, start_usize, &partial_values, range_start); - - let median = window.percentile(0.50); - this.checked_push_at(i, T::from(median))?; - - if this.batch_limit_reached() { - break; - } - } - - Ok(()) - })?; - - Ok(()) - } -} - -/// Compute all 8 rolling distribution stats (avg, min, max, p10, p25, median, p75, p90) -/// in a single sorted-vec pass per window. -#[allow(clippy::too_many_arguments)] -pub fn compute_rolling_distribution_from_starts( - max_from: I, - window_starts: &impl ReadableVec, - values: &impl ReadableVec, - average_out: &mut EagerVec>, - min_out: &mut EagerVec>, - max_out: &mut EagerVec>, - p10_out: &mut EagerVec>, - p25_out: &mut EagerVec>, - median_out: &mut EagerVec>, - p75_out: &mut EagerVec>, - p90_out: &mut EagerVec>, - exit: &Exit, -) -> Result<()> -where - I: VecIndex, - T: PcoVecValue + From, - A: VecValue + Copy, - f64: From, -{ - let version = window_starts.version() + values.version(); - - for v in [&mut *average_out, &mut *min_out, &mut *max_out, &mut *p10_out, &mut *p25_out, &mut *median_out, &mut *p75_out, &mut *p90_out] { - v.validate_and_truncate(version, max_from)?; - } - - let skip = [average_out.len(), min_out.len(), max_out.len(), p10_out.len(), p25_out.len(), median_out.len(), p75_out.len(), p90_out.len()] - .into_iter().min().unwrap(); - - let end = window_starts.len().min(values.len()); - if skip >= end { - return Ok(()); - } - - let range_start = if skip > 0 { - window_starts.collect_one_at(skip - 1).unwrap().to_usize() - } else { - 0 - }; - let partial_values: Vec = values - .collect_range_at(range_start, end) - .into_iter() - .map(|a| f64::from(a)) - .collect(); - - let capacity = if skip > 0 && skip < end { - let first_start = window_starts.collect_one_at(skip).unwrap().to_usize(); - (skip + 1).saturating_sub(first_start) - } else if !partial_values.is_empty() { - partial_values.len().min(1024) - } else { - 0 - }; - - let mut window = SlidingWindowSorted::with_capacity(capacity); - - if skip > 0 { - window.reconstruct(&partial_values, range_start, skip); - } - - let starts_batch = window_starts.collect_range_at(skip, end); - - for (j, start) in starts_batch.into_iter().enumerate() { - let i = skip + j; - let v = partial_values[i - range_start]; - let start_usize = start.to_usize(); - window.advance(v, start_usize, &partial_values, range_start); - - if window.is_empty() { - let zero = T::from(0.0); - for v in [&mut *average_out, &mut *min_out, &mut *max_out, &mut *p10_out, &mut *p25_out, &mut *median_out, &mut *p75_out, &mut *p90_out] { - v.checked_push_at(i, zero)?; - } - } else { - average_out.checked_push_at(i, T::from(window.average()))?; - min_out.checked_push_at(i, T::from(window.min()))?; - max_out.checked_push_at(i, T::from(window.max()))?; - p10_out.checked_push_at(i, T::from(window.percentile(0.10)))?; - p25_out.checked_push_at(i, T::from(window.percentile(0.25)))?; - median_out.checked_push_at(i, T::from(window.percentile(0.50)))?; - p75_out.checked_push_at(i, T::from(window.percentile(0.75)))?; - p90_out.checked_push_at(i, T::from(window.percentile(0.90)))?; - } - - if average_out.batch_limit_reached() { - let _lock = exit.lock(); - for v in [&mut *average_out, &mut *min_out, &mut *max_out, &mut *p10_out, &mut *p25_out, &mut *median_out, &mut *p75_out, &mut *p90_out] { - v.write()?; - } - } - } - - // Final flush - let _lock = exit.lock(); - for v in [average_out, min_out, max_out, p10_out, p25_out, median_out, p75_out, p90_out] { - v.write()?; - } - - Ok(()) -} - -pub trait ComputeDrawdown { - fn compute_drawdown( - &mut self, - max_from: I, - current: &impl ReadableVec, - ath: &impl ReadableVec, - exit: &Exit, - ) -> Result<()> - where - C: VecValue, - A: VecValue, - f64: From + From; -} - -impl ComputeDrawdown for EagerVec> -where - I: VecIndex, -{ - fn compute_drawdown( - &mut self, - max_from: I, - current: &impl ReadableVec, - ath: &impl ReadableVec, - exit: &Exit, - ) -> Result<()> - where - C: VecValue, - A: VecValue, - f64: From + From, - { - self.compute_transform2( - max_from, - current, - ath, - |(i, current, ath, _)| { - let ath_f64 = f64::from(ath); - let drawdown = if ath_f64 == 0.0 { - BasisPointsSigned16::default() - } else { - BasisPointsSigned16::from((f64::from(current) - ath_f64) / ath_f64) - }; - (i, drawdown) - }, - exit, - )?; - Ok(()) - } -} diff --git a/crates/brk_computer/src/transactions/compute.rs b/crates/brk_computer/src/transactions/compute.rs index 0db342a92..8e48fe9d1 100644 --- a/crates/brk_computer/src/transactions/compute.rs +++ b/crates/brk_computer/src/transactions/compute.rs @@ -33,14 +33,8 @@ impl Vecs { .compute(indexer, indexes, starting_indexes, exit)?; // Fees depends on size - self.fees.compute( - indexer, - indexes, - inputs, - &self.size, - starting_indexes, - exit, - )?; + self.fees + .compute(indexer, indexes, inputs, &self.size, starting_indexes, exit)?; // Volume depends on fees, counts, and blocks (lookback vecs, interval) self.volume.compute( diff --git a/crates/brk_computer/src/transactions/count/compute.rs b/crates/brk_computer/src/transactions/count/compute.rs index 46a2fff38..de713c993 100644 --- a/crates/brk_computer/src/transactions/count/compute.rs +++ b/crates/brk_computer/src/transactions/count/compute.rs @@ -15,19 +15,15 @@ impl Vecs { exit: &Exit, ) -> Result<()> { let window_starts = count_vecs.window_starts(); - self.tx_count.compute( - starting_indexes.height, - &window_starts, - exit, - |height| { + self.tx_count + .compute(starting_indexes.height, &window_starts, exit, |height| { Ok(height.compute_count_from_indexes( starting_indexes.height, &indexer.vecs.transactions.first_txindex, &indexer.vecs.transactions.txid, exit, )?) - }, - )?; + })?; Ok(()) } diff --git a/crates/brk_computer/src/transactions/count/import.rs b/crates/brk_computer/src/transactions/count/import.rs index 936519573..cb8e81706 100644 --- a/crates/brk_computer/src/transactions/count/import.rs +++ b/crates/brk_computer/src/transactions/count/import.rs @@ -17,16 +17,16 @@ impl Vecs { "is_coinbase", version, indexer.vecs.transactions.height.read_only_boxed_clone(), - indexer.vecs.transactions.first_txindex.read_only_boxed_clone(), - |index: TxIndex, _height, first_txindex| { - StoredBool::from(index == first_txindex) - }, + indexer + .vecs + .transactions + .first_txindex + .read_only_boxed_clone(), + |index: TxIndex, _height, first_txindex| StoredBool::from(index == first_txindex), ); Ok(Self { - tx_count: ComputedFromHeightFull::forced_import( - db, "tx_count", version, indexes, - )?, + tx_count: ComputedFromHeightFull::forced_import(db, "tx_count", version, indexes)?, is_coinbase: txindex_to_is_coinbase, }) } diff --git a/crates/brk_computer/src/transactions/fees/compute.rs b/crates/brk_computer/src/transactions/fees/compute.rs index d0c65d2d9..4fd962b31 100644 --- a/crates/brk_computer/src/transactions/fees/compute.rs +++ b/crates/brk_computer/src/transactions/fees/compute.rs @@ -58,22 +58,12 @@ impl Vecs { )?; // Skip coinbase (first tx per block) since it has fee=0 - self.fee.derive_from_with_skip( - indexer, - indexes, - starting_indexes, - exit, - 1, - )?; + self.fee + .derive_from_with_skip(indexer, indexes, starting_indexes, exit, 1)?; // Skip coinbase (first tx per block) since it has no feerate - self.fee_rate.derive_from_with_skip( - indexer, - indexes, - starting_indexes, - exit, - 1, - )?; + self.fee_rate + .derive_from_with_skip(indexer, indexes, starting_indexes, exit, 1)?; Ok(()) } diff --git a/crates/brk_computer/src/transactions/import.rs b/crates/brk_computer/src/transactions/import.rs index 9694f0d8d..a59656f29 100644 --- a/crates/brk_computer/src/transactions/import.rs +++ b/crates/brk_computer/src/transactions/import.rs @@ -2,11 +2,12 @@ use std::path::Path; use brk_error::Result; use brk_indexer::Indexer; -use brk_traversable::Traversable; use brk_types::Version; -use vecdb::{Database, PAGE_SIZE}; -use crate::indexes; +use crate::{ + indexes, + internal::{finalize_db, open_db}, +}; use super::{CountVecs, FeesVecs, SizeVecs, Vecs, VersionsVecs, VolumeVecs}; @@ -17,9 +18,7 @@ impl Vecs { indexer: &Indexer, indexes: &indexes::Vecs, ) -> Result { - let db = Database::open(&parent_path.join(super::DB_NAME))?; - db.set_min_len(PAGE_SIZE * 50_000_000)?; - + let db = open_db(parent_path, super::DB_NAME, 50_000_000)?; let version = parent_version; let count = CountVecs::forced_import(&db, version, indexer, indexes)?; @@ -36,14 +35,7 @@ impl Vecs { versions, volume, }; - - this.db.retain_regions( - this.iter_any_exportable() - .flat_map(|v| v.region_names()) - .collect(), - )?; - this.db.compact()?; - + finalize_db(&this.db, &this)?; Ok(this) } } diff --git a/crates/brk_computer/src/transactions/size/import.rs b/crates/brk_computer/src/transactions/size/import.rs index 619eeb2bb..476780532 100644 --- a/crates/brk_computer/src/transactions/size/import.rs +++ b/crates/brk_computer/src/transactions/size/import.rs @@ -1,7 +1,7 @@ use brk_error::Result; use brk_indexer::Indexer; use brk_types::{TxIndex, VSize, Version, Weight}; -use vecdb::{Database, ReadableCloneableVec, LazyVecFrom2}; +use vecdb::{Database, LazyVecFrom2, ReadableCloneableVec}; use super::Vecs; use crate::internal::LazyFromTxDistribution; @@ -17,9 +17,7 @@ impl Vecs { version, indexer.vecs.transactions.base_size.read_only_boxed_clone(), indexer.vecs.transactions.total_size.read_only_boxed_clone(), - |_index: TxIndex, base_size, total_size| { - Weight::from_sizes(*base_size, *total_size) - }, + |_index: TxIndex, base_size, total_size| Weight::from_sizes(*base_size, *total_size), ); let txindex_to_vsize = LazyVecFrom2::init( diff --git a/crates/brk_computer/src/transactions/versions/compute.rs b/crates/brk_computer/src/transactions/versions/compute.rs index 81e4a5f12..ed2220976 100644 --- a/crates/brk_computer/src/transactions/versions/compute.rs +++ b/crates/brk_computer/src/transactions/versions/compute.rs @@ -16,7 +16,8 @@ impl Vecs { ) -> Result<()> { let window_starts = count_vecs.window_starts(); - let tx_vany = |tx_vany: &mut ComputedFromHeightCumulativeSum, txversion: TxVersion| { + let tx_vany = |tx_vany: &mut ComputedFromHeightCumulativeSum, + txversion: TxVersion| { let txversion_vec = &indexer.vecs.transactions.txversion; // Cursor avoids per-transaction PcoVec page decompression. // Txindex values are sequential, so the cursor only advances forward. diff --git a/crates/brk_computer/src/transactions/versions/import.rs b/crates/brk_computer/src/transactions/versions/import.rs index fc9e4d01a..d5b33cfd1 100644 --- a/crates/brk_computer/src/transactions/versions/import.rs +++ b/crates/brk_computer/src/transactions/versions/import.rs @@ -6,7 +6,11 @@ use super::Vecs; use crate::{indexes, internal::ComputedFromHeightCumulativeSum}; impl Vecs { - pub(crate) fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { + pub(crate) fn forced_import( + db: &Database, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { Ok(Self { v1: ComputedFromHeightCumulativeSum::forced_import(db, "tx_v1", version, indexes)?, v2: ComputedFromHeightCumulativeSum::forced_import(db, "tx_v2", version, indexes)?, diff --git a/crates/brk_computer/src/transactions/volume/compute.rs b/crates/brk_computer/src/transactions/volume/compute.rs index 8890db3ea..b9df488b2 100644 --- a/crates/brk_computer/src/transactions/volume/compute.rs +++ b/crates/brk_computer/src/transactions/volume/compute.rs @@ -67,24 +67,30 @@ impl Vecs { self.annualized_volume .compute(prices, starting_indexes.height, exit)?; - self.tx_per_sec.height.compute_binary::<_, Timestamp, PerSec>( - starting_indexes.height, - &count_vecs.tx_count.height, - &blocks.interval.height, - exit, - )?; - self.inputs_per_sec.height.compute_binary::<_, Timestamp, PerSec>( - starting_indexes.height, - &inputs_count.full.sum, - &blocks.interval.height, - exit, - )?; - self.outputs_per_sec.height.compute_binary::<_, Timestamp, PerSec>( - starting_indexes.height, - &outputs_count.total_count.full.sum, - &blocks.interval.height, - exit, - )?; + self.tx_per_sec + .height + .compute_binary::<_, Timestamp, PerSec>( + starting_indexes.height, + &count_vecs.tx_count.height, + &blocks.interval.height, + exit, + )?; + self.inputs_per_sec + .height + .compute_binary::<_, Timestamp, PerSec>( + starting_indexes.height, + &inputs_count.full.sum, + &blocks.interval.height, + exit, + )?; + self.outputs_per_sec + .height + .compute_binary::<_, Timestamp, PerSec>( + starting_indexes.height, + &outputs_count.total_count.full.sum, + &blocks.interval.height, + exit, + )?; Ok(()) } diff --git a/crates/brk_computer/src/transactions/volume/import.rs b/crates/brk_computer/src/transactions/volume/import.rs index bc5a5d588..96306bba8 100644 --- a/crates/brk_computer/src/transactions/volume/import.rs +++ b/crates/brk_computer/src/transactions/volume/import.rs @@ -16,11 +16,12 @@ impl Vecs { ) -> Result { let v2 = Version::TWO; Ok(Self { - sent_sum: ValueFromHeightRolling::forced_import( - db, "sent_sum", version, indexes, - )?, + sent_sum: ValueFromHeightRolling::forced_import(db, "sent_sum", version, indexes)?, received_sum: ValueFromHeightRolling::forced_import( - db, "received_sum", version, indexes, + db, + "received_sum", + version, + indexes, )?, annualized_volume: ValueFromHeight::forced_import( db, @@ -28,12 +29,7 @@ impl Vecs { version, indexes, )?, - tx_per_sec: ComputedFromHeight::forced_import( - db, - "tx_per_sec", - version + v2, - indexes, - )?, + tx_per_sec: ComputedFromHeight::forced_import(db, "tx_per_sec", version + v2, indexes)?, outputs_per_sec: ComputedFromHeight::forced_import( db, "outputs_per_sec", diff --git a/crates/brk_computer/src/transactions/volume/vecs.rs b/crates/brk_computer/src/transactions/volume/vecs.rs index 4bb4218b2..586a4d6df 100644 --- a/crates/brk_computer/src/transactions/volume/vecs.rs +++ b/crates/brk_computer/src/transactions/volume/vecs.rs @@ -2,11 +2,8 @@ use brk_traversable::Traversable; use brk_types::StoredF32; use vecdb::{Rw, StorageMode}; -use crate::internal::{ - ComputedFromHeight, ValueFromHeight, ValueFromHeightRolling, -}; +use crate::internal::{ComputedFromHeight, ValueFromHeight, ValueFromHeightRolling}; -/// Volume metrics #[derive(Traversable)] pub struct Vecs { pub sent_sum: ValueFromHeightRolling, diff --git a/crates/brk_error/src/lib.rs b/crates/brk_error/src/lib.rs index 4be758dfb..786403c14 100644 --- a/crates/brk_error/src/lib.rs +++ b/crates/brk_error/src/lib.rs @@ -156,7 +156,6 @@ pub enum Error { }, } - impl Error { /// Returns true if this error is due to a file lock (another process has the database open). /// Lock errors are transient and should not trigger data deletion. diff --git a/crates/brk_fetcher/src/brk.rs b/crates/brk_fetcher/src/brk.rs index 97803f2bb..5e763daea 100644 --- a/crates/brk_fetcher/src/brk.rs +++ b/crates/brk_fetcher/src/brk.rs @@ -2,8 +2,7 @@ use std::collections::BTreeMap; use brk_error::{Error, Result}; use brk_types::{ - Cents, CheckedSub, Close, Date, Day1, Dollars, Height, High, Low, OHLCCents, Open, - Timestamp, + Cents, CheckedSub, Close, Date, Day1, Dollars, Height, High, Low, OHLCCents, Open, Timestamp, }; use serde_json::Value; use tracing::info; @@ -69,8 +68,7 @@ impl BRK { if !self.day1_to_ohlc.contains_key(&key) || ((key + self.day1_to_ohlc.get(&key).unwrap().len()) <= day1) { - self.day1_to_ohlc - .insert(key, Self::fetch_date_prices(key)?); + self.day1_to_ohlc.insert(key, Self::fetch_date_prices(key)?); } self.day1_to_ohlc diff --git a/crates/brk_indexer/src/processor/metadata.rs b/crates/brk_indexer/src/processor/metadata.rs index 61785c60a..f25657ab7 100644 --- a/crates/brk_indexer/src/processor/metadata.rs +++ b/crates/brk_indexer/src/processor/metadata.rs @@ -28,10 +28,9 @@ impl BlockProcessor<'_> { .blockhashprefix_to_height .insert(blockhash_prefix, height); - self.stores.height_to_coinbase_tag.insert( - height, - self.block.coinbase_tag().into(), - ); + self.stores + .height_to_coinbase_tag + .insert(height, self.block.coinbase_tag().into()); self.vecs .blocks @@ -52,8 +51,7 @@ impl BlockProcessor<'_> { /// Push block total_size and weight, reusing per-tx sizes already computed in ComputedTx. /// This avoids redundant tx serialization (base_size + total_size were already computed). pub fn push_block_size_and_weight(&mut self, txs: &[ComputedTx]) -> Result<()> { - let overhead = - bitcoin::block::Header::SIZE + bitcoin::VarInt::from(txs.len()).size(); + let overhead = bitcoin::block::Header::SIZE + bitcoin::VarInt::from(txs.len()).size(); let mut total_size = overhead; let mut weight_wu = overhead * 4; for ct in txs { diff --git a/crates/brk_indexer/src/processor/tx.rs b/crates/brk_indexer/src/processor/tx.rs index 3023a10a1..7233b2291 100644 --- a/crates/brk_indexer/src/processor/tx.rs +++ b/crates/brk_indexer/src/processor/tx.rs @@ -20,8 +20,7 @@ impl<'a> BlockProcessor<'a> { .par_iter() .enumerate() .map(|(index, tx)| { - let (btc_txid, base_size, total_size) = - self.block.compute_tx_id_and_sizes(index); + let (btc_txid, base_size, total_size) = self.block.compute_tx_id_and_sizes(index); let txid = Txid::from(btc_txid); let txid_prefix = TxidPrefix::from(&txid); @@ -105,8 +104,7 @@ pub(super) fn store_tx_metadata( md.txid.checked_push(ct.txindex, ct.txid)?; md.rawlocktime .checked_push(ct.txindex, ct.tx.lock_time.into())?; - md.base_size - .checked_push(ct.txindex, ct.base_size.into())?; + md.base_size.checked_push(ct.txindex, ct.base_size.into())?; md.total_size .checked_push(ct.txindex, ct.total_size.into())?; md.is_explicitly_rbf diff --git a/crates/brk_indexer/src/processor/types.rs b/crates/brk_indexer/src/processor/types.rs index f309a4438..4d5da9aed 100644 --- a/crates/brk_indexer/src/processor/types.rs +++ b/crates/brk_indexer/src/processor/types.rs @@ -56,4 +56,3 @@ pub struct BlockBuffers { pub already_added_addresses: ByAddressType>, pub same_block_output_info: FxHashMap, } - diff --git a/crates/brk_logger/src/lib.rs b/crates/brk_logger/src/lib.rs index 3e4e966f8..96f9258cb 100644 --- a/crates/brk_logger/src/lib.rs +++ b/crates/brk_logger/src/lib.rs @@ -31,9 +31,9 @@ pub fn init(path: Option<&Path>) -> io::Result<()> { ) }); - let filter: Targets = directives.parse().unwrap_or_else(|_| { - Targets::new().with_default(tracing::Level::INFO) - }); + let filter: Targets = directives + .parse() + .unwrap_or_else(|_| Targets::new().with_default(tracing::Level::INFO)); let registry = tracing_subscriber::registry() .with(filter) diff --git a/crates/brk_mempool/src/block_builder/graph.rs b/crates/brk_mempool/src/block_builder/graph.rs index 37e7c5b9d..e8621d605 100644 --- a/crates/brk_mempool/src/block_builder/graph.rs +++ b/crates/brk_mempool/src/block_builder/graph.rs @@ -4,7 +4,10 @@ use brk_types::TxidPrefix; use rustc_hash::FxHashMap; use super::tx_node::TxNode; -use crate::{entry::Entry, types::{PoolIndex, TxIndex}}; +use crate::{ + entry::Entry, + types::{PoolIndex, TxIndex}, +}; /// Type-safe wrapper around Vec that only allows PoolIndex access. pub struct Graph(Vec); diff --git a/crates/brk_mempool/src/block_builder/partitioner.rs b/crates/brk_mempool/src/block_builder/partitioner.rs index 041b2f8b8..a1aaa2131 100644 --- a/crates/brk_mempool/src/block_builder/partitioner.rs +++ b/crates/brk_mempool/src/block_builder/partitioner.rs @@ -9,7 +9,10 @@ const LOOK_AHEAD: usize = 100; /// Packages are sorted by fee rate descending, then placed into blocks. /// When a package doesn't fit, we look ahead for smaller packages that do. /// Atomic packages are never split across blocks. -pub fn partition_into_blocks(mut packages: Vec, num_blocks: usize) -> Vec> { +pub fn partition_into_blocks( + mut packages: Vec, + num_blocks: usize, +) -> Vec> { packages.sort_unstable_by(|a, b| b.fee_rate.cmp(&a.fee_rate)); let mut blocks: Vec> = Vec::with_capacity(num_blocks); diff --git a/crates/brk_mempool/src/projected_blocks/snapshot.rs b/crates/brk_mempool/src/projected_blocks/snapshot.rs index 5f83c5b2a..812c489d3 100644 --- a/crates/brk_mempool/src/projected_blocks/snapshot.rs +++ b/crates/brk_mempool/src/projected_blocks/snapshot.rs @@ -2,8 +2,14 @@ use std::hash::{DefaultHasher, Hash, Hasher}; use brk_types::RecommendedFees; -use super::{fees, stats::{self, BlockStats}}; -use crate::{entry::Entry, types::{SelectedTx, TxIndex}}; +use super::{ + fees, + stats::{self, BlockStats}, +}; +use crate::{ + entry::Entry, + types::{SelectedTx, TxIndex}, +}; /// Immutable snapshot of projected blocks. #[derive(Debug, Clone, Default)] diff --git a/crates/brk_oracle/examples/compare_digits.rs b/crates/brk_oracle/examples/compare_digits.rs index 99d584f81..db5d05476 100644 --- a/crates/brk_oracle/examples/compare_digits.rs +++ b/crates/brk_oracle/examples/compare_digits.rs @@ -161,21 +161,46 @@ fn main() { for h in START_HEIGHT..total_heights { let ft = first_txindex[h]; - let next_ft = first_txindex.get(h + 1).copied().unwrap_or(TxIndex::from(total_txs)); + let next_ft = first_txindex + .get(h + 1) + .copied() + .unwrap_or(TxIndex::from(total_txs)); let out_start = if ft.to_usize() + 1 < next_ft.to_usize() { - indexer.vecs.transactions.first_txoutindex.collect_one(ft + 1).unwrap().to_usize() + indexer + .vecs + .transactions + .first_txoutindex + .collect_one(ft + 1) + .unwrap() + .to_usize() } else { - out_first.get(h + 1).copied().unwrap_or(TxOutIndex::from(total_outputs)).to_usize() + out_first + .get(h + 1) + .copied() + .unwrap_or(TxOutIndex::from(total_outputs)) + .to_usize() }; - let out_end = out_first.get(h + 1).copied().unwrap_or(TxOutIndex::from(total_outputs)).to_usize(); + let out_end = out_first + .get(h + 1) + .copied() + .unwrap_or(TxOutIndex::from(total_outputs)) + .to_usize(); if h < earliest_start { continue; } - let values: Vec = indexer.vecs.outputs.value.collect_range_at(out_start, out_end); - let output_types: Vec = indexer.vecs.outputs.outputtype.collect_range_at(out_start, out_end); + let values: Vec = indexer + .vecs + .outputs + .value + .collect_range_at(out_start, out_end); + let output_types: Vec = indexer + .vecs + .outputs + .outputtype + .collect_range_at(out_start, out_end); // Build full histogram and per-digit histograms. let mut full_hist = [0u32; NUM_BINS]; diff --git a/crates/brk_oracle/examples/determinism.rs b/crates/brk_oracle/examples/determinism.rs index cdd14f738..e76026521 100644 --- a/crates/brk_oracle/examples/determinism.rs +++ b/crates/brk_oracle/examples/determinism.rs @@ -75,17 +75,42 @@ fn main() { for h in START_HEIGHT..end_height { let ft = first_txindex[h]; - let next_ft = first_txindex.get(h + 1).copied().unwrap_or(TxIndex::from(total_txs)); + let next_ft = first_txindex + .get(h + 1) + .copied() + .unwrap_or(TxIndex::from(total_txs)); let out_start = if ft.to_usize() + 1 < next_ft.to_usize() { - indexer.vecs.transactions.first_txoutindex.collect_one(ft + 1).unwrap().to_usize() + indexer + .vecs + .transactions + .first_txoutindex + .collect_one(ft + 1) + .unwrap() + .to_usize() } else { - out_first.get(h + 1).copied().unwrap_or(TxOutIndex::from(total_outputs)).to_usize() + out_first + .get(h + 1) + .copied() + .unwrap_or(TxOutIndex::from(total_outputs)) + .to_usize() }; - let out_end = out_first.get(h + 1).copied().unwrap_or(TxOutIndex::from(total_outputs)).to_usize(); + let out_end = out_first + .get(h + 1) + .copied() + .unwrap_or(TxOutIndex::from(total_outputs)) + .to_usize(); - let values: Vec = indexer.vecs.outputs.value.collect_range_at(out_start, out_end); - let output_types: Vec = indexer.vecs.outputs.outputtype.collect_range_at(out_start, out_end); + let values: Vec = indexer + .vecs + .outputs + .value + .collect_range_at(out_start, out_end); + let output_types: Vec = indexer + .vecs + .outputs + .outputtype + .collect_range_at(out_start, out_end); let mut hist = [0u32; NUM_BINS]; for (sats, output_type) in values.into_iter().zip(output_types) { @@ -125,10 +150,7 @@ fn main() { // Print results. println!(); - println!( - "{:<12} {:>16} {:>8}", - "Start", "Converged at", "Blocks" - ); + println!("{:<12} {:>16} {:>8}", "Start", "Converged at", "Blocks"); println!("{}", "-".repeat(40)); let mut max_blocks = 0usize; @@ -141,10 +163,7 @@ fn main() { if blocks > max_blocks { max_blocks = blocks; } - println!( - "{:<12} {:>16} {:>8}", - run.start_height, converged, blocks - ); + println!("{:<12} {:>16} {:>8}", run.start_height, converged, blocks); if run.diverged_after { diverged.push(run.start_height); } diff --git a/crates/brk_oracle/examples/sweep_digits.rs b/crates/brk_oracle/examples/sweep_digits.rs index b1b361248..2ce9c48fc 100644 --- a/crates/brk_oracle/examples/sweep_digits.rs +++ b/crates/brk_oracle/examples/sweep_digits.rs @@ -175,21 +175,46 @@ fn main() { for h in START_HEIGHT..total_heights { let ft = first_txindex[h]; - let next_ft = first_txindex.get(h + 1).copied().unwrap_or(TxIndex::from(total_txs)); + let next_ft = first_txindex + .get(h + 1) + .copied() + .unwrap_or(TxIndex::from(total_txs)); let out_start = if ft.to_usize() + 1 < next_ft.to_usize() { - indexer.vecs.transactions.first_txoutindex.collect_one(ft + 1).unwrap().to_usize() + indexer + .vecs + .transactions + .first_txoutindex + .collect_one(ft + 1) + .unwrap() + .to_usize() } else { - out_first.get(h + 1).copied().unwrap_or(TxOutIndex::from(total_outputs)).to_usize() + out_first + .get(h + 1) + .copied() + .unwrap_or(TxOutIndex::from(total_outputs)) + .to_usize() }; - let out_end = out_first.get(h + 1).copied().unwrap_or(TxOutIndex::from(total_outputs)).to_usize(); + let out_end = out_first + .get(h + 1) + .copied() + .unwrap_or(TxOutIndex::from(total_outputs)) + .to_usize(); if h < sweep_start { continue; } - let values: Vec = indexer.vecs.outputs.value.collect_range_at(out_start, out_end); - let output_types: Vec = indexer.vecs.outputs.outputtype.collect_range_at(out_start, out_end); + let values: Vec = indexer + .vecs + .outputs + .value + .collect_range_at(out_start, out_end); + let output_types: Vec = indexer + .vecs + .outputs + .outputtype + .collect_range_at(out_start, out_end); let mut full_hist = Box::new([0u32; NUM_BINS]); let mut round_outputs = Vec::new(); diff --git a/crates/brk_oracle/examples/sweep_tolerance.rs b/crates/brk_oracle/examples/sweep_tolerance.rs index 0fcf6e981..3d65c452b 100644 --- a/crates/brk_oracle/examples/sweep_tolerance.rs +++ b/crates/brk_oracle/examples/sweep_tolerance.rs @@ -177,21 +177,46 @@ fn main() { for h in START_HEIGHT..total_heights { let ft = first_txindex[h]; - let next_ft = first_txindex.get(h + 1).copied().unwrap_or(TxIndex::from(total_txs)); + let next_ft = first_txindex + .get(h + 1) + .copied() + .unwrap_or(TxIndex::from(total_txs)); let out_start = if ft.to_usize() + 1 < next_ft.to_usize() { - indexer.vecs.transactions.first_txoutindex.collect_one(ft + 1).unwrap().to_usize() + indexer + .vecs + .transactions + .first_txoutindex + .collect_one(ft + 1) + .unwrap() + .to_usize() } else { - out_first.get(h + 1).copied().unwrap_or(TxOutIndex::from(total_outputs)).to_usize() + out_first + .get(h + 1) + .copied() + .unwrap_or(TxOutIndex::from(total_outputs)) + .to_usize() }; - let out_end = out_first.get(h + 1).copied().unwrap_or(TxOutIndex::from(total_outputs)).to_usize(); + let out_end = out_first + .get(h + 1) + .copied() + .unwrap_or(TxOutIndex::from(total_outputs)) + .to_usize(); if h < sweep_start { continue; } - let values: Vec = indexer.vecs.outputs.value.collect_range_at(out_start, out_end); - let output_types: Vec = indexer.vecs.outputs.outputtype.collect_range_at(out_start, out_end); + let values: Vec = indexer + .vecs + .outputs + .value + .collect_range_at(out_start, out_end); + let output_types: Vec = indexer + .vecs + .outputs + .outputtype + .collect_range_at(out_start, out_end); let mut full_hist = Box::new([0u32; NUM_BINS]); let mut round_outputs = Vec::new(); @@ -330,9 +355,7 @@ fn main() { // Remove outputs matching this tolerance + mask. let tol_f32 = tolerance as f32; for ro in &bd.round_outputs { - if mask & (1 << (ro.digit - 1)) != 0 - && ro.rel_err <= tol_f32 - { + if mask & (1 << (ro.digit - 1)) != 0 && ro.rel_err <= tol_f32 { hist[ro.bin as usize] -= 1; } } @@ -417,9 +440,7 @@ fn main() { // Show current config for reference. let current = all_results .iter() - .find(|(t, m, _)| { - tolerances[*t].0 == 0.001 && masks[*m].0 == 0b0_0011_0111 - }) + .find(|(t, m, _)| tolerances[*t].0 == 0.001 && masks[*m].0 == 0b0_0011_0111) .unwrap(); let (_, _, cs) = current; println!( diff --git a/crates/brk_oracle/examples/validate.rs b/crates/brk_oracle/examples/validate.rs index ac7fce9f1..e4224d671 100644 --- a/crates/brk_oracle/examples/validate.rs +++ b/crates/brk_oracle/examples/validate.rs @@ -9,7 +9,7 @@ use std::path::PathBuf; use brk_indexer::Indexer; -use brk_oracle::{cents_to_bin, sats_to_bin, Config, Oracle, NUM_BINS, PRICES, START_HEIGHT}; +use brk_oracle::{Config, NUM_BINS, Oracle, PRICES, START_HEIGHT, cents_to_bin, sats_to_bin}; use brk_types::{OutputType, Sats, TxIndex, TxOutIndex}; use vecdb::{AnyVec, ReadableVec, VecIndex}; @@ -127,9 +127,24 @@ fn main() { .collect(); let mut runs = vec![ - Run { label: "w12 @ 575k", start_height: 575_000, oracle: None, stats: Stats::new() }, - Run { label: "w12 @ 600k", start_height: 600_000, oracle: None, stats: Stats::new() }, - Run { label: "w12 @ 630k", start_height: 630_000, oracle: None, stats: Stats::new() }, + Run { + label: "w12 @ 575k", + start_height: 575_000, + oracle: None, + stats: Stats::new(), + }, + Run { + label: "w12 @ 600k", + start_height: 600_000, + oracle: None, + stats: Stats::new(), + }, + Run { + label: "w12 @ 630k", + start_height: 630_000, + oracle: None, + stats: Stats::new(), + }, ]; // Build per-block filtered histograms from the indexer, feeding all oracles in one pass. @@ -144,18 +159,43 @@ fn main() { for h in START_HEIGHT..total_heights { let ft = first_txindex[h]; - let next_ft = first_txindex.get(h + 1).copied().unwrap_or(TxIndex::from(total_txs)); + let next_ft = first_txindex + .get(h + 1) + .copied() + .unwrap_or(TxIndex::from(total_txs)); let out_start = if ft.to_usize() + 1 < next_ft.to_usize() { - indexer.vecs.transactions.first_txoutindex.collect_one(ft + 1).unwrap().to_usize() + indexer + .vecs + .transactions + .first_txoutindex + .collect_one(ft + 1) + .unwrap() + .to_usize() } else { - out_first.get(h + 1).copied().unwrap_or(TxOutIndex::from(total_outputs)).to_usize() + out_first + .get(h + 1) + .copied() + .unwrap_or(TxOutIndex::from(total_outputs)) + .to_usize() }; - let out_end = out_first.get(h + 1).copied().unwrap_or(TxOutIndex::from(total_outputs)).to_usize(); + let out_end = out_first + .get(h + 1) + .copied() + .unwrap_or(TxOutIndex::from(total_outputs)) + .to_usize(); // Build filtered histogram once for all oracles. - let values: Vec = indexer.vecs.outputs.value.collect_range_at(out_start, out_end); - let output_types: Vec = indexer.vecs.outputs.outputtype.collect_range_at(out_start, out_end); + let values: Vec = indexer + .vecs + .outputs + .value + .collect_range_at(out_start, out_end); + let output_types: Vec = indexer + .vecs + .outputs + .outputtype + .collect_range_at(out_start, out_end); let mut hist = [0u32; NUM_BINS]; for (sats, output_type) in values.into_iter().zip(output_types) { @@ -233,9 +273,21 @@ fn main() { for (run, &(label, exp_5, exp_10, exp_20)) in runs.iter().zip(expected) { let s = &run.stats; - assert_eq!(s.gt_20pct, exp_20, "{label}: expected {exp_20} blocks >20%, got {}", s.gt_20pct); - assert_eq!(s.gt_10pct, exp_10, "{label}: expected {exp_10} blocks >10%, got {}", s.gt_10pct); - assert_eq!(s.gt_5pct, exp_5, "{label}: expected {exp_5} blocks >5%, got {}", s.gt_5pct); + assert_eq!( + s.gt_20pct, exp_20, + "{label}: expected {exp_20} blocks >20%, got {}", + s.gt_20pct + ); + assert_eq!( + s.gt_10pct, exp_10, + "{label}: expected {exp_10} blocks >10%, got {}", + s.gt_10pct + ); + assert_eq!( + s.gt_5pct, exp_5, + "{label}: expected {exp_5} blocks >5%, got {}", + s.gt_5pct + ); } println!("All assertions passed!"); diff --git a/crates/brk_query/src/impl/address.rs b/crates/brk_query/src/impl/address.rs index 684be2dd5..3b2d9b219 100644 --- a/crates/brk_query/src/impl/address.rs +++ b/crates/brk_query/src/impl/address.rs @@ -175,12 +175,20 @@ impl Query { .into_iter() .map(|(txindex, vout)| { let txid: Txid = txid_reader.get(txindex.to_usize()); - let height = vecs.transactions.height.collect_one_at(txindex.to_usize()).unwrap(); + let height = vecs + .transactions + .height + .collect_one_at(txindex.to_usize()) + .unwrap(); let first_txoutindex = first_txoutindex_reader.get(txindex.to_usize()); let txoutindex = first_txoutindex + vout; let value: Sats = value_reader.get(usize::from(txoutindex)); let block_hash = blockhash_reader.get(usize::from(height)); - let block_time = vecs.blocks.timestamp.collect_one_at(usize::from(height)).unwrap(); + let block_time = vecs + .blocks + .timestamp + .collect_one_at(usize::from(height)) + .unwrap(); Utxo { txid, diff --git a/crates/brk_query/src/impl/block/raw.rs b/crates/brk_query/src/impl/block/raw.rs index ef4ec0c5a..184338644 100644 --- a/crates/brk_query/src/impl/block/raw.rs +++ b/crates/brk_query/src/impl/block/raw.rs @@ -20,7 +20,11 @@ impl Query { return Err(Error::OutOfRange("Block height out of range".into())); } - let position = computer.positions.block_position.collect_one(height).unwrap(); + let position = computer + .positions + .block_position + .collect_one(height) + .unwrap(); let size = indexer.vecs.blocks.total_size.collect_one(height).unwrap(); reader.read_raw_bytes(position, *size as usize) diff --git a/crates/brk_query/src/impl/block/status.rs b/crates/brk_query/src/impl/block/status.rs index 51ec38167..61eecc6c1 100644 --- a/crates/brk_query/src/impl/block/status.rs +++ b/crates/brk_query/src/impl/block/status.rs @@ -13,14 +13,7 @@ impl Query { fn block_status_by_height(&self, height: Height) -> Result { let indexer = self.indexer(); - let max_height = Height::from( - indexer - .vecs - .blocks - .blockhash - .len() - .saturating_sub(1), - ); + let max_height = Height::from(indexer.vecs.blocks.blockhash.len().saturating_sub(1)); if height > max_height { return Ok(BlockStatus::not_in_best_chain()); diff --git a/crates/brk_query/src/impl/block/timestamp.rs b/crates/brk_query/src/impl/block/timestamp.rs index 4d9b93b76..e82410a87 100644 --- a/crates/brk_query/src/impl/block/timestamp.rs +++ b/crates/brk_query/src/impl/block/timestamp.rs @@ -57,7 +57,12 @@ impl Query { } let height = Height::from(best_height); - let blockhash = indexer.vecs.blocks.blockhash.reader().get(usize::from(height)); + let blockhash = indexer + .vecs + .blocks + .blockhash + .reader() + .get(usize::from(height)); // Convert timestamp to ISO 8601 format let ts_secs: i64 = (*best_ts).into(); diff --git a/crates/brk_query/src/impl/block/txs.rs b/crates/brk_query/src/impl/block/txs.rs index 2639bc390..64884428b 100644 --- a/crates/brk_query/src/impl/block/txs.rs +++ b/crates/brk_query/src/impl/block/txs.rs @@ -31,7 +31,12 @@ impl Query { return Err(Error::OutOfRange("Block height out of range".into())); } - let first_txindex = indexer.vecs.transactions.first_txindex.collect_one(height).unwrap(); + let first_txindex = indexer + .vecs + .transactions + .first_txindex + .collect_one(height) + .unwrap(); let next_first_txindex = indexer .vecs .transactions @@ -42,20 +47,12 @@ impl Query { let first: usize = first_txindex.into(); let next: usize = next_first_txindex.into(); - let txids: Vec = indexer - .vecs - .transactions - .txid - .collect_range_at(first, next); + let txids: Vec = indexer.vecs.transactions.txid.collect_range_at(first, next); Ok(txids) } - fn block_txs_by_height( - &self, - height: Height, - start_index: usize, - ) -> Result> { + fn block_txs_by_height(&self, height: Height, start_index: usize) -> Result> { let indexer = self.indexer(); let max_height = self.height(); @@ -63,7 +60,12 @@ impl Query { return Err(Error::OutOfRange("Block height out of range".into())); } - let first_txindex = indexer.vecs.transactions.first_txindex.collect_one(height).unwrap(); + let first_txindex = indexer + .vecs + .transactions + .first_txindex + .collect_one(height) + .unwrap(); let next_first_txindex = indexer .vecs .transactions @@ -100,7 +102,12 @@ impl Query { return Err(Error::OutOfRange("Block height out of range".into())); } - let first_txindex = indexer.vecs.transactions.first_txindex.collect_one(height).unwrap(); + let first_txindex = indexer + .vecs + .transactions + .first_txindex + .collect_one(height) + .unwrap(); let next_first_txindex = indexer .vecs .transactions diff --git a/crates/brk_query/src/impl/mempool.rs b/crates/brk_query/src/impl/mempool.rs index 03be4ed3d..f4b10584e 100644 --- a/crates/brk_query/src/impl/mempool.rs +++ b/crates/brk_query/src/impl/mempool.rs @@ -29,7 +29,12 @@ impl Query { let blocks = block_stats .into_iter() .map(|stats| { - MempoolBlock::new(stats.tx_count, stats.total_vsize, stats.total_fee, stats.fee_range) + MempoolBlock::new( + stats.tx_count, + stats.total_vsize, + stats.total_fee, + stats.fee_range, + ) }) .collect(); diff --git a/crates/brk_query/src/impl/mining/block_rewards.rs b/crates/brk_query/src/impl/mining/block_rewards.rs index 3d1bb1d8c..3d4044448 100644 --- a/crates/brk_query/src/impl/mining/block_rewards.rs +++ b/crates/brk_query/src/impl/mining/block_rewards.rs @@ -27,11 +27,13 @@ impl Query { .day1; Ok(iter.collect(|di, ts, h| { - rewards_vec.collect_one_flat(di).map(|reward| BlockRewardsEntry { - avg_height: h.into(), - timestamp: *ts, - avg_rewards: *reward, - }) + rewards_vec + .collect_one_flat(di) + .map(|reward| BlockRewardsEntry { + avg_height: h.into(), + timestamp: *ts, + avg_rewards: *reward, + }) })) } } diff --git a/crates/brk_query/src/impl/mining/hashrate.rs b/crates/brk_query/src/impl/mining/hashrate.rs index ac55deae8..c749f10e0 100644 --- a/crates/brk_query/src/impl/mining/hashrate.rs +++ b/crates/brk_query/src/impl/mining/hashrate.rs @@ -12,7 +12,12 @@ impl Query { let current_height = self.height(); // Get current difficulty - let current_difficulty = *indexer.vecs.blocks.difficulty.collect_one(current_height).unwrap(); + let current_difficulty = *indexer + .vecs + .blocks + .difficulty + .collect_one(current_height) + .unwrap(); // Get current hashrate let current_day1 = computer @@ -47,10 +52,7 @@ impl Query { let end_day1 = current_day1; // Sample at regular intervals to avoid too many data points - let total_days = end_day1 - .to_usize() - .saturating_sub(start_day1.to_usize()) - + 1; + let total_days = end_day1.to_usize().saturating_sub(start_day1.to_usize()) + 1; let step = (total_days / 200).max(1); // Max ~200 data points let hashrate_vec = &computer.mining.hashrate.hash_rate.day1; @@ -60,9 +62,10 @@ impl Query { let mut di = start_day1.to_usize(); while di <= end_day1.to_usize() { let day1 = Day1::from(di); - if let (Some(hr), Some(timestamp)) = - (hashrate_vec.collect_one_flat(day1), timestamp_vec.collect_one(day1)) - { + if let (Some(hr), Some(timestamp)) = ( + hashrate_vec.collect_one_flat(day1), + timestamp_vec.collect_one(day1), + ) { hashrates.push(HashrateEntry { timestamp, avg_hashrate: *hr as u128, diff --git a/crates/brk_query/src/impl/mining/pools.rs b/crates/brk_query/src/impl/mining/pools.rs index caf2b4649..276d8496a 100644 --- a/crates/brk_query/src/impl/mining/pools.rs +++ b/crates/brk_query/src/impl/mining/pools.rs @@ -30,16 +30,16 @@ impl Query { // For each pool, get cumulative count at end and start, subtract to get range count for (pool_id, pool_vecs) in &computer.pools.vecs { - let cumulative = &pool_vecs - .blocks_mined - .cumulative.height; + let cumulative = &pool_vecs.blocks_mined.cumulative.height; let count_at_end: u32 = *cumulative.collect_one(current_height).unwrap_or_default(); let count_at_start: u32 = if start == 0 { 0 } else { - *cumulative.collect_one(Height::from(start - 1)).unwrap_or_default() + *cumulative + .collect_one(Height::from(start - 1)) + .unwrap_or_default() }; let block_count = count_at_end.saturating_sub(count_at_start); @@ -98,9 +98,7 @@ impl Query { .get(&slug) .ok_or_else(|| Error::NotFound("Pool data not found".into()))?; - let cumulative = &pool_vecs - .blocks_mined - .cumulative.height; + let cumulative = &pool_vecs.blocks_mined.cumulative.height; // Get total blocks (all time) let total_all: u32 = *cumulative.collect_one(current_height).unwrap_or_default(); diff --git a/crates/brk_query/src/impl/transaction.rs b/crates/brk_query/src/impl/transaction.rs index 997fd9207..800fcf103 100644 --- a/crates/brk_query/src/impl/transaction.rs +++ b/crates/brk_query/src/impl/transaction.rs @@ -55,7 +55,12 @@ impl Query { }; // Get block info for status - let height = indexer.vecs.transactions.height.collect_one(txindex).unwrap(); + let height = indexer + .vecs + .transactions + .height + .collect_one(txindex) + .unwrap(); let block_hash = indexer.vecs.blocks.blockhash.read_once(height)?; let block_time = indexer.vecs.blocks.timestamp.collect_one(height).unwrap(); @@ -191,10 +196,30 @@ impl Query { // Get tx metadata using collect_one for PcoVec, read_once for BytesVec let txid = indexer.vecs.transactions.txid.read_once(txindex)?; - let height = indexer.vecs.transactions.height.collect_one(txindex).unwrap(); - let version = indexer.vecs.transactions.txversion.collect_one(txindex).unwrap(); - let lock_time = indexer.vecs.transactions.rawlocktime.collect_one(txindex).unwrap(); - let total_size = indexer.vecs.transactions.total_size.collect_one(txindex).unwrap(); + let height = indexer + .vecs + .transactions + .height + .collect_one(txindex) + .unwrap(); + let version = indexer + .vecs + .transactions + .txversion + .collect_one(txindex) + .unwrap(); + let lock_time = indexer + .vecs + .transactions + .rawlocktime + .collect_one(txindex) + .unwrap(); + let total_size = indexer + .vecs + .transactions + .total_size + .collect_one(txindex) + .unwrap(); let first_txinindex = indexer .vecs .transactions @@ -243,7 +268,8 @@ impl Query { let prev_txid = txid_reader.get(prev_txindex.to_usize()); // Calculate the txoutindex for the prevout - let prev_first_txoutindex = first_txoutindex_reader.get(prev_txindex.to_usize()); + let prev_first_txoutindex = + first_txoutindex_reader.get(prev_txindex.to_usize()); let prev_txoutindex = prev_first_txoutindex + prev_vout; // Get the value of the prevout @@ -312,7 +338,12 @@ impl Query { let reader = self.reader(); let computer = self.computer(); - let total_size = indexer.vecs.transactions.total_size.collect_one(txindex).unwrap(); + let total_size = indexer + .vecs + .transactions + .total_size + .collect_one(txindex) + .unwrap(); let position = computer.positions.tx_position.collect_one(txindex).unwrap(); let buffer = reader.read_raw_bytes(position, *total_size as usize)?; @@ -344,7 +375,12 @@ impl Query { .collect_one(spending_txindex) .unwrap(); let block_hash = indexer.vecs.blocks.blockhash.read_once(spending_height)?; - let block_time = indexer.vecs.blocks.timestamp.collect_one(spending_height).unwrap(); + let block_time = indexer + .vecs + .blocks + .timestamp + .collect_one(spending_height) + .unwrap(); Ok(TxOutspend { spent: true, diff --git a/crates/brk_reader/src/lib.rs b/crates/brk_reader/src/lib.rs index 6c39b75f2..9b1363b29 100644 --- a/crates/brk_reader/src/lib.rs +++ b/crates/brk_reader/src/lib.rs @@ -208,9 +208,10 @@ impl ReaderInner { .into_iter() .par_bridge() .try_for_each(|(metadata, bytes, xor_i)| { - if let Ok(Some(block)) = - decode_block(bytes, metadata, &client, xor_i, xor_bytes, start, end, start_time, end_time) - && send_block.send(block).is_err() + if let Ok(Some(block)) = decode_block( + bytes, metadata, &client, xor_i, xor_bytes, start, end, start_time, + end_time, + ) && send_block.send(block).is_err() { return ControlFlow::Break(()); } @@ -335,7 +336,11 @@ impl ReaderInner { Ok(blk_indices.get(final_idx).copied().unwrap_or(0)) } - pub fn get_first_block_height(&self, blk_path: &PathBuf, xor_bytes: XORBytes) -> Result { + pub fn get_first_block_height( + &self, + blk_path: &PathBuf, + xor_bytes: XORBytes, + ) -> Result { let mut file = File::open(blk_path)?; let mut buf = [0u8; 4096]; let n = file.read(&mut buf)?; diff --git a/crates/brk_rpc/src/backend/corepc.rs b/crates/brk_rpc/src/backend/corepc.rs index 461600b73..d7876905b 100644 --- a/crates/brk_rpc/src/backend/corepc.rs +++ b/crates/brk_rpc/src/backend/corepc.rs @@ -194,9 +194,7 @@ impl ClientInner { .previous_block_hash .map(|s| s.parse::()) .transpose() - .map_err(|_| { - corepc_client::client_sync::Error::UnexpectedStructure - })?; + .map_err(|_| corepc_client::client_sync::Error::UnexpectedStructure)?; Ok(BlockHeaderInfo { height: r.height as usize, confirmations: r.confirmations, @@ -224,10 +222,8 @@ impl ClientInner { match r { Some(r) => { - let script_pub_key = - bitcoin::ScriptBuf::from_hex(&r.script_pub_key.hex).map_err(|_| { - corepc_client::client_sync::Error::UnexpectedStructure - })?; + let script_pub_key = bitcoin::ScriptBuf::from_hex(&r.script_pub_key.hex) + .map_err(|_| corepc_client::client_sync::Error::UnexpectedStructure)?; let sats = (r.value * 100_000_000.0).round() as u64; Ok(Some(TxOutInfo { coinbase: r.coinbase, @@ -243,9 +239,8 @@ impl ClientInner { let r = self.call_with_retry(|c| c.get_raw_mempool())?; r.0.iter() .map(|s| { - s.parse::().map_err(|_| { - corepc_client::client_sync::Error::UnexpectedStructure.into() - }) + s.parse::() + .map_err(|_| corepc_client::client_sync::Error::UnexpectedStructure.into()) }) .collect() } @@ -254,16 +249,15 @@ impl ClientInner { let r = self.call_with_retry(|c| c.get_raw_mempool_verbose())?; r.0.into_iter() .map(|(txid_str, entry)| { - let txid = txid_str.parse::().map_err(|_| { - corepc_client::client_sync::Error::UnexpectedStructure - })?; + let txid = txid_str + .parse::() + .map_err(|_| corepc_client::client_sync::Error::UnexpectedStructure)?; let depends = entry .depends .iter() .map(|s| { - s.parse::().map_err(|_| { - corepc_client::client_sync::Error::UnexpectedStructure - }) + s.parse::() + .map_err(|_| corepc_client::client_sync::Error::UnexpectedStructure) }) .collect::, _>>()?; Ok(( diff --git a/crates/brk_rpc/src/lib.rs b/crates/brk_rpc/src/lib.rs index 34e263ea7..8aab50818 100644 --- a/crates/brk_rpc/src/lib.rs +++ b/crates/brk_rpc/src/lib.rs @@ -75,9 +75,7 @@ impl Client { where H: Into + Copy, { - self.0 - .get_block_hash(height.into()) - .map(BlockHash::from) + self.0.get_block_hash(height.into()).map(BlockHash::from) } pub fn get_block_header<'a, H>(&self, hash: &'a H) -> Result @@ -192,16 +190,18 @@ impl Client { let result = self.0.get_raw_mempool_verbose()?; Ok(result .into_iter() - .map(|(txid, entry): (bitcoin::Txid, backend::RawMempoolEntry)| MempoolEntryInfo { - txid: txid.into(), - vsize: entry.vsize, - weight: entry.weight, - fee: Sats::from(entry.base_fee_sats), - ancestor_count: entry.ancestor_count, - ancestor_size: entry.ancestor_size, - ancestor_fee: Sats::from(entry.ancestor_fee_sats), - depends: entry.depends.into_iter().map(Txid::from).collect(), - }) + .map( + |(txid, entry): (bitcoin::Txid, backend::RawMempoolEntry)| MempoolEntryInfo { + txid: txid.into(), + vsize: entry.vsize, + weight: entry.weight, + fee: Sats::from(entry.base_fee_sats), + ancestor_count: entry.ancestor_count, + ancestor_size: entry.ancestor_size, + ancestor_fee: Sats::from(entry.ancestor_fee_sats), + depends: entry.depends.into_iter().map(Txid::from).collect(), + }, + ) .collect()) } diff --git a/crates/brk_server/src/api/mempool/mod.rs b/crates/brk_server/src/api/mempool/mod.rs index 24feb88a8..c1ac5a7b6 100644 --- a/crates/brk_server/src/api/mempool/mod.rs +++ b/crates/brk_server/src/api/mempool/mod.rs @@ -1,5 +1,10 @@ use aide::axum::{ApiRouter, routing::get_with}; -use axum::{extract::State, http::{HeaderMap, Uri}, response::Redirect, routing::get}; +use axum::{ + extract::State, + http::{HeaderMap, Uri}, + response::Redirect, + routing::get, +}; use brk_types::{Dollars, MempoolBlock, MempoolInfo, RecommendedFees, Txid}; use crate::extended::TransformResponseExtended; diff --git a/crates/brk_server/src/api/metrics/bulk.rs b/crates/brk_server/src/api/metrics/bulk.rs index af976f0a4..62dc39fa8 100644 --- a/crates/brk_server/src/api/metrics/bulk.rs +++ b/crates/brk_server/src/api/metrics/bulk.rs @@ -25,7 +25,9 @@ pub async fn handler( State(state): State, ) -> Result { // Phase 1: Search and resolve metadata (cheap) - let resolved = state.run(move |q| q.resolve(params, max_weight(&addr))).await?; + let resolved = state + .run(move |q| q.resolve(params, max_weight(&addr))) + .await?; let format = resolved.format(); let etag = resolved.etag(); diff --git a/crates/brk_server/src/api/metrics/data.rs b/crates/brk_server/src/api/metrics/data.rs index 3a4e5282e..db1b3a569 100644 --- a/crates/brk_server/src/api/metrics/data.rs +++ b/crates/brk_server/src/api/metrics/data.rs @@ -25,7 +25,9 @@ pub async fn handler( State(state): State, ) -> Result { // Phase 1: Search and resolve metadata (cheap) - let resolved = state.run(move |q| q.resolve(params, max_weight(&addr))).await?; + let resolved = state + .run(move |q| q.resolve(params, max_weight(&addr))) + .await?; let format = resolved.format(); let etag = resolved.etag(); diff --git a/crates/brk_server/src/api/metrics/legacy.rs b/crates/brk_server/src/api/metrics/legacy.rs index c190b132c..e8c397414 100644 --- a/crates/brk_server/src/api/metrics/legacy.rs +++ b/crates/brk_server/src/api/metrics/legacy.rs @@ -25,7 +25,9 @@ pub async fn handler( State(state): State, ) -> Result { // Phase 1: Search and resolve metadata (cheap) - let resolved = state.run(move |q| q.resolve(params, max_weight(&addr))).await?; + let resolved = state + .run(move |q| q.resolve(params, max_weight(&addr))) + .await?; let format = resolved.format(); let etag = resolved.etag(); diff --git a/crates/brk_server/src/api/server/mod.rs b/crates/brk_server/src/api/server/mod.rs index 240c8f3d6..9ac3dac81 100644 --- a/crates/brk_server/src/api/server/mod.rs +++ b/crates/brk_server/src/api/server/mod.rs @@ -1,7 +1,10 @@ use std::{borrow::Cow, fs, path}; use aide::axum::{ApiRouter, routing::get_with}; -use axum::{extract::State, http::{HeaderMap, Uri}}; +use axum::{ + extract::State, + http::{HeaderMap, Uri}, +}; use brk_types::{DiskUsage, Health, Height, SyncStatus}; use vecdb::ReadableVec; diff --git a/crates/brk_server/src/lib.rs b/crates/brk_server/src/lib.rs index 226c40674..69ae70005 100644 --- a/crates/brk_server/src/lib.rs +++ b/crates/brk_server/src/lib.rs @@ -76,9 +76,7 @@ impl Server { // When behind a reverse proxy (e.g. cloudflared), the direct // connection comes from loopback but the request is external. // Mark it as non-loopback so it gets the stricter limit. - if addr.ip().is_loopback() - && request.headers().contains_key("CF-Connecting-IP") - { + if addr.ip().is_loopback() && request.headers().contains_key("CF-Connecting-IP") { addr.set_ip(std::net::Ipv4Addr::UNSPECIFIED.into()); } diff --git a/crates/brk_server/src/state.rs b/crates/brk_server/src/state.rs index dca043e28..35b2f8d12 100644 --- a/crates/brk_server/src/state.rs +++ b/crates/brk_server/src/state.rs @@ -1,4 +1,9 @@ -use std::{future::Future, path::PathBuf, sync::Arc, time::{Duration, Instant}}; +use std::{ + future::Future, + path::PathBuf, + sync::Arc, + time::{Duration, Instant}, +}; use derive_more::Deref; diff --git a/crates/brk_traversable/src/lib.rs b/crates/brk_traversable/src/lib.rs index fa9f16fc3..d735866de 100644 --- a/crates/brk_traversable/src/lib.rs +++ b/crates/brk_traversable/src/lib.rs @@ -1,7 +1,7 @@ use std::{collections::BTreeMap, fmt::Display}; -pub use indexmap::IndexMap; pub use brk_types::{Index, MetricLeaf, MetricLeafWithSchema, TreeNode}; +pub use indexmap::IndexMap; #[cfg(feature = "derive")] pub use brk_traversable_derive::Traversable; diff --git a/crates/brk_types/src/addressbytes.rs b/crates/brk_types/src/addressbytes.rs index 363f363ec..c87672dfd 100644 --- a/crates/brk_types/src/addressbytes.rs +++ b/crates/brk_types/src/addressbytes.rs @@ -1,6 +1,6 @@ use std::str::FromStr; -use bitcoin::{Network, PublicKey, opcodes, script::Builder, ScriptBuf}; +use bitcoin::{Network, PublicKey, ScriptBuf, opcodes, script::Builder}; use brk_error::Error; use super::{ @@ -61,18 +61,10 @@ impl AddressBytes { .push_slice(***b) .push_opcode(opcodes::all::OP_EQUAL) .into_script(), - AddressBytes::P2WPKH(b) => { - Builder::new().push_int(0).push_slice(***b).into_script() - } - AddressBytes::P2WSH(b) => { - Builder::new().push_int(0).push_slice(***b).into_script() - } - AddressBytes::P2TR(b) => { - Builder::new().push_int(1).push_slice(***b).into_script() - } - AddressBytes::P2A(b) => { - Builder::new().push_int(1).push_slice(***b).into_script() - } + AddressBytes::P2WPKH(b) => Builder::new().push_int(0).push_slice(***b).into_script(), + AddressBytes::P2WSH(b) => Builder::new().push_int(0).push_slice(***b).into_script(), + AddressBytes::P2TR(b) => Builder::new().push_int(1).push_slice(***b).into_script(), + AddressBytes::P2A(b) => Builder::new().push_int(1).push_slice(***b).into_script(), } } } @@ -142,10 +134,9 @@ impl TryFrom<(&ScriptBuf, OutputType)> for AddressBytes { let bytes = &script.as_bytes()[2..]; Ok(Self::P2A(P2ABytes::from(bytes))) } - OutputType::P2MS - | OutputType::Unknown - | OutputType::Empty - | OutputType::OpReturn => Err(Error::WrongAddressType), + OutputType::P2MS | OutputType::Unknown | OutputType::Empty | OutputType::OpReturn => { + Err(Error::WrongAddressType) + } } } } diff --git a/crates/brk_types/src/basis_points_16.rs b/crates/brk_types/src/basis_points_16.rs index 819cf8984..66f4b7f92 100644 --- a/crates/brk_types/src/basis_points_16.rs +++ b/crates/brk_types/src/basis_points_16.rs @@ -52,7 +52,10 @@ impl BasisPoints16 { impl From for BasisPoints16 { #[inline] fn from(value: usize) -> Self { - debug_assert!(value <= u16::MAX as usize, "usize out of BasisPoints16 range: {value}"); + debug_assert!( + value <= u16::MAX as usize, + "usize out of BasisPoints16 range: {value}" + ); Self(value as u16) } } @@ -76,7 +79,10 @@ impl From for u16 { impl From for BasisPoints16 { #[inline] fn from(value: f32) -> Self { - debug_assert!(value >= 0.0 && value <= u16::MAX as f32 / 10000.0, "f32 out of BasisPoints16 range: {value}"); + debug_assert!( + value >= 0.0 && value <= u16::MAX as f32 / 10000.0, + "f32 out of BasisPoints16 range: {value}" + ); Self((value * 10000.0).round() as u16) } } @@ -86,7 +92,10 @@ impl From for BasisPoints16 { impl From for BasisPoints16 { #[inline] fn from(value: f64) -> Self { - debug_assert!(value >= 0.0 && value <= u16::MAX as f64 / 10000.0, "f64 out of BasisPoints16 range: {value}"); + debug_assert!( + value >= 0.0 && value <= u16::MAX as f64 / 10000.0, + "f64 out of BasisPoints16 range: {value}" + ); Self((value * 10000.0).round() as u16) } } diff --git a/crates/brk_types/src/basis_points_32.rs b/crates/brk_types/src/basis_points_32.rs index 49036707e..5f2007519 100644 --- a/crates/brk_types/src/basis_points_32.rs +++ b/crates/brk_types/src/basis_points_32.rs @@ -51,7 +51,10 @@ impl BasisPoints32 { impl From for BasisPoints32 { #[inline] fn from(value: usize) -> Self { - debug_assert!(value <= u32::MAX as usize, "usize out of BasisPoints32 range: {value}"); + debug_assert!( + value <= u32::MAX as usize, + "usize out of BasisPoints32 range: {value}" + ); Self(value as u32) } } diff --git a/crates/brk_types/src/basis_points_signed_16.rs b/crates/brk_types/src/basis_points_signed_16.rs index 0b878f853..02008cf0b 100644 --- a/crates/brk_types/src/basis_points_signed_16.rs +++ b/crates/brk_types/src/basis_points_signed_16.rs @@ -56,7 +56,10 @@ impl BasisPointsSigned16 { impl From for BasisPointsSigned16 { #[inline] fn from(value: usize) -> Self { - debug_assert!(value <= i16::MAX as usize, "usize out of BasisPointsSigned16 range: {value}"); + debug_assert!( + value <= i16::MAX as usize, + "usize out of BasisPointsSigned16 range: {value}" + ); Self(value as i16) } } diff --git a/crates/brk_types/src/basis_points_signed_32.rs b/crates/brk_types/src/basis_points_signed_32.rs index 28a78bcd1..d800828ee 100644 --- a/crates/brk_types/src/basis_points_signed_32.rs +++ b/crates/brk_types/src/basis_points_signed_32.rs @@ -56,7 +56,10 @@ impl BasisPointsSigned32 { impl From for BasisPointsSigned32 { #[inline] fn from(value: usize) -> Self { - debug_assert!(value <= i32::MAX as usize, "usize out of BasisPointsSigned32 range: {value}"); + debug_assert!( + value <= i32::MAX as usize, + "usize out of BasisPointsSigned32 range: {value}" + ); Self(value as i32) } } diff --git a/crates/brk_types/src/block.rs b/crates/brk_types/src/block.rs index 1c1082b2a..20b56d3bf 100644 --- a/crates/brk_types/src/block.rs +++ b/crates/brk_types/src/block.rs @@ -64,16 +64,20 @@ impl Block { if let Some(raw) = self.raw_tx_bytes(index) { let total_size = raw.len() as u32; let is_segwit = raw[4] == 0x00; - let base_size = if is_segwit { tx.base_size() as u32 } else { total_size }; + let base_size = if is_segwit { + tx.base_size() as u32 + } else { + total_size + }; let txid = Self::hash_raw_tx(raw, base_size); - debug_assert_eq!( - txid, - tx.compute_txid(), - "raw txid mismatch at tx {index}" - ); + debug_assert_eq!(txid, tx.compute_txid(), "raw txid mismatch at tx {index}"); (txid, base_size, total_size) } else { - (tx.compute_txid(), tx.base_size() as u32, tx.total_size() as u32) + ( + tx.compute_txid(), + tx.base_size() as u32, + tx.total_size() as u32, + ) } } @@ -183,4 +187,3 @@ impl ReadBlock { self.block } } - diff --git a/crates/brk_types/src/cents_sats.rs b/crates/brk_types/src/cents_sats.rs index 2c4676052..dcd9baaba 100644 --- a/crates/brk_types/src/cents_sats.rs +++ b/crates/brk_types/src/cents_sats.rs @@ -4,7 +4,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{Bytes, Formattable}; -use super::{CentsSquaredSats, Cents, Sats}; +use super::{Cents, CentsSquaredSats, Sats}; /// Cents × Sats (u128) - price in cents multiplied by amount in sats. /// Uses u128 because large amounts at any price can overflow u64. diff --git a/crates/brk_types/src/cost_basis_value.rs b/crates/brk_types/src/cost_basis_value.rs index 77b01c3ec..b9fa8522d 100644 --- a/crates/brk_types/src/cost_basis_value.rs +++ b/crates/brk_types/src/cost_basis_value.rs @@ -4,7 +4,9 @@ use strum::Display; /// Value type for cost basis distribution. /// Options: supply (BTC), realized (USD, price × supply), unrealized (USD, spot × supply). -#[derive(Debug, Display, Clone, Copy, Default, PartialEq, Eq, Deserialize, Serialize, JsonSchema)] +#[derive( + Debug, Display, Clone, Copy, Default, PartialEq, Eq, Deserialize, Serialize, JsonSchema, +)] #[serde(rename_all = "lowercase")] #[strum(serialize_all = "lowercase")] pub enum CostBasisValue { diff --git a/crates/brk_types/src/datarange.rs b/crates/brk_types/src/datarange.rs index 0b5ea9609..ba5fc09db 100644 --- a/crates/brk_types/src/datarange.rs +++ b/crates/brk_types/src/datarange.rs @@ -1,23 +1,41 @@ use schemars::JsonSchema; use serde::Deserialize; -use crate::{de_unquote_i64, de_unquote_limit, Limit}; +use crate::{Limit, de_unquote_i64, de_unquote_limit}; /// Range parameters for slicing data #[derive(Default, Debug, Deserialize, JsonSchema)] pub struct DataRange { /// Inclusive starting index, if negative counts from end. Aliases: `from`, `f`, `s` - #[serde(default, alias = "s", alias = "from", alias = "f", deserialize_with = "de_unquote_i64")] + #[serde( + default, + alias = "s", + alias = "from", + alias = "f", + deserialize_with = "de_unquote_i64" + )] #[schemars(example = 0, example = -1, example = -10, example = -1000)] start: Option, /// Exclusive ending index, if negative counts from end. Aliases: `to`, `t`, `e` - #[serde(default, alias = "e", alias = "to", alias = "t", deserialize_with = "de_unquote_i64")] + #[serde( + default, + alias = "e", + alias = "to", + alias = "t", + deserialize_with = "de_unquote_i64" + )] #[schemars(example = 1000)] end: Option, /// Maximum number of values to return (ignored if `end` is set). Aliases: `count`, `c`, `l` - #[serde(default, alias = "l", alias = "count", alias = "c", deserialize_with = "de_unquote_limit")] + #[serde( + default, + alias = "l", + alias = "count", + alias = "c", + deserialize_with = "de_unquote_limit" + )] limit: Option, } diff --git a/crates/brk_types/src/datarangeformat.rs b/crates/brk_types/src/datarangeformat.rs index 403848f6c..ce87cdd24 100644 --- a/crates/brk_types/src/datarangeformat.rs +++ b/crates/brk_types/src/datarangeformat.rs @@ -36,4 +36,3 @@ impl DataRangeFormat { self } } - diff --git a/crates/brk_types/src/date.rs b/crates/brk_types/src/date.rs index dcc63cd5a..725f63900 100644 --- a/crates/brk_types/src/date.rs +++ b/crates/brk_types/src/date.rs @@ -7,7 +7,7 @@ use vecdb::{Formattable, Pco}; use crate::ONE_DAY_IN_SEC_F64; -use super::{Day1, Year10, Month1, Month3, Month6, Timestamp, Week1, Year1}; +use super::{Day1, Month1, Month3, Month6, Timestamp, Week1, Year1, Year10}; /// Date in YYYYMMDD format stored as u32 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Pco, JsonSchema)] diff --git a/crates/brk_types/src/day3.rs b/crates/brk_types/src/day3.rs index 4a3259ccc..78585a5fb 100644 --- a/crates/brk_types/src/day3.rs +++ b/crates/brk_types/src/day3.rs @@ -4,7 +4,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; -use super::{Timestamp, INDEX_EPOCH}; +use super::{INDEX_EPOCH, Timestamp}; pub const DAY3_INTERVAL: u32 = 259200; diff --git a/crates/brk_types/src/etag.rs b/crates/brk_types/src/etag.rs index 6db952d60..af0ae3be2 100644 --- a/crates/brk_types/src/etag.rs +++ b/crates/brk_types/src/etag.rs @@ -47,7 +47,13 @@ impl Etag { /// - Slice reaches the end: `{version:x}-{start}-{total}-{height}` (includes height since last value may be recomputed each block) /// /// `version` is the metric version for single queries, or the sum of versions for bulk queries. - pub fn from_metric(version: super::Version, total: usize, start: usize, end: usize, height: u32) -> Self { + pub fn from_metric( + version: super::Version, + total: usize, + start: usize, + end: usize, + height: u32, + ) -> Self { let v = u32::from(version); if end < total { // Fixed window not at the end - len doesn't matter diff --git a/crates/brk_types/src/fundedaddressdata.rs b/crates/brk_types/src/fundedaddressdata.rs index 690346077..fa980903c 100644 --- a/crates/brk_types/src/fundedaddressdata.rs +++ b/crates/brk_types/src/fundedaddressdata.rs @@ -3,7 +3,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{Bytes, Formattable}; -use crate::{CentsSats, CentsSquaredSats, Cents, EmptyAddressData, Sats, SupplyState}; +use crate::{Cents, CentsSats, CentsSquaredSats, EmptyAddressData, Sats, SupplyState}; /// Snapshot of cost basis related state. /// Uses CentsSats (u64) for single-UTXO values, CentsSquaredSats (u128) for investor cap. @@ -108,12 +108,7 @@ impl FundedAddressData { self.receive_outputs(amount, price, 1); } - pub fn receive_outputs( - &mut self, - amount: Sats, - price: Cents, - output_count: u32, - ) { + pub fn receive_outputs(&mut self, amount: Sats, price: Cents, output_count: u32) { self.received += amount; self.funded_txo_count += output_count; let ps = CentsSats::from_price_sats(price, amount); diff --git a/crates/brk_types/src/hour1.rs b/crates/brk_types/src/hour1.rs index 6d2711bee..c20eab849 100644 --- a/crates/brk_types/src/hour1.rs +++ b/crates/brk_types/src/hour1.rs @@ -4,7 +4,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; -use super::{Timestamp, INDEX_EPOCH}; +use super::{INDEX_EPOCH, Timestamp}; pub const HOUR1_INTERVAL: u32 = 3600; diff --git a/crates/brk_types/src/hour12.rs b/crates/brk_types/src/hour12.rs index 7a86e20bc..8117ade76 100644 --- a/crates/brk_types/src/hour12.rs +++ b/crates/brk_types/src/hour12.rs @@ -4,7 +4,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; -use super::{Timestamp, INDEX_EPOCH}; +use super::{INDEX_EPOCH, Timestamp}; pub const HOUR12_INTERVAL: u32 = 43200; diff --git a/crates/brk_types/src/hour4.rs b/crates/brk_types/src/hour4.rs index 13609e397..17386bc38 100644 --- a/crates/brk_types/src/hour4.rs +++ b/crates/brk_types/src/hour4.rs @@ -4,7 +4,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; -use super::{Timestamp, INDEX_EPOCH}; +use super::{INDEX_EPOCH, Timestamp}; pub const HOUR4_INTERVAL: u32 = 14400; diff --git a/crates/brk_types/src/index.rs b/crates/brk_types/src/index.rs index 802403079..f2162265f 100644 --- a/crates/brk_types/src/index.rs +++ b/crates/brk_types/src/index.rs @@ -8,16 +8,13 @@ use vecdb::PrintableIndex; use crate::PairOutputIndex; use super::{ - Date, Day1, Day3, Year10, DifficultyEpoch, EmptyAddressIndex, EmptyOutputIndex, HalvingEpoch, - Height, Hour1, Hour4, Hour12, FundedAddressIndex, Minute10, Minute30, - Month1, OpReturnIndex, P2AAddressIndex, P2MSOutputIndex, - P2PK33AddressIndex, P2PK65AddressIndex, P2PKHAddressIndex, P2SHAddressIndex, P2TRAddressIndex, - P2WPKHAddressIndex, P2WSHAddressIndex, Month3, Month6, Timestamp, TxInIndex, TxIndex, - TxOutIndex, UnknownOutputIndex, Week1, Year1, - timestamp::INDEX_EPOCH, - minute10::MINUTE10_INTERVAL, - minute30::MINUTE30_INTERVAL, hour1::HOUR1_INTERVAL, hour4::HOUR4_INTERVAL, - hour12::HOUR12_INTERVAL, + Date, Day1, Day3, DifficultyEpoch, EmptyAddressIndex, EmptyOutputIndex, FundedAddressIndex, + HalvingEpoch, Height, Hour1, Hour4, Hour12, Minute10, Minute30, Month1, Month3, Month6, + OpReturnIndex, P2AAddressIndex, P2MSOutputIndex, P2PK33AddressIndex, P2PK65AddressIndex, + P2PKHAddressIndex, P2SHAddressIndex, P2TRAddressIndex, P2WPKHAddressIndex, P2WSHAddressIndex, + Timestamp, TxInIndex, TxIndex, TxOutIndex, UnknownOutputIndex, Week1, Year1, Year10, + hour1::HOUR1_INTERVAL, hour4::HOUR4_INTERVAL, hour12::HOUR12_INTERVAL, + minute10::MINUTE10_INTERVAL, minute30::MINUTE30_INTERVAL, timestamp::INDEX_EPOCH, }; /// Aggregation dimension for querying metrics. Includes time-based (date, week, month, year), @@ -148,7 +145,6 @@ impl Index { .collect::>() } - pub fn name(&self) -> &'static str { match self { Self::Minute10 => ::to_string(), diff --git a/crates/brk_types/src/indexes.rs b/crates/brk_types/src/indexes.rs index 26e1df964..e17223840 100644 --- a/crates/brk_types/src/indexes.rs +++ b/crates/brk_types/src/indexes.rs @@ -1,8 +1,7 @@ use crate::{ - EmptyOutputIndex, Height, - OpReturnIndex, OutputType, P2AAddressIndex, P2MSOutputIndex, P2PK33AddressIndex, - P2PK65AddressIndex, P2PKHAddressIndex, P2SHAddressIndex, P2TRAddressIndex, P2WPKHAddressIndex, - P2WSHAddressIndex, TxInIndex, TxIndex, TxOutIndex, TypeIndex, + EmptyOutputIndex, Height, OpReturnIndex, OutputType, P2AAddressIndex, P2MSOutputIndex, + P2PK33AddressIndex, P2PK65AddressIndex, P2PKHAddressIndex, P2SHAddressIndex, P2TRAddressIndex, + P2WPKHAddressIndex, P2WSHAddressIndex, TxInIndex, TxIndex, TxOutIndex, TypeIndex, UnknownOutputIndex, }; @@ -63,4 +62,3 @@ impl Indexes { } } } - diff --git a/crates/brk_types/src/lib.rs b/crates/brk_types/src/lib.rs index 3230ec02c..bc2a160b9 100644 --- a/crates/brk_types/src/lib.rs +++ b/crates/brk_types/src/lib.rs @@ -52,7 +52,7 @@ mod datarange; mod datarangeformat; mod date; mod day1; -mod year10; +mod day3; mod deser; mod difficultyadjustment; mod difficultyadjustmententry; @@ -78,6 +78,9 @@ mod health; mod height; mod heightparam; mod hex; +mod hour1; +mod hour12; +mod hour4; mod index; mod indexes; mod indexinfo; @@ -96,13 +99,11 @@ mod metricselection; mod metricselectionlegacy; mod metricspaginated; mod metricwithindex; -mod day3; -mod hour1; -mod hour12; -mod hour4; mod minute10; mod minute30; mod month1; +mod month3; +mod month6; mod ohlc; mod opreturnindex; mod option_ext; @@ -140,14 +141,12 @@ mod poolslugparam; mod poolssummary; mod poolstats; mod port; -mod month3; mod rawlocktime; mod recommendedfees; mod rewardstats; mod sats; mod sats_signed; mod satsfract; -mod month6; mod stored_bool; mod stored_f32; mod stored_f64; @@ -192,6 +191,7 @@ mod week1; mod weight; mod year; mod year1; +mod year10; pub use address::*; pub use addressbytes::*; @@ -243,7 +243,7 @@ pub use datarange::*; pub use datarangeformat::*; pub use date::*; pub use day1::*; -pub use year10::*; +pub use day3::*; pub use deser::*; pub use difficultyadjustment::*; pub use difficultyadjustmententry::*; @@ -269,6 +269,9 @@ pub use health::*; pub use height::*; pub use heightparam::*; pub use hex::*; +pub use hour1::*; +pub use hour4::*; +pub use hour12::*; pub use index::*; pub use indexes::*; pub use indexinfo::*; @@ -287,13 +290,11 @@ pub use metricselection::*; pub use metricselectionlegacy::*; pub use metricspaginated::*; pub use metricwithindex::*; -pub use day3::*; -pub use hour1::*; -pub use hour12::*; -pub use hour4::*; pub use minute10::*; pub use minute30::*; pub use month1::*; +pub use month3::*; +pub use month6::*; pub use ohlc::*; pub use opreturnindex::*; pub use option_ext::*; @@ -331,14 +332,12 @@ pub use poolslugparam::*; pub use poolssummary::*; pub use poolstats::*; pub use port::*; -pub use month3::*; pub use rawlocktime::*; pub use recommendedfees::*; pub use rewardstats::*; pub use sats::*; pub use sats_signed::*; pub use satsfract::*; -pub use month6::*; pub use stored_bool::*; pub use stored_f32::*; pub use stored_f64::*; @@ -383,3 +382,4 @@ pub use week1::*; pub use weight::*; pub use year::*; pub use year1::*; +pub use year10::*; diff --git a/crates/brk_types/src/metricdata.rs b/crates/brk_types/src/metricdata.rs index 739224ba7..7e7ce3afc 100644 --- a/crates/brk_types/src/metricdata.rs +++ b/crates/brk_types/src/metricdata.rs @@ -1,7 +1,7 @@ use std::{io::Write, ops::Deref}; use schemars::JsonSchema; -use serde::{de::DeserializeOwned, Deserialize}; +use serde::{Deserialize, de::DeserializeOwned}; use serde_json::Value; use vecdb::AnySerializableVec; @@ -72,9 +72,7 @@ impl MetricData { // Check first index to verify date conversion works (sub-daily returns None) self.index.index_to_date(self.start)?; let index = self.index; - Some(self.indexes().map(move |i| { - index.index_to_date(i).unwrap() - })) + Some(self.indexes().map(move |i| index.index_to_date(i).unwrap())) } /// Returns an iterator over timestamps for the index range. @@ -85,9 +83,10 @@ impl MetricData { return None; } let index = self.index; - Some(self.indexes().map(move |i| { - index.index_to_timestamp(i).unwrap() - })) + Some( + self.indexes() + .map(move |i| index.index_to_timestamp(i).unwrap()), + ) } /// Iterate over (index, &value) pairs. @@ -146,13 +145,17 @@ impl DateMetricData { /// Returns an iterator over timestamps for the index range (infallible). /// Works for all date-based indexes including sub-daily. pub fn timestamps(&self) -> impl Iterator + '_ { - self.0.timestamps().expect("DateMetricData is always date-based") + self.0 + .timestamps() + .expect("DateMetricData is always date-based") } /// Iterate over (timestamp, &value) pairs (infallible). /// Works for all date-based indexes including sub-daily. pub fn iter_timestamps(&self) -> impl Iterator + '_ { - self.0.iter_timestamps().expect("DateMetricData is always date-based") + self.0 + .iter_timestamps() + .expect("DateMetricData is always date-based") } } @@ -170,10 +173,7 @@ impl<'de, T: DeserializeOwned> Deserialize<'de> for DateMetricData { { let inner = MetricData::::deserialize(deserializer)?; Self::try_new(inner).map_err(|m| { - serde::de::Error::custom(format!( - "expected date-based index, got {:?}", - m.index - )) + serde::de::Error::custom(format!("expected date-based index, got {:?}", m.index)) }) } } @@ -517,7 +517,11 @@ mod tests { let result: Result, _> = serde_json::from_str(json); assert!(result.is_err()); let err = result.unwrap_err().to_string(); - assert!(err.contains("date-based"), "error should mention date-based: {}", err); + assert!( + err.contains("date-based"), + "error should mention date-based: {}", + err + ); } // timestamp_to_index tests diff --git a/crates/brk_types/src/minute10.rs b/crates/brk_types/src/minute10.rs index e2c6f16ee..98bba9716 100644 --- a/crates/brk_types/src/minute10.rs +++ b/crates/brk_types/src/minute10.rs @@ -4,7 +4,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; -use super::{Timestamp, INDEX_EPOCH}; +use super::{INDEX_EPOCH, Timestamp}; pub const MINUTE10_INTERVAL: u32 = 600; diff --git a/crates/brk_types/src/minute30.rs b/crates/brk_types/src/minute30.rs index d45faba9d..27a23a470 100644 --- a/crates/brk_types/src/minute30.rs +++ b/crates/brk_types/src/minute30.rs @@ -4,7 +4,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; -use super::{Timestamp, INDEX_EPOCH}; +use super::{INDEX_EPOCH, Timestamp}; pub const MINUTE30_INTERVAL: u32 = 1800; diff --git a/crates/brk_types/src/month3.rs b/crates/brk_types/src/month3.rs index 826ad0059..6f8a6c446 100644 --- a/crates/brk_types/src/month3.rs +++ b/crates/brk_types/src/month3.rs @@ -107,7 +107,15 @@ impl PrintableIndex for Month3 { } fn to_possible_strings() -> &'static [&'static str] { - &["quarter", "q", "quarterly", "month3", "quarterindex", "3m", "3mo"] + &[ + "quarter", + "q", + "quarterly", + "month3", + "quarterindex", + "3m", + "3mo", + ] } } diff --git a/crates/brk_types/src/pool.rs b/crates/brk_types/src/pool.rs index c1f0883e4..4b2bbce77 100644 --- a/crates/brk_types/src/pool.rs +++ b/crates/brk_types/src/pool.rs @@ -40,4 +40,3 @@ impl Pool { self.slug.into() } } - diff --git a/crates/brk_types/src/stored_u64.rs b/crates/brk_types/src/stored_u64.rs index 7523d4420..001392674 100644 --- a/crates/brk_types/src/stored_u64.rs +++ b/crates/brk_types/src/stored_u64.rs @@ -6,10 +6,10 @@ use serde::{Deserialize, Serialize}; use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex}; use super::{ - Day1, EmptyOutputIndex, Height, Month1, OpReturnIndex, P2AAddressIndex, - P2MSOutputIndex, P2PK33AddressIndex, P2PK65AddressIndex, P2PKHAddressIndex, P2SHAddressIndex, - P2TRAddressIndex, P2WPKHAddressIndex, P2WSHAddressIndex, TxInIndex, TxIndex, TxOutIndex, - UnknownOutputIndex, Year1, + Day1, EmptyOutputIndex, Height, Month1, OpReturnIndex, P2AAddressIndex, P2MSOutputIndex, + P2PK33AddressIndex, P2PK65AddressIndex, P2PKHAddressIndex, P2SHAddressIndex, P2TRAddressIndex, + P2WPKHAddressIndex, P2WSHAddressIndex, TxInIndex, TxIndex, TxOutIndex, UnknownOutputIndex, + Year1, }; /// Fixed-size 64-bit unsigned integer optimized for on-disk storage diff --git a/crates/brk_types/src/treenode.rs b/crates/brk_types/src/treenode.rs index 76ad4bf1a..70c8bd009 100644 --- a/crates/brk_types/src/treenode.rs +++ b/crates/brk_types/src/treenode.rs @@ -526,10 +526,7 @@ mod tests { // Two branches lifting children with same key but different metric names → conflict let tree = branch(vec![ ("a", branch(vec![("data", leaf("metric_a", Index::Height))])), - ( - "b", - branch(vec![("data", leaf("metric_b", Index::Day1))]), - ), + ("b", branch(vec![("data", leaf("metric_b", Index::Day1))])), ]); let result = tree.merge_branches(); assert!(result.is_none(), "Should detect conflict"); @@ -543,10 +540,7 @@ mod tests { "a", branch(vec![("sum", leaf("metric_sum", Index::Height))]), ), - ( - "b", - branch(vec![("sum", leaf("metric_sum", Index::Day1))]), - ), + ("b", branch(vec![("sum", leaf("metric_sum", Index::Day1))])), ]); let result = tree.merge_branches(); assert!(result.is_some(), "Should merge successfully"); @@ -1172,10 +1166,7 @@ mod tests { // Both have same metric name → collapses to single Leaf let tree = branch(vec![ // day1 with wrap="base" - ( - "day1", - branch(vec![("base", leaf("metric", Index::Day1))]), - ), + ("day1", branch(vec![("base", leaf("metric", Index::Day1))])), // rest (flatten): DerivedDateLast merged to Leaf // Same metric name as base ("rest", leaf("metric", Index::Week1)), diff --git a/crates/brk_website/examples/website.rs b/crates/brk_website/examples/website.rs index d1fd067f4..82a6da4ef 100644 --- a/crates/brk_website/examples/website.rs +++ b/crates/brk_website/examples/website.rs @@ -9,13 +9,9 @@ use axum::{ use brk_website::{Website, router}; use tokio::net::TcpListener; use tower_http::{ - catch_panic::CatchPanicLayer, - classify::ServerErrorsFailureClass, - compression::CompressionLayer, - cors::CorsLayer, - normalize_path::NormalizePathLayer, - timeout::TimeoutLayer, - trace::TraceLayer, + catch_panic::CatchPanicLayer, classify::ServerErrorsFailureClass, + compression::CompressionLayer, cors::CorsLayer, normalize_path::NormalizePathLayer, + timeout::TimeoutLayer, trace::TraceLayer, }; use tower_layer::Layer; use tracing::{error, info}; @@ -35,10 +31,7 @@ async fn main() -> std::io::Result<()> { website.log(); - let compression_layer = CompressionLayer::new() - .br(true) - .gzip(true) - .zstd(true); + let compression_layer = CompressionLayer::new().br(true).gzip(true).zstd(true); let response_uri_layer = axum::middleware::from_fn( async |request: Request, next: Next| -> Response { diff --git a/crates/brk_website/src/headers.rs b/crates/brk_website/src/headers.rs index 219c65325..8949a6688 100644 --- a/crates/brk_website/src/headers.rs +++ b/crates/brk_website/src/headers.rs @@ -13,8 +13,7 @@ pub trait HeaderMapExtended { impl HeaderMapExtended for HeaderMap { fn has_etag(&self, etag: &str) -> bool { - self.get(header::IF_NONE_MATCH) - .is_some_and(|v| v == etag) + self.get(header::IF_NONE_MATCH).is_some_and(|v| v == etag) } fn insert_etag(&mut self, etag: &str) { diff --git a/crates/brk_website/src/router.rs b/crates/brk_website/src/router.rs index dd722473b..825afc25c 100644 --- a/crates/brk_website/src/router.rs +++ b/crates/brk_website/src/router.rs @@ -1,6 +1,9 @@ use axum::{Router, routing::get}; -use crate::{Website, handlers::{file_handler, index_handler}}; +use crate::{ + Website, + handlers::{file_handler, index_handler}, +}; /// Create a router for serving the website. /// diff --git a/crates/brk_website/src/website.rs b/crates/brk_website/src/website.rs index 21c0893b2..cc9743972 100644 --- a/crates/brk_website/src/website.rs +++ b/crates/brk_website/src/website.rs @@ -117,8 +117,8 @@ impl Website { .get_file("index.html") .expect("index.html must exist in embedded website"); - let html = - std::str::from_utf8(file.contents()).expect("index.html must be valid UTF-8"); + let html = std::str::from_utf8(file.contents()) + .expect("index.html must be valid UTF-8"); let importmap = ImportMap::scan_embedded(&EMBEDDED_WEBSITE, ""); importmap @@ -225,7 +225,10 @@ impl FromStr for Website { } impl Serialize for Website { - fn serialize(&self, serializer: S) -> std::result::Result { + fn serialize( + &self, + serializer: S, + ) -> std::result::Result { match self { Self::Disabled => serializer.serialize_bool(false), Self::Default => serializer.serialize_bool(true), @@ -235,7 +238,9 @@ impl Serialize for Website { } impl<'de> Deserialize<'de> for Website { - fn deserialize>(deserializer: D) -> std::result::Result { + fn deserialize>( + deserializer: D, + ) -> std::result::Result { use serde::de::{self, Visitor}; struct WebsiteVisitor;