mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-24 22:59:58 -07:00
181 lines
5.8 KiB
Rust
181 lines
5.8 KiB
Rust
use brk_error::{Error, Result};
|
|
use brk_types::{
|
|
Height, PoolBlockCounts, PoolBlockShares, PoolDetail, PoolDetailInfo, PoolInfo, PoolSlug,
|
|
PoolStats, PoolsSummary, TimePeriod, pools,
|
|
};
|
|
use vecdb::{AnyVec, ReadableVec, VecIndex};
|
|
|
|
use crate::Query;
|
|
|
|
impl Query {
|
|
pub fn mining_pools(&self, time_period: TimePeriod) -> Result<PoolsSummary> {
|
|
let computer = self.computer();
|
|
let current_height = self.height();
|
|
let end = current_height.to_usize();
|
|
|
|
// No blocks indexed yet
|
|
if computer.pools.pool.len() == 0 {
|
|
return Ok(PoolsSummary {
|
|
pools: vec![],
|
|
block_count: 0,
|
|
last_estimated_hashrate: 0,
|
|
});
|
|
}
|
|
|
|
// Calculate start height based on time period
|
|
let start = end.saturating_sub(time_period.block_count());
|
|
|
|
let pools = pools();
|
|
let mut pool_data: Vec<(&'static brk_types::Pool, u64)> = Vec::new();
|
|
|
|
// For each pool, get cumulative count at end and start, subtract to get range count
|
|
for (pool_id, cumulative) in computer
|
|
.pools
|
|
.major
|
|
.iter()
|
|
.map(|(id, v)| (id, &v.blocks_mined.cumulative.height))
|
|
.chain(
|
|
computer
|
|
.pools
|
|
.minor
|
|
.iter()
|
|
.map(|(id, v)| (id, &v.blocks_mined.cumulative.height)),
|
|
)
|
|
{
|
|
let count_at_end: u64 = *cumulative.collect_one(current_height).unwrap_or_default();
|
|
|
|
let count_at_start: u64 = if start == 0 {
|
|
0
|
|
} else {
|
|
*cumulative
|
|
.collect_one(Height::from(start - 1))
|
|
.unwrap_or_default()
|
|
};
|
|
|
|
let block_count = count_at_end.saturating_sub(count_at_start);
|
|
|
|
if block_count > 0 {
|
|
pool_data.push((pools.get(*pool_id), block_count));
|
|
}
|
|
}
|
|
|
|
// Sort by block count descending
|
|
pool_data.sort_by(|a, b| b.1.cmp(&a.1));
|
|
|
|
let total_blocks: u64 = pool_data.iter().map(|(_, count)| count).sum();
|
|
|
|
// Build stats with ranks
|
|
let pool_stats: Vec<PoolStats> = pool_data
|
|
.into_iter()
|
|
.enumerate()
|
|
.map(|(idx, (pool, block_count))| {
|
|
let share = if total_blocks > 0 {
|
|
block_count as f64 / total_blocks as f64
|
|
} else {
|
|
0.0
|
|
};
|
|
PoolStats::new(pool, block_count, (idx + 1) as u32, share)
|
|
})
|
|
.collect();
|
|
|
|
// TODO: Calculate actual hashrate from difficulty
|
|
let last_estimated_hashrate = 0u128;
|
|
|
|
Ok(PoolsSummary {
|
|
pools: pool_stats,
|
|
block_count: total_blocks,
|
|
last_estimated_hashrate,
|
|
})
|
|
}
|
|
|
|
pub fn all_pools(&self) -> Vec<PoolInfo> {
|
|
pools().iter().map(PoolInfo::from).collect()
|
|
}
|
|
|
|
pub fn pool_detail(&self, slug: PoolSlug) -> Result<PoolDetail> {
|
|
let computer = self.computer();
|
|
let current_height = self.height();
|
|
let end = current_height.to_usize();
|
|
|
|
let pools_list = pools();
|
|
let pool = pools_list.get(slug);
|
|
|
|
// Get cumulative blocks for this pool (works for both major and minor)
|
|
let cumulative = computer
|
|
.pools
|
|
.major
|
|
.get(&slug)
|
|
.map(|v| &v.blocks_mined.cumulative.height)
|
|
.or_else(|| {
|
|
computer
|
|
.pools
|
|
.minor
|
|
.get(&slug)
|
|
.map(|v| &v.blocks_mined.cumulative.height)
|
|
})
|
|
.ok_or_else(|| Error::NotFound("Pool data not found".into()))?;
|
|
|
|
// Get total blocks (all time)
|
|
let total_all: u64 = *cumulative.collect_one(current_height).unwrap_or_default();
|
|
|
|
// Get blocks for 24h (144 blocks)
|
|
let start_24h = end.saturating_sub(144);
|
|
let count_before_24h: u64 = if start_24h == 0 {
|
|
0
|
|
} else {
|
|
*cumulative
|
|
.collect_one(Height::from(start_24h - 1))
|
|
.unwrap_or_default()
|
|
};
|
|
let total_24h = total_all.saturating_sub(count_before_24h);
|
|
|
|
// Get blocks for 1w (1008 blocks)
|
|
let start_1w = end.saturating_sub(1008);
|
|
let count_before_1w: u64 = if start_1w == 0 {
|
|
0
|
|
} else {
|
|
*cumulative
|
|
.collect_one(Height::from(start_1w - 1))
|
|
.unwrap_or_default()
|
|
};
|
|
let total_1w = total_all.saturating_sub(count_before_1w);
|
|
|
|
// Calculate total network blocks for share calculation
|
|
let network_blocks_all = (end + 1) as u64;
|
|
let network_blocks_24h = (end - start_24h + 1) as u64;
|
|
let network_blocks_1w = (end - start_1w + 1) as u64;
|
|
|
|
let share_all = if network_blocks_all > 0 {
|
|
total_all as f64 / network_blocks_all as f64
|
|
} else {
|
|
0.0
|
|
};
|
|
let share_24h = if network_blocks_24h > 0 {
|
|
total_24h as f64 / network_blocks_24h as f64
|
|
} else {
|
|
0.0
|
|
};
|
|
let share_1w = if network_blocks_1w > 0 {
|
|
total_1w as f64 / network_blocks_1w as f64
|
|
} else {
|
|
0.0
|
|
};
|
|
|
|
Ok(PoolDetail {
|
|
pool: PoolDetailInfo::from(pool),
|
|
block_count: PoolBlockCounts {
|
|
all: total_all,
|
|
day: total_24h,
|
|
week: total_1w,
|
|
},
|
|
block_share: PoolBlockShares {
|
|
all: share_all,
|
|
day: share_24h,
|
|
week: share_1w,
|
|
},
|
|
estimated_hashrate: 0, // TODO: Calculate from share and network hashrate
|
|
reported_hashrate: None,
|
|
})
|
|
}
|
|
}
|