global: snap

This commit is contained in:
nym21
2026-04-17 21:23:11 +02:00
parent 008143ff00
commit 2a93f51e81
47 changed files with 2075 additions and 389 deletions
+5 -2
View File
@@ -3,7 +3,10 @@
//! This module detects repeating tree structures and analyzes them
//! using the bottom-up name deconstruction algorithm.
use std::collections::{BTreeMap, BTreeSet};
use std::{
cmp::Reverse,
collections::{BTreeMap, BTreeSet},
};
use brk_types::{TreeNode, extract_json_type};
@@ -111,7 +114,7 @@ pub fn detect_structural_patterns(
// Also collects node bases for each tree path
let node_bases = analyze_pattern_modes(tree, &mut patterns, &pattern_lookup);
patterns.sort_by(|a, b| b.fields.len().cmp(&a.fields.len()));
patterns.sort_by_key(|p| Reverse(p.fields.len()));
(patterns, concrete_to_pattern, type_mappings, node_bases)
}
+1 -1
View File
@@ -31,7 +31,7 @@ impl ClientConstants {
let pools = pools();
let mut sorted_pools: Vec<_> = pools.iter().collect();
sorted_pools.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase()));
sorted_pools.sort_by_key(|p| p.name.to_lowercase());
let pool_map: BTreeMap<PoolSlug, &'static str> =
sorted_pools.iter().map(|p| (p.slug(), p.name)).collect();
+121 -38
View File
@@ -1310,7 +1310,7 @@ impl IndexPct0Pct1Pct2Pct5Pct95Pct98Pct99ScorePattern {
}
/// Pattern struct for repeated tree structure.
pub struct AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5 {
pub struct AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6 {
pub all: AverageBlockCumulativeSumPattern<StoredU64>,
pub p2a: AverageBlockCumulativeSumPattern<StoredU64>,
pub p2pk33: AverageBlockCumulativeSumPattern<StoredU64>,
@@ -1322,7 +1322,7 @@ pub struct AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5 {
pub p2wsh: AverageBlockCumulativeSumPattern<StoredU64>,
}
impl AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5 {
impl AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6 {
/// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
@@ -1340,7 +1340,7 @@ impl AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5 {
}
/// Pattern struct for repeated tree structure.
pub struct AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3 {
pub struct AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4 {
pub all: SeriesPattern1<StoredU64>,
pub p2a: SeriesPattern1<StoredU64>,
pub p2pk33: SeriesPattern1<StoredU64>,
@@ -1352,7 +1352,7 @@ pub struct AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3 {
pub p2wsh: SeriesPattern1<StoredU64>,
}
impl AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3 {
impl AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4 {
/// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
@@ -1370,7 +1370,7 @@ impl AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3 {
}
/// Pattern struct for repeated tree structure.
pub struct AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6 {
pub struct AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7 {
pub all: _1m1w1y24hBpsPercentRatioPattern,
pub p2a: _1m1w1y24hBpsPercentRatioPattern,
pub p2pk33: _1m1w1y24hBpsPercentRatioPattern,
@@ -1382,7 +1382,7 @@ pub struct AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6 {
pub p2wsh: _1m1w1y24hBpsPercentRatioPattern,
}
impl AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6 {
impl AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7 {
/// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
@@ -1434,7 +1434,7 @@ pub struct CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2 {
pub capitalized_cap_in_loss_raw: SeriesPattern18<CentsSquaredSats>,
pub capitalized_cap_in_profit_raw: SeriesPattern18<CentsSquaredSats>,
pub gross_pnl: CentsUsdPattern3,
pub invested_capital: InPattern,
pub invested_capital: InPattern2,
pub loss: CentsNegativeToUsdPattern2,
pub net_pnl: CentsToUsdPattern3,
pub nupl: BpsRatioPattern,
@@ -1449,7 +1449,7 @@ impl CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2 {
capitalized_cap_in_loss_raw: SeriesPattern18::new(client.clone(), _m(&acc, "capitalized_cap_in_loss_raw")),
capitalized_cap_in_profit_raw: SeriesPattern18::new(client.clone(), _m(&acc, "capitalized_cap_in_profit_raw")),
gross_pnl: CentsUsdPattern3::new(client.clone(), _m(&acc, "unrealized_gross_pnl")),
invested_capital: InPattern::new(client.clone(), _m(&acc, "invested_capital_in")),
invested_capital: InPattern2::new(client.clone(), _m(&acc, "invested_capital_in")),
loss: CentsNegativeToUsdPattern2::new(client.clone(), _m(&acc, "unrealized_loss")),
net_pnl: CentsToUsdPattern3::new(client.clone(), _m(&acc, "net_unrealized_pnl")),
nupl: BpsRatioPattern::new(client.clone(), _m(&acc, "nupl")),
@@ -1960,7 +1960,7 @@ impl ActivityOutputsRealizedSupplyUnrealizedPattern2 {
/// Pattern struct for repeated tree structure.
pub struct BlockChangeCumulativeDeltaSumPattern {
pub block: CentsUsdPattern4,
pub change_1m: ToPattern,
pub change_1m: ToPattern2,
pub cumulative: CentsUsdPattern,
pub delta: AbsoluteRatePattern2,
pub sum: _1m1w1y24hPattern5,
@@ -1971,7 +1971,7 @@ impl BlockChangeCumulativeDeltaSumPattern {
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
block: CentsUsdPattern4::new(client.clone(), _m(&acc, "realized_pnl")),
change_1m: ToPattern::new(client.clone(), _m(&acc, "pnl_change_1m_to")),
change_1m: ToPattern2::new(client.clone(), _m(&acc, "pnl_change_1m_to")),
cumulative: CentsUsdPattern::new(client.clone(), _m(&acc, "realized_pnl_cumulative")),
delta: AbsoluteRatePattern2::new(client.clone(), _m(&acc, "realized_pnl_delta")),
sum: _1m1w1y24hPattern5::new(client.clone(), _m(&acc, "realized_pnl_sum")),
@@ -2966,6 +2966,22 @@ impl AbsoluteRatePattern2 {
}
}
/// Pattern struct for repeated tree structure.
pub struct AddrUtxoPattern {
pub addr: BtcCentsSatsUsdPattern,
pub utxo: BtcCentsSatsUsdPattern,
}
impl AddrUtxoPattern {
/// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
addr: BtcCentsSatsUsdPattern::new(client.clone(), _m(&acc, "addr_amount")),
utxo: BtcCentsSatsUsdPattern::new(client.clone(), _m(&acc, "utxo_amount")),
}
}
}
/// Pattern struct for repeated tree structure.
pub struct AllSthPattern2 {
pub all: BtcCentsDeltaSatsUsdPattern,
@@ -3192,32 +3208,48 @@ impl DeltaTotalPattern {
/// Pattern struct for repeated tree structure.
pub struct FundedTotalPattern {
pub funded: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3,
pub total: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3,
pub funded: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4,
pub total: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4,
}
impl FundedTotalPattern {
/// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
funded: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3::new(client.clone(), acc.clone()),
total: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3::new(client.clone(), _p("total", &acc)),
funded: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4::new(client.clone(), acc.clone()),
total: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4::new(client.clone(), _p("total", &acc)),
}
}
}
/// Pattern struct for repeated tree structure.
pub struct InPattern2 {
pub in_loss: CentsUsdPattern3,
pub in_profit: CentsUsdPattern3,
}
impl InPattern2 {
/// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
in_loss: CentsUsdPattern3::new(client.clone(), _m(&acc, "loss")),
in_profit: CentsUsdPattern3::new(client.clone(), _m(&acc, "profit")),
}
}
}
/// Pattern struct for repeated tree structure.
pub struct InPattern {
pub in_loss: CentsUsdPattern3,
pub in_profit: CentsUsdPattern3,
pub in_loss: ToPattern,
pub in_profit: ToPattern,
}
impl InPattern {
/// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
in_loss: CentsUsdPattern3::new(client.clone(), _m(&acc, "loss")),
in_profit: CentsUsdPattern3::new(client.clone(), _m(&acc, "profit")),
in_loss: ToPattern::new(client.clone(), _m(&acc, "loss_to_own")),
in_profit: ToPattern::new(client.clone(), _m(&acc, "profit_to_own")),
}
}
}
@@ -3277,12 +3309,12 @@ pub struct SdSmaPattern {
}
/// Pattern struct for repeated tree structure.
pub struct ToPattern {
pub struct ToPattern2 {
pub to_mcap: BpsPercentRatioPattern,
pub to_rcap: BpsPercentRatioPattern,
}
impl ToPattern {
impl ToPattern2 {
/// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
@@ -3334,6 +3366,20 @@ impl PricePattern {
}
}
/// Pattern struct for repeated tree structure.
pub struct ToPattern {
pub to_own: BpsPercentRatioPattern2,
}
impl ToPattern {
/// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
to_own: BpsPercentRatioPattern2::new(client.clone(), acc.clone()),
}
}
}
/// Pattern struct for repeated tree structure.
pub struct TransferPattern {
pub transfer_volume: AverageBlockCumulativeSumPattern3,
@@ -4197,14 +4243,15 @@ pub struct SeriesTree_Addrs {
pub raw: SeriesTree_Addrs_Raw,
pub indexes: SeriesTree_Addrs_Indexes,
pub data: SeriesTree_Addrs_Data,
pub funded: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3,
pub empty: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3,
pub funded: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4,
pub empty: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4,
pub activity: SeriesTree_Addrs_Activity,
pub total: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3,
pub new: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5,
pub total: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4,
pub new: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6,
pub reused: SeriesTree_Addrs_Reused,
pub exposed: SeriesTree_Addrs_Exposed,
pub delta: SeriesTree_Addrs_Delta,
pub avg_amount: SeriesTree_Addrs_AvgAmount,
}
impl SeriesTree_Addrs {
@@ -4213,14 +4260,15 @@ impl SeriesTree_Addrs {
raw: SeriesTree_Addrs_Raw::new(client.clone(), format!("{base_path}_raw")),
indexes: SeriesTree_Addrs_Indexes::new(client.clone(), format!("{base_path}_indexes")),
data: SeriesTree_Addrs_Data::new(client.clone(), format!("{base_path}_data")),
funded: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3::new(client.clone(), "addr_count".to_string()),
empty: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3::new(client.clone(), "empty_addr_count".to_string()),
funded: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4::new(client.clone(), "addr_count".to_string()),
empty: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4::new(client.clone(), "empty_addr_count".to_string()),
activity: SeriesTree_Addrs_Activity::new(client.clone(), format!("{base_path}_activity")),
total: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3::new(client.clone(), "total_addr_count".to_string()),
new: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5::new(client.clone(), "new_addr_count".to_string()),
total: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4::new(client.clone(), "total_addr_count".to_string()),
new: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6::new(client.clone(), "new_addr_count".to_string()),
reused: SeriesTree_Addrs_Reused::new(client.clone(), format!("{base_path}_reused")),
exposed: SeriesTree_Addrs_Exposed::new(client.clone(), format!("{base_path}_exposed")),
delta: SeriesTree_Addrs_Delta::new(client.clone(), format!("{base_path}_delta")),
avg_amount: SeriesTree_Addrs_AvgAmount::new(client.clone(), format!("{base_path}_avg_amount")),
}
}
}
@@ -4485,11 +4533,11 @@ impl SeriesTree_Addrs_Reused {
/// Series tree node.
pub struct SeriesTree_Addrs_Reused_Events {
pub output_to_reused_addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5,
pub output_to_reused_addr_share: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6,
pub output_to_reused_addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6,
pub output_to_reused_addr_share: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7,
pub spendable_output_to_reused_addr_share: _1m1w1y24hBpsPercentRatioPattern,
pub input_from_reused_addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5,
pub input_from_reused_addr_share: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6,
pub input_from_reused_addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6,
pub input_from_reused_addr_share: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7,
pub active_reused_addr_count: _1m1w1y24hBlockPattern,
pub active_reused_addr_share: SeriesTree_Addrs_Reused_Events_ActiveReusedAddrShare,
}
@@ -4497,11 +4545,11 @@ pub struct SeriesTree_Addrs_Reused_Events {
impl SeriesTree_Addrs_Reused_Events {
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
Self {
output_to_reused_addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5::new(client.clone(), "output_to_reused_addr_count".to_string()),
output_to_reused_addr_share: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6::new(client.clone(), "output_to_reused_addr_share".to_string()),
output_to_reused_addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6::new(client.clone(), "output_to_reused_addr_count".to_string()),
output_to_reused_addr_share: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7::new(client.clone(), "output_to_reused_addr_share".to_string()),
spendable_output_to_reused_addr_share: _1m1w1y24hBpsPercentRatioPattern::new(client.clone(), "spendable_output_to_reused_addr_share".to_string()),
input_from_reused_addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5::new(client.clone(), "input_from_reused_addr_count".to_string()),
input_from_reused_addr_share: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6::new(client.clone(), "input_from_reused_addr_share".to_string()),
input_from_reused_addr_count: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6::new(client.clone(), "input_from_reused_addr_count".to_string()),
input_from_reused_addr_share: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7::new(client.clone(), "input_from_reused_addr_share".to_string()),
active_reused_addr_count: _1m1w1y24hBlockPattern::new(client.clone(), "active_reused_addr_count".to_string()),
active_reused_addr_share: SeriesTree_Addrs_Reused_Events_ActiveReusedAddrShare::new(client.clone(), format!("{base_path}_active_reused_addr_share")),
}
@@ -4633,6 +4681,35 @@ impl SeriesTree_Addrs_Delta {
}
}
/// Series tree node.
pub struct SeriesTree_Addrs_AvgAmount {
pub all: AddrUtxoPattern,
pub p2pk65: AddrUtxoPattern,
pub p2pk33: AddrUtxoPattern,
pub p2pkh: AddrUtxoPattern,
pub p2sh: AddrUtxoPattern,
pub p2wpkh: AddrUtxoPattern,
pub p2wsh: AddrUtxoPattern,
pub p2tr: AddrUtxoPattern,
pub p2a: AddrUtxoPattern,
}
impl SeriesTree_Addrs_AvgAmount {
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
Self {
all: AddrUtxoPattern::new(client.clone(), "avg".to_string()),
p2pk65: AddrUtxoPattern::new(client.clone(), "p2pk65_avg".to_string()),
p2pk33: AddrUtxoPattern::new(client.clone(), "p2pk33_avg".to_string()),
p2pkh: AddrUtxoPattern::new(client.clone(), "p2pkh_avg".to_string()),
p2sh: AddrUtxoPattern::new(client.clone(), "p2sh_avg".to_string()),
p2wpkh: AddrUtxoPattern::new(client.clone(), "p2wpkh_avg".to_string()),
p2wsh: AddrUtxoPattern::new(client.clone(), "p2wsh_avg".to_string()),
p2tr: AddrUtxoPattern::new(client.clone(), "p2tr_avg".to_string()),
p2a: AddrUtxoPattern::new(client.clone(), "p2a_avg".to_string()),
}
}
}
/// Series tree node.
pub struct SeriesTree_Scripts {
pub raw: SeriesTree_Scripts_Raw,
@@ -6975,6 +7052,7 @@ pub struct SeriesTree_Cohorts_Utxo_All {
pub realized: SeriesTree_Cohorts_Utxo_All_Realized,
pub cost_basis: SeriesTree_Cohorts_Utxo_All_CostBasis,
pub unrealized: SeriesTree_Cohorts_Utxo_All_Unrealized,
pub invested_capital: InPattern,
}
impl SeriesTree_Cohorts_Utxo_All {
@@ -6986,6 +7064,7 @@ impl SeriesTree_Cohorts_Utxo_All {
realized: SeriesTree_Cohorts_Utxo_All_Realized::new(client.clone(), format!("{base_path}_realized")),
cost_basis: SeriesTree_Cohorts_Utxo_All_CostBasis::new(client.clone(), format!("{base_path}_cost_basis")),
unrealized: SeriesTree_Cohorts_Utxo_All_Unrealized::new(client.clone(), format!("{base_path}_unrealized")),
invested_capital: InPattern::new(client.clone(), "invested_capital_in".to_string()),
}
}
}
@@ -7358,7 +7437,7 @@ pub struct SeriesTree_Cohorts_Utxo_All_Unrealized {
pub loss: SeriesTree_Cohorts_Utxo_All_Unrealized_Loss,
pub net_pnl: SeriesTree_Cohorts_Utxo_All_Unrealized_NetPnl,
pub gross_pnl: CentsUsdPattern3,
pub invested_capital: InPattern,
pub invested_capital: InPattern2,
pub capitalized_cap_in_profit_raw: SeriesPattern18<CentsSquaredSats>,
pub capitalized_cap_in_loss_raw: SeriesPattern18<CentsSquaredSats>,
pub sentiment: SeriesTree_Cohorts_Utxo_All_Unrealized_Sentiment,
@@ -7372,7 +7451,7 @@ impl SeriesTree_Cohorts_Utxo_All_Unrealized {
loss: SeriesTree_Cohorts_Utxo_All_Unrealized_Loss::new(client.clone(), format!("{base_path}_loss")),
net_pnl: SeriesTree_Cohorts_Utxo_All_Unrealized_NetPnl::new(client.clone(), format!("{base_path}_net_pnl")),
gross_pnl: CentsUsdPattern3::new(client.clone(), "unrealized_gross_pnl".to_string()),
invested_capital: InPattern::new(client.clone(), "invested_capital_in".to_string()),
invested_capital: InPattern2::new(client.clone(), "invested_capital_in".to_string()),
capitalized_cap_in_profit_raw: SeriesPattern18::new(client.clone(), "capitalized_cap_in_profit_raw".to_string()),
capitalized_cap_in_loss_raw: SeriesPattern18::new(client.clone(), "capitalized_cap_in_loss_raw".to_string()),
sentiment: SeriesTree_Cohorts_Utxo_All_Unrealized_Sentiment::new(client.clone(), format!("{base_path}_sentiment")),
@@ -7462,6 +7541,7 @@ pub struct SeriesTree_Cohorts_Utxo_Sth {
pub realized: SeriesTree_Cohorts_Utxo_Sth_Realized,
pub cost_basis: InMaxMinPerSupplyPattern,
pub unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2,
pub invested_capital: InPattern,
}
impl SeriesTree_Cohorts_Utxo_Sth {
@@ -7473,6 +7553,7 @@ impl SeriesTree_Cohorts_Utxo_Sth {
realized: SeriesTree_Cohorts_Utxo_Sth_Realized::new(client.clone(), format!("{base_path}_realized")),
cost_basis: InMaxMinPerSupplyPattern::new(client.clone(), "sth".to_string()),
unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2::new(client.clone(), "sth".to_string()),
invested_capital: InPattern::new(client.clone(), "sth_invested_capital_in".to_string()),
}
}
}
@@ -7730,6 +7811,7 @@ pub struct SeriesTree_Cohorts_Utxo_Lth {
pub realized: SeriesTree_Cohorts_Utxo_Lth_Realized,
pub cost_basis: InMaxMinPerSupplyPattern,
pub unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2,
pub invested_capital: InPattern,
}
impl SeriesTree_Cohorts_Utxo_Lth {
@@ -7741,6 +7823,7 @@ impl SeriesTree_Cohorts_Utxo_Lth {
realized: SeriesTree_Cohorts_Utxo_Lth_Realized::new(client.clone(), format!("{base_path}_realized")),
cost_basis: InMaxMinPerSupplyPattern::new(client.clone(), "lth".to_string()),
unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2::new(client.clone(), "lth".to_string()),
invested_capital: InPattern::new(client.clone(), "lth_invested_capital_in".to_string()),
}
}
}
@@ -67,14 +67,14 @@ pub(crate) fn process_funded_addrs(
// Pure pushes - no holes remain
addrs_data.funded.reserve_pushed(pushes_iter.len());
let mut next_index = addrs_data.funded.len();
for (addr_type, type_index, data) in pushes_iter {
for (next_index, (addr_type, type_index, data)) in
(addrs_data.funded.len()..).zip(pushes_iter)
{
addrs_data.funded.push(data);
result.get_mut(addr_type).unwrap().insert(
type_index,
AnyAddrIndex::from(FundedAddrIndex::from(next_index)),
);
next_index += 1;
}
Ok(result)
@@ -138,14 +138,14 @@ pub(crate) fn process_empty_addrs(
// Pure pushes - no holes remain
addrs_data.empty.reserve_pushed(pushes_iter.len());
let mut next_index = addrs_data.empty.len();
for (addr_type, type_index, data) in pushes_iter {
for (next_index, (addr_type, type_index, data)) in
(addrs_data.empty.len()..).zip(pushes_iter)
{
addrs_data.empty.push(data);
result.get_mut(addr_type).unwrap().insert(
type_index,
AnyAddrIndex::from(EmptyAddrIndex::from(next_index)),
);
next_index += 1;
}
Ok(result)
@@ -542,17 +542,14 @@ impl UTXOCohorts<Rw> {
}
/// Second phase of post-processing: compute relative metrics.
pub(crate) fn compute_rest_part2<HM>(
pub(crate) fn compute_rest_part2(
&mut self,
blocks: &blocks::Vecs,
prices: &prices::Vecs,
starting_indexes: &Indexes,
height_to_market_cap: &HM,
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()>
where
HM: ReadableVec<Height, Dollars> + Sync,
{
) -> Result<()> {
// Get under_1h value sources for adjusted computation (cloned to avoid borrow conflicts).
let under_1h_value_created = self
.age_range
@@ -258,6 +258,7 @@ pub(crate) fn process_blocks(
.chain(vecs.addrs.activity.par_iter_height_mut())
.chain(vecs.addrs.reused.par_iter_height_mut())
.chain(vecs.addrs.exposed.par_iter_height_mut())
.chain(vecs.addrs.avg_amount.par_iter_height_mut())
.chain(rayon::iter::once(
&mut vecs.coinblocks_destroyed.block as &mut dyn AnyStoredVec,
))
@@ -156,6 +156,7 @@ impl AllCohortMetrics {
starting_indexes.height,
&self.supply,
&self.unrealized,
&self.realized,
height_to_market_cap,
exit,
)?;
@@ -132,6 +132,7 @@ impl ExtendedCohortMetrics {
starting_indexes.height,
&self.supply,
&self.unrealized,
&self.realized,
height_to_market_cap,
all_supply_sats,
&self.supply.total.usd.height,
@@ -133,7 +133,7 @@ pub use realized::{
AdjustedSopr, RealizedCore, RealizedFull, RealizedFullAccum, RealizedLike, RealizedMinimal,
};
pub use relative::{RelativeForAll, RelativeToAll, RelativeWithExtended};
pub use supply::{SupplyBase, SupplyCore};
pub use supply::{AvgAmountMetrics, SupplyBase, SupplyCore};
pub use unrealized::{
UnrealizedBasic, UnrealizedCore, UnrealizedFull, UnrealizedLike, UnrealizedMinimal,
};
@@ -118,11 +118,11 @@ impl RealizedMinimal {
|(i, cap_cents, supply, ..)| {
let cap = cap_cents.as_u128();
let supply_sats = Sats::from(supply).as_u128();
if supply_sats == 0 {
(i, Cents::ZERO)
} else {
(i, Cents::from(cap * Sats::ONE_BTC_U128 / supply_sats))
}
let cents = (cap * Sats::ONE_BTC_U128)
.checked_div(supply_sats)
.map(Cents::from)
.unwrap_or(Cents::ZERO);
(i, cents)
},
exit,
)?)
@@ -4,9 +4,9 @@ use brk_types::{Dollars, Height};
use derive_more::{Deref, DerefMut};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::distribution::metrics::{ImportConfig, SupplyCore, UnrealizedFull};
use crate::distribution::metrics::{ImportConfig, RealizedFull, SupplyCore, UnrealizedFull};
use super::{RelativeExtendedOwnPnl, RelativeFull};
use super::{RelativeExtendedOwnPnl, RelativeFull, RelativeInvestedCapital};
/// Relative metrics for the "all" cohort (base + own_pnl, NO rel_to_all).
#[derive(Deref, DerefMut, Traversable)]
@@ -17,6 +17,8 @@ pub struct RelativeForAll<M: StorageMode = Rw> {
pub base: RelativeFull<M>,
#[traversable(flatten)]
pub extended_own_pnl: RelativeExtendedOwnPnl<M>,
#[traversable(flatten)]
pub invested_capital: RelativeInvestedCapital<M>,
}
impl RelativeForAll {
@@ -24,6 +26,7 @@ impl RelativeForAll {
Ok(Self {
base: RelativeFull::forced_import(cfg)?,
extended_own_pnl: RelativeExtendedOwnPnl::forced_import(cfg)?,
invested_capital: RelativeInvestedCapital::forced_import(cfg)?,
})
}
@@ -32,6 +35,7 @@ impl RelativeForAll {
max_from: Height,
supply: &SupplyCore,
unrealized: &UnrealizedFull,
realized: &RealizedFull,
market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
@@ -43,6 +47,8 @@ impl RelativeForAll {
&unrealized.gross_pnl.usd.height,
exit,
)?;
self.invested_capital
.compute(max_from, unrealized, realized, exit)?;
Ok(())
}
}
@@ -0,0 +1,53 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{BasisPoints16, Cents, Height, Version};
use vecdb::{Exit, Rw, StorageMode};
use crate::internal::{PercentPerBlock, RatioCentsBp16};
use crate::distribution::metrics::{ImportConfig, RealizedFull, UnrealizedFull};
/// Shares of invested capital in profit / in loss relative to own realized cap.
/// Present for cohorts with `UnrealizedFull` (all, sth, lth).
#[derive(Traversable)]
pub struct RelativeInvestedCapital<M: StorageMode = Rw> {
#[traversable(wrap = "invested_capital/in_profit", rename = "to_own")]
pub in_profit_to_own: PercentPerBlock<BasisPoints16, M>,
#[traversable(wrap = "invested_capital/in_loss", rename = "to_own")]
pub in_loss_to_own: PercentPerBlock<BasisPoints16, M>,
}
impl RelativeInvestedCapital {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let v0 = Version::ZERO;
Ok(Self {
in_profit_to_own: cfg.import("invested_capital_in_profit_to_own", v0)?,
in_loss_to_own: cfg.import("invested_capital_in_loss_to_own", v0)?,
})
}
pub(crate) fn compute(
&mut self,
max_from: Height,
unrealized: &UnrealizedFull,
realized: &RealizedFull,
exit: &Exit,
) -> Result<()> {
let realized_cap = &realized.core.minimal.cap.cents.height;
self.in_profit_to_own
.compute_binary::<Cents, Cents, RatioCentsBp16>(
max_from,
&unrealized.invested_capital.in_profit.cents.height,
realized_cap,
exit,
)?;
self.in_loss_to_own
.compute_binary::<Cents, Cents, RatioCentsBp16>(
max_from,
&unrealized.invested_capital.in_loss.cents.height,
realized_cap,
exit,
)?;
Ok(())
}
}
@@ -2,6 +2,7 @@ mod extended_own_market_cap;
mod extended_own_pnl;
mod for_all;
mod full;
mod invested_capital;
mod to_all;
mod with_extended;
@@ -9,5 +10,6 @@ pub use extended_own_market_cap::RelativeExtendedOwnMarketCap;
pub use extended_own_pnl::RelativeExtendedOwnPnl;
pub use for_all::RelativeForAll;
pub use full::RelativeFull;
pub use invested_capital::RelativeInvestedCapital;
pub use to_all::RelativeToAll;
pub use with_extended::RelativeWithExtended;
@@ -4,9 +4,12 @@ use brk_types::{Dollars, Height, Sats};
use derive_more::{Deref, DerefMut};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::distribution::metrics::{ImportConfig, SupplyCore, UnrealizedFull};
use crate::distribution::metrics::{ImportConfig, RealizedFull, SupplyCore, UnrealizedFull};
use super::{RelativeExtendedOwnMarketCap, RelativeExtendedOwnPnl, RelativeFull, RelativeToAll};
use super::{
RelativeExtendedOwnMarketCap, RelativeExtendedOwnPnl, RelativeFull, RelativeInvestedCapital,
RelativeToAll,
};
/// Full extended relative metrics (base + rel_to_all + own_market_cap + own_pnl).
/// Used by: sth, lth cohorts.
@@ -22,6 +25,8 @@ pub struct RelativeWithExtended<M: StorageMode = Rw> {
pub extended_own_market_cap: RelativeExtendedOwnMarketCap<M>,
#[traversable(flatten)]
pub extended_own_pnl: RelativeExtendedOwnPnl<M>,
#[traversable(flatten)]
pub invested_capital: RelativeInvestedCapital<M>,
}
impl RelativeWithExtended {
@@ -31,6 +36,7 @@ impl RelativeWithExtended {
rel_to_all: RelativeToAll::forced_import(cfg)?,
extended_own_market_cap: RelativeExtendedOwnMarketCap::forced_import(cfg)?,
extended_own_pnl: RelativeExtendedOwnPnl::forced_import(cfg)?,
invested_capital: RelativeInvestedCapital::forced_import(cfg)?,
})
}
@@ -40,6 +46,7 @@ impl RelativeWithExtended {
max_from: Height,
supply: &SupplyCore,
unrealized: &UnrealizedFull,
realized: &RealizedFull,
market_cap: &impl ReadableVec<Height, Dollars>,
all_supply_sats: &impl ReadableVec<Height, Sats>,
own_market_cap: &impl ReadableVec<Height, Dollars>,
@@ -57,6 +64,8 @@ impl RelativeWithExtended {
&unrealized.gross_pnl.usd.height,
exit,
)?;
self.invested_capital
.compute(max_from, unrealized, realized, exit)?;
Ok(())
}
}
@@ -0,0 +1,77 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Sats, StoredU64, Version};
use vecdb::{AnyStoredVec, Database, Exit, ReadableVec, Rw, StorageMode, WritableVec};
use crate::{indexes, internal::AmountPerBlock, prices};
/// Average amount held per UTXO and per funded address.
///
/// `utxo = supply / utxo_count`, `addr = supply / funded_addr_count`.
#[derive(Traversable)]
pub struct AvgAmountMetrics<M: StorageMode = Rw> {
pub utxo: AmountPerBlock<M>,
pub addr: AmountPerBlock<M>,
}
impl AvgAmountMetrics {
pub(crate) fn forced_import(
db: &Database,
prefix: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let name = |suffix: &str| {
if prefix.is_empty() {
suffix.to_string()
} else {
format!("{prefix}_{suffix}")
}
};
Ok(Self {
utxo: AmountPerBlock::forced_import(db, &name("avg_utxo_amount"), version, indexes)?,
addr: AmountPerBlock::forced_import(db, &name("avg_addr_amount"), version, indexes)?,
})
}
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
vec![
&mut self.utxo.sats.height as &mut dyn AnyStoredVec,
&mut self.utxo.cents.height,
&mut self.addr.sats.height,
&mut self.addr.cents.height,
]
}
pub(crate) fn reset_height(&mut self) -> Result<()> {
self.utxo.sats.height.reset()?;
self.utxo.cents.height.reset()?;
self.addr.sats.height.reset()?;
self.addr.cents.height.reset()?;
Ok(())
}
pub(crate) fn compute(
&mut self,
prices: &prices::Vecs,
supply_sats: &impl ReadableVec<Height, Sats>,
utxo_count: &impl ReadableVec<Height, StoredU64>,
funded_addr_count: &impl ReadableVec<Height, StoredU64>,
max_from: Height,
exit: &Exit,
) -> Result<()> {
self.utxo
.sats
.height
.compute_divide(max_from, supply_sats, utxo_count, exit)?;
self.utxo.compute(prices, max_from, exit)?;
self.addr
.sats
.height
.compute_divide(max_from, supply_sats, funded_addr_count, exit)?;
self.addr.compute(prices, max_from, exit)?;
Ok(())
}
}
@@ -49,7 +49,7 @@ impl SupplyBase {
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
vec![
&mut self.total.sats.height as &mut dyn AnyStoredVec,
&mut self.total.cents.height as &mut dyn AnyStoredVec,
&mut self.total.cents.height,
]
}
@@ -1,5 +1,7 @@
mod avg_amount;
mod base;
mod core;
pub use avg_amount::AvgAmountMetrics;
pub use self::core::SupplyCore;
pub use base::SupplyBase;
+36 -1
View File
@@ -25,7 +25,7 @@ use crate::{
},
indexes, inputs,
internal::{
PerBlockCumulativeRolling, WindowStartVec, Windows,
PerBlockCumulativeRolling, WindowStartVec, Windows, WithAddrTypes,
db_utils::{finalize_db, open_db},
},
outputs, prices, transactions,
@@ -37,6 +37,7 @@ use super::{
AddrActivityVecs, AddrCountsVecs, DeltaVecs, ExposedAddrVecs, NewAddrCountVecs,
ReusedAddrVecs, TotalAddrCountVecs,
},
metrics::AvgAmountMetrics,
};
const VERSION: Version = Version::new(23);
@@ -51,6 +52,7 @@ pub struct AddrMetricsVecs<M: StorageMode = Rw> {
pub reused: ReusedAddrVecs<M>,
pub exposed: ExposedAddrVecs<M>,
pub delta: DeltaVecs,
pub avg_amount: WithAddrTypes<AvgAmountMetrics<M>>,
#[traversable(wrap = "indexes", rename = "funded")]
pub funded_index:
LazyVecFrom1<FundedAddrIndex, FundedAddrIndex, FundedAddrIndex, FundedAddrData>,
@@ -170,6 +172,9 @@ impl Vecs {
// Growth rate: delta change + rate (global + per-type)
let delta = DeltaVecs::new(version, &addr_count, cached_starts, indexes);
// Average amount (supply / utxo_count, supply / funded_addr_count) for `all` and per addr type.
let avg_amount = WithAddrTypes::<AvgAmountMetrics>::forced_import(&db, version, indexes)?;
let this = Self {
supply_state: BytesVec::forced_import_with(
vecdb::ImportOptions::new(&db, "supply_state", version)
@@ -185,6 +190,7 @@ impl Vecs {
reused: reused_addr_count,
exposed: exposed_addr_vecs,
delta,
avg_amount,
funded_index: funded_addr_index,
empty_index: empty_addr_index,
},
@@ -302,6 +308,7 @@ impl Vecs {
self.addrs.activity.reset_height()?;
self.addrs.reused.reset_height()?;
self.addrs.exposed.reset_height()?;
self.addrs.avg_amount.reset_height()?;
reset_state(
&mut self.any_addr_indexes,
&mut self.addrs_data,
@@ -490,6 +497,34 @@ impl Vecs {
exit,
)?;
// Average amount (supply / utxo_count, supply / funded_addr_count) for `all` and per addr type.
let all_m = &self.utxo_cohorts.all.metrics;
self.addrs.avg_amount.all.compute(
prices,
&all_m.supply.total.sats.height,
&all_m.outputs.unspent_count.height,
&self.addrs.funded.all.height,
starting_indexes.height,
exit,
)?;
for ((ot, avg), (_, funded)) in self
.addrs
.avg_amount
.by_addr_type
.iter_mut()
.zip(self.addrs.funded.by_addr_type.iter())
{
let type_m = &t.get(ot).metrics;
avg.compute(
prices,
&type_m.supply.total.sats.height,
&type_m.outputs.unspent_count.height,
&funded.height,
starting_indexes.height,
exit,
)?;
}
// 6c. Compute total_addr_count = addr_count + empty_addr_count
self.addrs.total.compute(
starting_indexes.height,
@@ -267,7 +267,7 @@ impl<T: NumericValue + JsonSchema> PerBlockDistribution<T> {
vec.push(zero);
}
} else {
weighted.sort_unstable_by(|a, b| a.0.cmp(&b.0));
weighted.sort_unstable_by_key(|a| a.0);
max.push(weighted.last().unwrap().0);
pct90.push(get_weighted_percentile(&weighted, 0.90));
@@ -24,9 +24,9 @@ pub use derived::{
RatioCents64, TimesSqrt,
};
pub use ratio::{
RatioCentsBp32, RatioCentsSignedCentsBps32, RatioCentsSignedDollarsBps32, RatioDiffCentsBps32,
RatioDiffDollarsBps32, RatioDiffF32Bps32, RatioDollarsBp16, RatioDollarsBp32,
RatioDollarsBps32, RatioSatsBp16, RatioU64Bp16, RatioU64F32,
RatioCentsBp16, RatioCentsBp32, RatioCentsSignedCentsBps32, RatioCentsSignedDollarsBps32,
RatioDiffCentsBps32, RatioDiffDollarsBps32, RatioDiffF32Bps32, RatioDollarsBp16,
RatioDollarsBp32, RatioDollarsBps32, RatioSatsBp16, RatioU64Bp16, RatioU64F32,
};
pub use specialized::{
BlockCountTarget1m, BlockCountTarget1w, BlockCountTarget1y, BlockCountTarget24h,
@@ -43,6 +43,19 @@ impl BinaryTransform<Cents, Cents, BasisPoints32> for RatioCentsBp32 {
}
}
pub struct RatioCentsBp16;
impl BinaryTransform<Cents, Cents, BasisPoints16> for RatioCentsBp16 {
#[inline(always)]
fn apply(numerator: Cents, denominator: Cents) -> BasisPoints16 {
if denominator == Cents::ZERO {
BasisPoints16::ZERO
} else {
BasisPoints16::from(numerator.inner() as f64 / denominator.inner() as f64)
}
}
}
pub struct RatioDollarsBp16;
impl BinaryTransform<Dollars, Dollars, BasisPoints16> for RatioDollarsBp16 {
@@ -17,6 +17,8 @@ use super::{
WindowStartVec, Windows,
};
use crate::distribution::metrics::AvgAmountMetrics;
/// `all` aggregate plus per-`AddrType` breakdown.
#[derive(Clone, Traversable)]
pub struct WithAddrTypes<T> {
@@ -246,6 +248,42 @@ impl WithAddrTypes<AmountPerBlock> {
}
}
impl WithAddrTypes<AvgAmountMetrics> {
pub(crate) fn forced_import(
db: &Database,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let all = AvgAmountMetrics::forced_import(db, "", version, indexes)?;
let by_addr_type = ByAddrType::new_with_name(|type_name| {
AvgAmountMetrics::forced_import(db, type_name, version, indexes)
})?;
Ok(Self { all, by_addr_type })
}
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
let mut vecs = self.all.collect_vecs_mut();
for v in self.by_addr_type.values_mut() {
vecs.extend(v.collect_vecs_mut());
}
vecs
}
pub(crate) fn par_iter_height_mut(
&mut self,
) -> impl ParallelIterator<Item = &mut dyn AnyStoredVec> {
self.collect_vecs_mut().into_par_iter()
}
pub(crate) fn reset_height(&mut self) -> Result<()> {
self.all.reset_height()?;
for v in self.by_addr_type.values_mut() {
v.reset_height()?;
}
Ok(())
}
}
impl<B: BpsType> WithAddrTypes<PercentPerBlock<B>> {
pub(crate) fn forced_import(
db: &Database,
@@ -1,3 +1,5 @@
use std::cmp::Reverse;
use super::{BLOCK_VSIZE, package::Package};
use crate::types::SelectedTx;
@@ -13,7 +15,7 @@ pub fn partition_into_blocks(
mut packages: Vec<Package>,
num_blocks: usize,
) -> Vec<Vec<SelectedTx>> {
packages.sort_unstable_by(|a, b| b.fee_rate.cmp(&a.fee_rate));
packages.sort_unstable_by_key(|p| Reverse(p.fee_rate));
let mut blocks: Vec<Vec<SelectedTx>> = Vec::with_capacity(num_blocks);
let mut current_block: Vec<SelectedTx> = Vec::new();
+1 -5
View File
@@ -375,11 +375,7 @@ impl Query {
slug: pool_slug,
miner_names,
},
avg_fee: Sats::from(if non_coinbase > 0 {
total_fees_u64 / non_coinbase
} else {
0
}),
avg_fee: Sats::from(total_fees_u64.checked_div(non_coinbase).unwrap_or(0)),
avg_fee_rate: FeeRate::from((total_fees, VSize::from(vsize))),
coinbase_raw,
coinbase_address,
@@ -80,7 +80,7 @@ impl BlockWindow {
.prices
.spot.cents.height
.collect_range_at(self.start, self.end);
let read_start = self.start.saturating_sub(1).max(0);
let read_start = self.start.saturating_sub(1);
let all_cum = cumulative.collect_range_at(read_start, self.end);
let offset = if self.start > 0 { 1 } else { 0 };
@@ -91,19 +91,19 @@ impl BlockWindow {
while pos < total {
let window_end = (pos + self.window).min(total);
let block_count = (window_end - pos) as u64;
if block_count > 0 {
let mid = (pos + window_end) / 2;
let cum_end = all_cum[window_end - 1 + offset];
let cum_start = if pos + offset > 0 {
all_cum[pos + offset - 1]
} else {
Sats::ZERO
};
let total_sats = cum_end - cum_start;
let mid = (pos + window_end) / 2;
let cum_end = all_cum[window_end - 1 + offset];
let cum_start = if pos + offset > 0 {
all_cum[pos + offset - 1]
} else {
Sats::ZERO
};
let total_sats = cum_end - cum_start;
if let Some(avg) = (*total_sats).checked_div(block_count) {
results.push(WindowAvg {
avg_height: Height::from(self.start + mid),
timestamp: all_ts[mid],
avg_value: Sats::from(*total_sats / block_count),
avg_value: Sats::from(avg),
usd: Dollars::from(all_prices[mid]),
});
}
+3 -1
View File
@@ -1,3 +1,5 @@
use std::cmp::Reverse;
use brk_error::{Error, Result};
use brk_types::{
BlockInfoV1, Day1, Height, Pool, PoolBlockCounts, PoolBlockShares, PoolDetail, PoolDetailInfo,
@@ -89,7 +91,7 @@ impl Query {
}
// Sort by block count descending
pool_data.sort_by(|a, b| b.1.cmp(&a.1));
pool_data.sort_by_key(|p| Reverse(p.1));
let total_blocks: u64 = pool_data.iter().map(|(_, count)| count).sum();
@@ -3,6 +3,7 @@
//! Run with:
//! cargo run -p brk_rpc --example compare_backends --features corepc
#[cfg(all(feature = "bitcoincore-rpc", feature = "corepc"))]
use std::time::{Duration, Instant};
#[cfg(not(all(feature = "bitcoincore-rpc", feature = "corepc")))]
@@ -260,6 +261,7 @@ fn main() {
println!("=== All checks passed ===");
}
#[cfg(all(feature = "bitcoincore-rpc", feature = "corepc"))]
fn timed<T>(f: impl FnOnce() -> T) -> (Duration, T) {
let start = Instant::now();
let result = f();
+2
View File
@@ -1,3 +1,5 @@
#![allow(unreachable_patterns, reason = "P2PK65 and P2PK33 both serialize as 'p2pk'")]
use bitcoin::{AddressType, ScriptBuf, opcodes::all::OP_PUSHBYTES_2};
use brk_error::Error;
use schemars::JsonSchema;
+15 -16
View File
@@ -9,7 +9,7 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use vecdb::{CheckedSub, Formattable, Pco, SaturatingAdd};
use crate::StoredF64;
use crate::{StoredF64, StoredU64};
use super::{Bitcoin, Cents, Dollars, Height};
@@ -204,35 +204,34 @@ impl Sum for Sats {
impl Div<Dollars> for Sats {
type Output = Self;
#[allow(clippy::suspicious_arithmetic_impl, reason = "cents-precision upscale before division")]
fn div(self, rhs: Dollars) -> Self::Output {
let raw_cents = u64::from(Cents::from(rhs));
if raw_cents != 0 {
Self(self.0 * 100 / raw_cents)
} else {
Self::MAX
}
(self.0 * 100)
.checked_div(raw_cents)
.map(Self)
.unwrap_or(Self::MAX)
}
}
impl Div<Sats> for Sats {
type Output = Self;
fn div(self, rhs: Sats) -> Self::Output {
if rhs.0 == 0 {
Self(0)
} else {
Self(self.0 / rhs.0)
}
Self(self.0.checked_div(rhs.0).unwrap_or(0))
}
}
impl Div<usize> for Sats {
type Output = Self;
fn div(self, rhs: usize) -> Self::Output {
if rhs == 0 {
Self::ZERO
} else {
Self(self.0 / rhs as u64)
}
Self(self.0.checked_div(rhs as u64).unwrap_or(0))
}
}
impl Div<StoredU64> for Sats {
type Output = Self;
fn div(self, rhs: StoredU64) -> Self::Output {
Self(self.0.checked_div(u64::from(rhs)).unwrap_or(0))
}
}
+2 -4
View File
@@ -99,10 +99,8 @@ fn sanitize(dirty: impl Iterator<Item = String>) -> Vec<String> {
let mut current = String::new();
for c in s.to_lowercase().chars() {
match c {
' ' | ',' | '+' => {
if !current.is_empty() {
clean.push(mem::take(&mut current));
}
' ' | ',' | '+' if !current.is_empty() => {
clean.push(mem::take(&mut current));
}
'-' => current.push('_'),
c if c.is_alphanumeric() || c == '_' => current.push(c),