mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-05-21 07:14:47 -07:00
547 lines
16 KiB
Rust
547 lines
16 KiB
Rust
mod address;
|
|
mod dateindex;
|
|
mod decadeindex;
|
|
mod difficultyepoch;
|
|
mod halvingepoch;
|
|
mod height;
|
|
mod monthindex;
|
|
mod quarterindex;
|
|
mod semesterindex;
|
|
mod txindex;
|
|
mod txinindex;
|
|
mod txoutindex;
|
|
mod weekindex;
|
|
mod yearindex;
|
|
|
|
use std::path::Path;
|
|
|
|
use brk_error::Result;
|
|
use brk_indexer::Indexer;
|
|
use brk_traversable::Traversable;
|
|
use brk_types::{Date, DateIndex, Indexes, MonthIndex, Version, WeekIndex};
|
|
use vecdb::{Database, Exit, IterableVec, PAGE_SIZE, TypedVecIterator};
|
|
|
|
use crate::blocks;
|
|
|
|
pub use address::Vecs as AddressVecs;
|
|
pub use brk_types::ComputeIndexes;
|
|
pub use dateindex::Vecs as DateIndexVecs;
|
|
pub use decadeindex::Vecs as DecadeIndexVecs;
|
|
pub use difficultyepoch::Vecs as DifficultyEpochVecs;
|
|
pub use halvingepoch::Vecs as HalvingEpochVecs;
|
|
pub use height::Vecs as HeightVecs;
|
|
pub use monthindex::Vecs as MonthIndexVecs;
|
|
pub use quarterindex::Vecs as QuarterIndexVecs;
|
|
pub use semesterindex::Vecs as SemesterIndexVecs;
|
|
pub use txindex::Vecs as TxIndexVecs;
|
|
pub use txinindex::Vecs as TxInIndexVecs;
|
|
pub use txoutindex::Vecs as TxOutIndexVecs;
|
|
pub use weekindex::Vecs as WeekIndexVecs;
|
|
pub use yearindex::Vecs as YearIndexVecs;
|
|
|
|
const VERSION: Version = Version::ZERO;
|
|
pub const DB_NAME: &str = "indexes";
|
|
|
|
#[derive(Clone, Traversable)]
|
|
pub struct Vecs {
|
|
db: Database,
|
|
pub address: AddressVecs,
|
|
pub height: HeightVecs,
|
|
pub difficultyepoch: DifficultyEpochVecs,
|
|
pub halvingepoch: HalvingEpochVecs,
|
|
pub dateindex: DateIndexVecs,
|
|
pub weekindex: WeekIndexVecs,
|
|
pub monthindex: MonthIndexVecs,
|
|
pub quarterindex: QuarterIndexVecs,
|
|
pub semesterindex: SemesterIndexVecs,
|
|
pub yearindex: YearIndexVecs,
|
|
pub decadeindex: DecadeIndexVecs,
|
|
pub txindex: TxIndexVecs,
|
|
pub txinindex: TxInIndexVecs,
|
|
pub txoutindex: TxOutIndexVecs,
|
|
}
|
|
|
|
impl Vecs {
|
|
pub fn forced_import(
|
|
parent: &Path,
|
|
parent_version: Version,
|
|
indexer: &Indexer,
|
|
) -> Result<Self> {
|
|
let db = Database::open(&parent.join(DB_NAME))?;
|
|
db.set_min_len(PAGE_SIZE * 10_000_000)?;
|
|
|
|
let version = parent_version + VERSION;
|
|
|
|
let this = Self {
|
|
address: AddressVecs::forced_import(version, indexer),
|
|
height: HeightVecs::forced_import(&db, version)?,
|
|
difficultyepoch: DifficultyEpochVecs::forced_import(&db, version)?,
|
|
halvingepoch: HalvingEpochVecs::forced_import(&db, version)?,
|
|
dateindex: DateIndexVecs::forced_import(&db, version)?,
|
|
weekindex: WeekIndexVecs::forced_import(&db, version)?,
|
|
monthindex: MonthIndexVecs::forced_import(&db, version)?,
|
|
quarterindex: QuarterIndexVecs::forced_import(&db, version)?,
|
|
semesterindex: SemesterIndexVecs::forced_import(&db, version)?,
|
|
yearindex: YearIndexVecs::forced_import(&db, version)?,
|
|
decadeindex: DecadeIndexVecs::forced_import(&db, version)?,
|
|
txindex: TxIndexVecs::forced_import(&db, version, indexer)?,
|
|
txinindex: TxInIndexVecs::forced_import(version, indexer),
|
|
txoutindex: TxOutIndexVecs::forced_import(version, indexer),
|
|
db,
|
|
};
|
|
|
|
this.db.retain_regions(
|
|
this.iter_any_exportable()
|
|
.flat_map(|v| v.region_names())
|
|
.collect(),
|
|
)?;
|
|
this.db.compact()?;
|
|
|
|
Ok(this)
|
|
}
|
|
|
|
pub fn compute(
|
|
&mut self,
|
|
indexer: &Indexer,
|
|
blocks_time: &blocks::time::Vecs,
|
|
starting_indexes: Indexes,
|
|
exit: &Exit,
|
|
) -> Result<ComputeIndexes> {
|
|
let indexes = self.compute_(indexer, blocks_time, starting_indexes, exit)?;
|
|
let _lock = exit.lock();
|
|
self.db.compact()?;
|
|
Ok(indexes)
|
|
}
|
|
|
|
fn compute_(
|
|
&mut self,
|
|
indexer: &Indexer,
|
|
blocks_time: &blocks::time::Vecs,
|
|
starting_indexes: Indexes,
|
|
exit: &Exit,
|
|
) -> Result<ComputeIndexes> {
|
|
// Transaction indexes - compute input/output counts
|
|
self.txindex.input_count.compute_count_from_indexes(
|
|
starting_indexes.txindex,
|
|
&indexer.vecs.transactions.first_txinindex,
|
|
&indexer.vecs.inputs.outpoint,
|
|
exit,
|
|
)?;
|
|
self.txindex.output_count.compute_count_from_indexes(
|
|
starting_indexes.txindex,
|
|
&indexer.vecs.transactions.first_txoutindex,
|
|
&indexer.vecs.outputs.value,
|
|
exit,
|
|
)?;
|
|
|
|
// Height indexes
|
|
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,
|
|
)?;
|
|
|
|
let decremented_starting_height = starting_indexes.height.decremented().unwrap_or_default();
|
|
|
|
// DateIndex (uses blocks_time.date_monotonic computed in blocks::time::compute_early)
|
|
let starting_dateindex = self
|
|
.height
|
|
.dateindex
|
|
.into_iter()
|
|
.get(decremented_starting_height)
|
|
.unwrap_or_default();
|
|
|
|
self.height.dateindex.compute_transform(
|
|
starting_indexes.height,
|
|
&blocks_time.date,
|
|
|(h, d, ..)| (h, DateIndex::try_from(d).unwrap()),
|
|
exit,
|
|
)?;
|
|
|
|
let starting_dateindex = if let Some(dateindex) = self
|
|
.height
|
|
.dateindex
|
|
.into_iter()
|
|
.get(decremented_starting_height)
|
|
{
|
|
starting_dateindex.min(dateindex)
|
|
} else {
|
|
starting_dateindex
|
|
};
|
|
|
|
// Difficulty epoch
|
|
let starting_difficultyepoch = self
|
|
.height
|
|
.difficultyepoch
|
|
.into_iter()
|
|
.get(decremented_starting_height)
|
|
.unwrap_or_default();
|
|
|
|
self.height.difficultyepoch.compute_from_index(
|
|
starting_indexes.height,
|
|
&indexer.vecs.blocks.weight,
|
|
exit,
|
|
)?;
|
|
|
|
self.difficultyepoch.first_height.compute_coarser(
|
|
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
|
|
.into_iter()
|
|
.get(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_coarser(
|
|
starting_indexes.height,
|
|
&self.height.halvingepoch,
|
|
exit,
|
|
)?;
|
|
|
|
self.halvingepoch.identity.compute_from_index(
|
|
starting_halvingepoch,
|
|
&self.halvingepoch.first_height,
|
|
exit,
|
|
)?;
|
|
|
|
// Time indexes (depends on height.dateindex)
|
|
self.dateindex.first_height.compute_coarser(
|
|
starting_indexes.height,
|
|
&self.height.dateindex,
|
|
exit,
|
|
)?;
|
|
|
|
self.dateindex.identity.compute_from_index(
|
|
starting_dateindex,
|
|
&self.dateindex.first_height,
|
|
exit,
|
|
)?;
|
|
|
|
self.dateindex.date.compute_transform(
|
|
starting_dateindex,
|
|
&self.dateindex.identity,
|
|
|(di, ..)| (di, Date::from(di)),
|
|
exit,
|
|
)?;
|
|
|
|
self.dateindex.height_count.compute_count_from_indexes(
|
|
starting_dateindex,
|
|
&self.dateindex.first_height,
|
|
&indexer.vecs.blocks.weight,
|
|
exit,
|
|
)?;
|
|
|
|
// Week
|
|
let starting_weekindex = self
|
|
.dateindex
|
|
.weekindex
|
|
.into_iter()
|
|
.get(starting_dateindex)
|
|
.unwrap_or_default();
|
|
|
|
self.dateindex.weekindex.compute_range(
|
|
starting_dateindex,
|
|
&self.dateindex.identity,
|
|
|i| (i, WeekIndex::from(i)),
|
|
exit,
|
|
)?;
|
|
|
|
self.weekindex.first_dateindex.compute_coarser(
|
|
starting_dateindex,
|
|
&self.dateindex.weekindex,
|
|
exit,
|
|
)?;
|
|
|
|
self.weekindex.identity.compute_from_index(
|
|
starting_weekindex,
|
|
&self.weekindex.first_dateindex,
|
|
exit,
|
|
)?;
|
|
|
|
self.weekindex.date.compute_transform(
|
|
starting_weekindex,
|
|
&self.weekindex.first_dateindex,
|
|
|(wi, first_di, ..)| (wi, Date::from(first_di)),
|
|
exit,
|
|
)?;
|
|
|
|
self.weekindex.dateindex_count.compute_count_from_indexes(
|
|
starting_weekindex,
|
|
&self.weekindex.first_dateindex,
|
|
&self.dateindex.date,
|
|
exit,
|
|
)?;
|
|
|
|
// Month
|
|
let starting_monthindex = self
|
|
.dateindex
|
|
.monthindex
|
|
.into_iter()
|
|
.get(starting_dateindex)
|
|
.unwrap_or_default();
|
|
|
|
self.dateindex.monthindex.compute_range(
|
|
starting_dateindex,
|
|
&self.dateindex.identity,
|
|
|i| (i, MonthIndex::from(i)),
|
|
exit,
|
|
)?;
|
|
|
|
self.monthindex.first_dateindex.compute_coarser(
|
|
starting_dateindex,
|
|
&self.dateindex.monthindex,
|
|
exit,
|
|
)?;
|
|
|
|
self.monthindex.identity.compute_from_index(
|
|
starting_monthindex,
|
|
&self.monthindex.first_dateindex,
|
|
exit,
|
|
)?;
|
|
|
|
self.monthindex.date.compute_transform(
|
|
starting_monthindex,
|
|
&self.monthindex.first_dateindex,
|
|
|(mi, first_di, ..)| (mi, Date::from(first_di)),
|
|
exit,
|
|
)?;
|
|
|
|
self.monthindex.dateindex_count.compute_count_from_indexes(
|
|
starting_monthindex,
|
|
&self.monthindex.first_dateindex,
|
|
&self.dateindex.date,
|
|
exit,
|
|
)?;
|
|
|
|
// Quarter
|
|
let starting_quarterindex = self
|
|
.monthindex
|
|
.quarterindex
|
|
.into_iter()
|
|
.get(starting_monthindex)
|
|
.unwrap_or_default();
|
|
|
|
self.monthindex.quarterindex.compute_from_index(
|
|
starting_monthindex,
|
|
&self.monthindex.first_dateindex,
|
|
exit,
|
|
)?;
|
|
|
|
self.quarterindex.first_monthindex.compute_coarser(
|
|
starting_monthindex,
|
|
&self.monthindex.quarterindex,
|
|
exit,
|
|
)?;
|
|
|
|
self.quarterindex.identity.compute_from_index(
|
|
starting_quarterindex,
|
|
&self.quarterindex.first_monthindex,
|
|
exit,
|
|
)?;
|
|
|
|
let monthindex_first_dateindex = &self.monthindex.first_dateindex;
|
|
self.quarterindex.date.compute_transform(
|
|
starting_quarterindex,
|
|
&self.quarterindex.first_monthindex,
|
|
|(qi, first_mi, _)| {
|
|
let first_di = monthindex_first_dateindex.iter().get_unwrap(first_mi);
|
|
(qi, Date::from(first_di))
|
|
},
|
|
exit,
|
|
)?;
|
|
|
|
self.quarterindex
|
|
.monthindex_count
|
|
.compute_count_from_indexes(
|
|
starting_quarterindex,
|
|
&self.quarterindex.first_monthindex,
|
|
&self.monthindex.identity,
|
|
exit,
|
|
)?;
|
|
|
|
// Semester
|
|
let starting_semesterindex = self
|
|
.monthindex
|
|
.semesterindex
|
|
.into_iter()
|
|
.get(starting_monthindex)
|
|
.unwrap_or_default();
|
|
|
|
self.monthindex.semesterindex.compute_from_index(
|
|
starting_monthindex,
|
|
&self.monthindex.first_dateindex,
|
|
exit,
|
|
)?;
|
|
|
|
self.semesterindex.first_monthindex.compute_coarser(
|
|
starting_monthindex,
|
|
&self.monthindex.semesterindex,
|
|
exit,
|
|
)?;
|
|
|
|
self.semesterindex.identity.compute_from_index(
|
|
starting_semesterindex,
|
|
&self.semesterindex.first_monthindex,
|
|
exit,
|
|
)?;
|
|
|
|
let monthindex_first_dateindex = &self.monthindex.first_dateindex;
|
|
self.semesterindex.date.compute_transform(
|
|
starting_semesterindex,
|
|
&self.semesterindex.first_monthindex,
|
|
|(si, first_mi, _)| {
|
|
let first_di = monthindex_first_dateindex.iter().get_unwrap(first_mi);
|
|
(si, Date::from(first_di))
|
|
},
|
|
exit,
|
|
)?;
|
|
|
|
self.semesterindex
|
|
.monthindex_count
|
|
.compute_count_from_indexes(
|
|
starting_semesterindex,
|
|
&self.semesterindex.first_monthindex,
|
|
&self.monthindex.identity,
|
|
exit,
|
|
)?;
|
|
|
|
// Year
|
|
let starting_yearindex = self
|
|
.monthindex
|
|
.yearindex
|
|
.into_iter()
|
|
.get(starting_monthindex)
|
|
.unwrap_or_default();
|
|
|
|
self.monthindex.yearindex.compute_from_index(
|
|
starting_monthindex,
|
|
&self.monthindex.first_dateindex,
|
|
exit,
|
|
)?;
|
|
|
|
self.yearindex.first_monthindex.compute_coarser(
|
|
starting_monthindex,
|
|
&self.monthindex.yearindex,
|
|
exit,
|
|
)?;
|
|
|
|
self.yearindex.identity.compute_from_index(
|
|
starting_yearindex,
|
|
&self.yearindex.first_monthindex,
|
|
exit,
|
|
)?;
|
|
|
|
let monthindex_first_dateindex = &self.monthindex.first_dateindex;
|
|
self.yearindex.date.compute_transform(
|
|
starting_yearindex,
|
|
&self.yearindex.first_monthindex,
|
|
|(yi, first_mi, _)| {
|
|
let first_di = monthindex_first_dateindex.iter().get_unwrap(first_mi);
|
|
(yi, Date::from(first_di))
|
|
},
|
|
exit,
|
|
)?;
|
|
|
|
self.yearindex.monthindex_count.compute_count_from_indexes(
|
|
starting_yearindex,
|
|
&self.yearindex.first_monthindex,
|
|
&self.monthindex.identity,
|
|
exit,
|
|
)?;
|
|
|
|
// Decade
|
|
let starting_decadeindex = self
|
|
.yearindex
|
|
.decadeindex
|
|
.into_iter()
|
|
.get(starting_yearindex)
|
|
.unwrap_or_default();
|
|
|
|
self.yearindex.decadeindex.compute_from_index(
|
|
starting_yearindex,
|
|
&self.yearindex.first_monthindex,
|
|
exit,
|
|
)?;
|
|
|
|
self.decadeindex.first_yearindex.compute_coarser(
|
|
starting_yearindex,
|
|
&self.yearindex.decadeindex,
|
|
exit,
|
|
)?;
|
|
|
|
self.decadeindex.identity.compute_from_index(
|
|
starting_decadeindex,
|
|
&self.decadeindex.first_yearindex,
|
|
exit,
|
|
)?;
|
|
|
|
let yearindex_first_monthindex = &self.yearindex.first_monthindex;
|
|
let monthindex_first_dateindex = &self.monthindex.first_dateindex;
|
|
self.decadeindex.date.compute_transform(
|
|
starting_decadeindex,
|
|
&self.decadeindex.first_yearindex,
|
|
|(di, first_yi, _)| {
|
|
let first_mi = yearindex_first_monthindex.iter().get_unwrap(first_yi);
|
|
let first_di = monthindex_first_dateindex.iter().get_unwrap(first_mi);
|
|
(di, Date::from(first_di))
|
|
},
|
|
exit,
|
|
)?;
|
|
|
|
self.decadeindex
|
|
.yearindex_count
|
|
.compute_count_from_indexes(
|
|
starting_decadeindex,
|
|
&self.decadeindex.first_yearindex,
|
|
&self.yearindex.identity,
|
|
exit,
|
|
)?;
|
|
|
|
Ok(ComputeIndexes::new(
|
|
starting_indexes,
|
|
starting_dateindex,
|
|
starting_weekindex,
|
|
starting_monthindex,
|
|
starting_quarterindex,
|
|
starting_semesterindex,
|
|
starting_yearindex,
|
|
starting_decadeindex,
|
|
starting_difficultyepoch,
|
|
starting_halvingepoch,
|
|
))
|
|
}
|
|
}
|