brk_computer 0.3.0-beta.9

A Bitcoin dataset computer built on top of brk_indexer
Documentation
use brk_error::Result;
use brk_indexer::Indexer;
use brk_types::{CheckedSub, Dollars, Halving, Sats};
use vecdb::{Exit, ReadableVec, VecIndex};

use super::Vecs;
use crate::{
    blocks, indexes,
    internal::{RatioDollarsBp32, RatioSatsBp16},
    prices, transactions,
};

impl Vecs {
    #[allow(clippy::too_many_arguments)]
    pub(crate) fn compute(
        &mut self,
        indexer: &Indexer,
        indexes: &indexes::Vecs,
        lookback: &blocks::LookbackVecs,
        transactions: &transactions::Vecs,
        prices: &prices::Vecs,
        exit: &Exit,
    ) -> Result<()> {
        let starting_height = indexer.safe_lengths().height;

        // coinbase and fees are independent — parallelize
        let window_starts = lookback.window_starts();
        let (r_coinbase, r_fees) = rayon::join(
            || {
                self.coinbase.compute(starting_height, prices, exit, |vec| {
                    let mut txout_cursor = indexer.vecs.transactions.first_txout_index.cursor();
                    let mut count_cursor = indexes.tx_index.output_count.cursor();

                    vec.compute_transform(
                        starting_height,
                        &indexer.vecs.transactions.first_tx_index,
                        |(height, tx_index, ..)| {
                            let ti = tx_index.to_usize();

                            txout_cursor.advance(ti - txout_cursor.position());
                            let first_txout_index = txout_cursor.next().unwrap().to_usize();

                            count_cursor.advance(ti - count_cursor.position());
                            let output_count: usize = count_cursor.next().unwrap().into();

                            let sats = indexer.vecs.outputs.value.fold_range_at(
                                first_txout_index,
                                first_txout_index + output_count,
                                Sats::ZERO,
                                |acc, v| acc + v,
                            );
                            (height, sats)
                        },
                        exit,
                    )?;
                    Ok(())
                })
            },
            || {
                self.fees
                    .compute(starting_height, &window_starts, prices, exit, |vec| {
                        vec.compute_sum_from_indexes(
                            starting_height,
                            &indexer.vecs.transactions.first_tx_index,
                            &indexes.height.tx_index_count,
                            &transactions.fees.fee.tx_index,
                            exit,
                        )?;
                        Ok(())
                    })
            },
        );
        r_coinbase?;
        r_fees?;

        self.subsidy.block.sats.compute_transform2(
            starting_height,
            &self.coinbase.block.sats,
            &self.fees.block.sats,
            |(height, coinbase, fees, ..)| {
                (
                    height,
                    coinbase.checked_sub(fees).unwrap_or_else(|| {
                        panic!("coinbase {coinbase:?} < fees {fees:?} at {height:?}")
                    }),
                )
            },
            exit,
        )?;
        self.subsidy.compute_rest(starting_height, prices, exit)?;

        self.output_volume.compute_subtract(
            starting_height,
            &transactions.volume.transfer_volume.block.sats,
            &self.fees.block.sats,
            exit,
        )?;

        self.unclaimed.block.sats.compute_transform(
            starting_height,
            &self.subsidy.block.sats,
            |(height, subsidy, ..)| {
                let halving = Halving::from(height);
                let expected = Sats::FIFTY_BTC / 2_usize.pow(halving.to_usize() as u32);
                (height, expected.checked_sub(subsidy).unwrap())
            },
            exit,
        )?;
        self.unclaimed.compute(prices, starting_height, exit)?;

        self.fee_dominance
            .compute_binary::<Sats, Sats, RatioSatsBp16, _, _, _, _>(
                starting_height,
                &self.fees.cumulative.sats.height,
                &self.coinbase.cumulative.sats.height,
                self.fees.sum.as_array().map(|w| &w.sats.height),
                self.coinbase.sum.as_array().map(|w| &w.sats.height),
                exit,
            )?;

        self.fee_to_subsidy_ratio
            .compute_binary::<Dollars, Dollars, RatioDollarsBp32, _, _>(
                starting_height,
                self.coinbase.sum.as_array().map(|w| &w.usd.height),
                self.fees.sum.as_array().map(|w| &w.usd.height),
                exit,
            )?;

        Ok(())
    }
}