global: renames part 2

This commit is contained in:
nym21
2026-03-13 22:42:43 +01:00
parent 0795c1bbf8
commit a0d378d06d
117 changed files with 3024 additions and 3189 deletions
@@ -259,7 +259,7 @@ impl AddressTypeToActivityCountVecs {
pub struct AddressActivityVecs<M: StorageMode = Rw> {
pub all: ActivityCountVecs<M>,
#[traversable(flatten)]
pub by_addresstype: AddressTypeToActivityCountVecs<M>,
pub by_address_type: AddressTypeToActivityCountVecs<M>,
}
impl AddressActivityVecs {
@@ -272,7 +272,7 @@ impl AddressActivityVecs {
) -> Result<Self> {
Ok(Self {
all: ActivityCountVecs::forced_import(db, name, version, indexes, cached_starts)?,
by_addresstype: AddressTypeToActivityCountVecs::forced_import(
by_address_type: AddressTypeToActivityCountVecs::forced_import(
db, name, version, indexes, cached_starts,
)?,
})
@@ -281,7 +281,7 @@ impl AddressActivityVecs {
pub(crate) fn min_stateful_len(&self) -> usize {
self.all
.min_stateful_len()
.min(self.by_addresstype.min_stateful_len())
.min(self.by_address_type.min_stateful_len())
}
pub(crate) fn par_iter_height_mut(
@@ -289,12 +289,12 @@ impl AddressActivityVecs {
) -> impl ParallelIterator<Item = &mut dyn AnyStoredVec> {
self.all
.par_iter_height_mut()
.chain(self.by_addresstype.par_iter_height_mut())
.chain(self.by_address_type.par_iter_height_mut())
}
pub(crate) fn reset_height(&mut self) -> Result<()> {
self.all.reset_height()?;
self.by_addresstype.reset_height()?;
self.by_address_type.reset_height()?;
Ok(())
}
@@ -304,7 +304,7 @@ impl AddressActivityVecs {
exit: &Exit,
) -> Result<()> {
self.all.compute_rest(max_from, exit)?;
self.by_addresstype.compute_rest(max_from, exit)?;
self.by_address_type.compute_rest(max_from, exit)?;
Ok(())
}
@@ -315,7 +315,7 @@ impl AddressActivityVecs {
) -> Result<()> {
let totals = counts.totals();
self.all.truncate_push_height(height, &totals)?;
self.by_addresstype.truncate_push_height(height, counts)?;
self.by_address_type.truncate_push_height(height, counts)?;
Ok(())
}
}
@@ -165,7 +165,7 @@ impl AddressTypeToAddressCountVecs {
pub struct AddressCountsVecs<M: StorageMode = Rw> {
pub all: AddressCountVecs<M>,
#[traversable(flatten)]
pub by_addresstype: AddressTypeToAddressCountVecs<M>,
pub by_address_type: AddressTypeToAddressCountVecs<M>,
}
impl AddressCountsVecs {
@@ -177,24 +177,24 @@ impl AddressCountsVecs {
) -> Result<Self> {
Ok(Self {
all: AddressCountVecs::forced_import(db, name, version, indexes)?,
by_addresstype: AddressTypeToAddressCountVecs::forced_import(db, name, version, indexes)?,
by_address_type: AddressTypeToAddressCountVecs::forced_import(db, name, version, indexes)?,
})
}
pub(crate) fn min_stateful_len(&self) -> usize {
self.all.height.len().min(self.by_addresstype.min_stateful_len())
self.all.height.len().min(self.by_address_type.min_stateful_len())
}
pub(crate) fn par_iter_height_mut(
&mut self,
) -> impl ParallelIterator<Item = &mut dyn AnyStoredVec> {
rayon::iter::once(&mut self.all.height as &mut dyn AnyStoredVec)
.chain(self.by_addresstype.par_iter_height_mut())
.chain(self.by_address_type.par_iter_height_mut())
}
pub(crate) fn reset_height(&mut self) -> Result<()> {
self.all.height.reset()?;
self.by_addresstype.reset_height()?;
self.by_address_type.reset_height()?;
Ok(())
}
@@ -205,7 +205,7 @@ impl AddressCountsVecs {
address_counts: &AddressTypeToAddressCount,
) -> Result<()> {
self.all.height.truncate_push(height, total.into())?;
self.by_addresstype
self.by_address_type
.truncate_push_height(height, address_counts)?;
Ok(())
}
@@ -215,7 +215,7 @@ impl AddressCountsVecs {
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
let sources = self.by_addresstype.by_height();
let sources = self.by_address_type.by_height();
self.all
.height
.compute_sum_of_others(starting_indexes.height, &sources, exit)?;
@@ -1,6 +1,6 @@
use brk_cohort::ByAddressType;
use brk_traversable::Traversable;
use brk_types::{BasisPoints32, StoredI64, StoredU64, Version};
use brk_types::{BasisPointsSigned32, StoredI64, StoredU64, Version};
use crate::{
indexes,
@@ -9,13 +9,13 @@ use crate::{
use super::AddressCountsVecs;
type AddrDelta = LazyRollingDeltasFromHeight<StoredU64, StoredI64, BasisPoints32>;
type AddrDelta = LazyRollingDeltasFromHeight<StoredU64, StoredI64, BasisPointsSigned32>;
#[derive(Clone, Traversable)]
pub struct DeltaVecs {
pub all: AddrDelta,
#[traversable(flatten)]
pub by_addresstype: ByAddressType<AddrDelta>,
pub by_address_type: ByAddressType<AddrDelta>,
}
impl DeltaVecs {
@@ -35,7 +35,7 @@ impl DeltaVecs {
indexes,
);
let by_addresstype = address_count.by_addresstype.map_with_name(|name, addr| {
let by_address_type = address_count.by_address_type.map_with_name(|name, addr| {
LazyRollingDeltasFromHeight::new(
&format!("{name}_address_count"),
version,
@@ -47,7 +47,7 @@ impl DeltaVecs {
Self {
all,
by_addresstype,
by_address_type,
}
}
}
@@ -32,7 +32,7 @@ macro_rules! define_any_address_indexes_vecs {
pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> {
Ok(Self {
$($field: BytesVec::forced_import_with(
ImportOptions::new(db, "anyaddressindex", version)
ImportOptions::new(db, "any_address_index", version)
.with_saved_stamped_changes(SAVED_STAMPED_CHANGES),
)?,)*
})
@@ -57,11 +57,11 @@ macro_rules! define_any_address_indexes_vecs {
Ok(())
}
/// Get address index for a given type and typeindex.
/// Get address index for a given type and type_index.
/// Uses get_any_or_read_at to check updated layer (needed after rollback).
pub(crate) fn get(&self, address_type: OutputType, typeindex: TypeIndex, reader: &Reader) -> Result<AnyAddressIndex> {
pub(crate) fn get(&self, address_type: OutputType, type_index: TypeIndex, reader: &Reader) -> Result<AnyAddressIndex> {
match address_type {
$(OutputType::$variant => Ok(self.$field.get_any_or_read_at(typeindex.into(), reader)?.unwrap()),)*
$(OutputType::$variant => Ok(self.$field.get_any_or_read_at(type_index.into(), reader)?.unwrap()),)*
_ => unreachable!("Invalid address type: {:?}", address_type),
}
}
@@ -74,10 +74,10 @@ macro_rules! define_any_address_indexes_vecs {
impl<M: StorageMode> AnyAddressIndexesVecs<M> {
/// Get address index with single read (no caching).
pub fn get_once(&self, address_type: OutputType, typeindex: TypeIndex) -> Result<AnyAddressIndex> {
pub fn get_once(&self, address_type: OutputType, type_index: TypeIndex) -> Result<AnyAddressIndex> {
match address_type {
$(OutputType::$variant => self.$field
.collect_one(<$index>::from(usize::from(typeindex)))
.collect_one(<$index>::from(usize::from(type_index)))
.ok_or_else(|| Error::UnsupportedType(address_type.to_string())),)*
_ => Err(Error::UnsupportedType(address_type.to_string())),
}
@@ -177,18 +177,18 @@ fn process_single_type_merged<I: vecdb::VecIndex>(
let mut pushes = Vec::with_capacity(map1.len() + map2.len());
let mut update_count = 0usize;
for (typeindex, any_index) in map1.into_iter().chain(map2) {
if usize::from(typeindex) < current_len {
vec.update(I::from(usize::from(typeindex)), any_index)?;
for (type_index, any_index) in map1.into_iter().chain(map2) {
if usize::from(type_index) < current_len {
vec.update(I::from(usize::from(type_index)), any_index)?;
update_count += 1;
} else {
pushes.push((typeindex, any_index));
pushes.push((type_index, any_index));
}
}
let push_count = pushes.len();
if !pushes.is_empty() {
pushes.sort_unstable_by_key(|(typeindex, _)| *typeindex);
pushes.sort_unstable_by_key(|(type_index, _)| *type_index);
for (_, any_index) in pushes {
vec.push(any_index);
}
@@ -16,7 +16,7 @@ use super::TotalAddressCountVecs;
pub struct NewAddressCountVecs<M: StorageMode = Rw> {
pub all: PerBlockCumulativeWithSums<StoredU64, StoredU64, M>,
#[traversable(flatten)]
pub by_addresstype: ByAddressType<PerBlockCumulativeWithSums<StoredU64, StoredU64, M>>,
pub by_address_type: ByAddressType<PerBlockCumulativeWithSums<StoredU64, StoredU64, M>>,
}
impl NewAddressCountVecs {
@@ -34,7 +34,7 @@ impl NewAddressCountVecs {
cached_starts,
)?;
let by_addresstype = ByAddressType::new_with_name(|name| {
let by_address_type = ByAddressType::new_with_name(|name| {
PerBlockCumulativeWithSums::forced_import(
db,
&format!("{name}_new_address_count"),
@@ -46,7 +46,7 @@ impl NewAddressCountVecs {
Ok(Self {
all,
by_addresstype,
by_address_type,
})
}
@@ -61,9 +61,9 @@ impl NewAddressCountVecs {
})?;
for ((_, new), (_, total)) in self
.by_addresstype
.by_address_type
.iter_mut()
.zip(total_address_count.by_addresstype.iter())
.zip(total_address_count.by_address_type.iter())
{
new.compute(max_from, exit, |height_vec| {
Ok(height_vec.compute_change(max_from, &total.height, 1, exit)?)
@@ -13,7 +13,7 @@ use super::AddressCountsVecs;
pub struct TotalAddressCountVecs<M: StorageMode = Rw> {
pub all: PerBlock<StoredU64, M>,
#[traversable(flatten)]
pub by_addresstype: ByAddressType<PerBlock<StoredU64, M>>,
pub by_address_type: ByAddressType<PerBlock<StoredU64, M>>,
}
impl TotalAddressCountVecs {
@@ -24,7 +24,7 @@ impl TotalAddressCountVecs {
) -> Result<Self> {
let all = PerBlock::forced_import(db, "total_address_count", version, indexes)?;
let by_addresstype: ByAddressType<PerBlock<StoredU64>> =
let by_address_type: ByAddressType<PerBlock<StoredU64>> =
ByAddressType::new_with_name(|name| {
PerBlock::forced_import(
db,
@@ -36,7 +36,7 @@ impl TotalAddressCountVecs {
Ok(Self {
all,
by_addresstype,
by_address_type,
})
}
@@ -55,11 +55,11 @@ impl TotalAddressCountVecs {
exit,
)?;
for ((_, total), ((_, addr), (_, empty))) in self.by_addresstype.iter_mut().zip(
for ((_, total), ((_, addr), (_, empty))) in self.by_address_type.iter_mut().zip(
address_count
.by_addresstype
.by_address_type
.iter()
.zip(empty_address_count.by_addresstype.iter()),
.zip(empty_address_count.by_address_type.iter()),
) {
total
.height
@@ -59,14 +59,14 @@ impl<T> AddressTypeToTypeIndexMap<T> {
Self::merge_single(&mut self.p2wsh, &mut other.p2wsh);
}
/// Insert a value for a specific address type and typeindex.
/// Insert a value for a specific address type and type_index.
pub(crate) fn insert_for_type(
&mut self,
address_type: OutputType,
typeindex: TypeIndex,
type_index: TypeIndex,
value: T,
) {
self.get_mut(address_type).unwrap().insert(typeindex, value);
self.get_mut(address_type).unwrap().insert(type_index, value);
}
/// Consume and iterate over entries by address type.
@@ -96,8 +96,8 @@ where
pub(crate) fn merge_vec(mut self, other: Self) -> Self {
for (address_type, other_map) in other.0.into_iter() {
let self_map = self.0.get_mut_unwrap(address_type);
for (typeindex, mut other_vec) in other_map {
match self_map.entry(typeindex) {
for (type_index, mut other_vec) in other_map {
match self_map.entry(type_index) {
Entry::Occupied(mut entry) => {
let self_vec = entry.get_mut();
if other_vec.len() > self_vec.len() {
+15 -15
View File
@@ -37,14 +37,14 @@ impl AddressCache {
/// Check if address is in cache (either funded or empty).
#[inline]
pub(crate) fn contains(&self, address_type: OutputType, typeindex: TypeIndex) -> bool {
pub(crate) fn contains(&self, address_type: OutputType, type_index: TypeIndex) -> bool {
self.funded
.get(address_type)
.is_some_and(|m| m.contains_key(&typeindex))
.is_some_and(|m| m.contains_key(&type_index))
|| self
.empty
.get(address_type)
.is_some_and(|m| m.contains_key(&typeindex))
.is_some_and(|m| m.contains_key(&type_index))
}
/// Merge address data into funded cache.
@@ -68,9 +68,9 @@ impl AddressCache {
/// Update transaction counts for addresses.
pub(crate) fn update_tx_counts(
&mut self,
txindex_vecs: AddressTypeToTypeIndexMap<SmallVec<[TxIndex; 4]>>,
tx_index_vecs: AddressTypeToTypeIndexMap<SmallVec<[TxIndex; 4]>>,
) {
update_tx_counts(&mut self.funded, &mut self.empty, txindex_vecs);
update_tx_counts(&mut self.funded, &mut self.empty, tx_index_vecs);
}
/// Take the cache contents for flushing, leaving empty caches.
@@ -93,33 +93,33 @@ impl AddressCache {
#[allow(clippy::too_many_arguments)]
pub(crate) fn load_uncached_address_data(
address_type: OutputType,
typeindex: TypeIndex,
first_addressindexes: &ByAddressType<TypeIndex>,
type_index: TypeIndex,
first_address_indexes: &ByAddressType<TypeIndex>,
cache: &AddressCache,
vr: &VecsReaders,
any_address_indexes: &AnyAddressIndexesVecs,
addresses_data: &AddressesDataVecs,
) -> Result<Option<WithAddressDataSource<FundedAddressData>>> {
// Check if this is a new address (typeindex >= first for this height)
let first = *first_addressindexes.get(address_type).unwrap();
if first <= typeindex {
// Check if this is a new address (type_index >= first for this height)
let first = *first_address_indexes.get(address_type).unwrap();
if first <= type_index {
return Ok(Some(WithAddressDataSource::New(
FundedAddressData::default(),
)));
}
// Skip if already in cache
if cache.contains(address_type, typeindex) {
if cache.contains(address_type, type_index) {
return Ok(None);
}
// Read from storage
let reader = vr.address_reader(address_type);
let anyaddressindex = any_address_indexes.get(address_type, typeindex, reader)?;
let any_address_index = any_address_indexes.get(address_type, type_index, reader)?;
Ok(Some(match anyaddressindex.to_enum() {
Ok(Some(match any_address_index.to_enum() {
AnyAddressDataIndexEnum::Funded(funded_index) => {
let reader = &vr.anyaddressindex_to_anyaddressdata.funded;
let reader = &vr.any_address_index_to_any_address_data.funded;
let funded_data = addresses_data
.funded
.get_any_or_read_at(funded_index.into(), reader)?
@@ -127,7 +127,7 @@ pub(crate) fn load_uncached_address_data(
WithAddressDataSource::FromFunded(funded_index, funded_data)
}
AnyAddressDataIndexEnum::Empty(empty_index) => {
let reader = &vr.anyaddressindex_to_anyaddressdata.empty;
let reader = &vr.any_address_index_to_any_address_data.empty;
let empty_data = addresses_data
.empty
.get_any_or_read_at(empty_index.into(), reader)?
@@ -26,17 +26,17 @@ pub(crate) fn process_funded_addresses(
let mut pushes: Vec<(OutputType, TypeIndex, FundedAddressData)> = Vec::with_capacity(total);
for (address_type, items) in funded_updates.into_iter() {
for (typeindex, source) in items {
for (type_index, source) in items {
match source {
WithAddressDataSource::New(data) => {
pushes.push((address_type, typeindex, data));
pushes.push((address_type, type_index, data));
}
WithAddressDataSource::FromFunded(index, data) => {
updates.push((index, data));
}
WithAddressDataSource::FromEmpty(empty_index, data) => {
deletes.push(empty_index);
pushes.push((address_type, typeindex, data));
pushes.push((address_type, type_index, data));
}
}
}
@@ -57,21 +57,21 @@ pub(crate) fn process_funded_addresses(
let holes_count = addresses_data.funded.holes().len();
let mut pushes_iter = pushes.into_iter();
for (address_type, typeindex, data) in pushes_iter.by_ref().take(holes_count) {
for (address_type, type_index, data) in pushes_iter.by_ref().take(holes_count) {
let index = addresses_data.funded.fill_first_hole_or_push(data)?;
result
.get_mut(address_type)
.unwrap()
.insert(typeindex, AnyAddressIndex::from(index));
.insert(type_index, AnyAddressIndex::from(index));
}
// Pure pushes - no holes remain
addresses_data.funded.reserve_pushed(pushes_iter.len());
let mut next_index = addresses_data.funded.len();
for (address_type, typeindex, data) in pushes_iter {
for (address_type, type_index, data) in pushes_iter {
addresses_data.funded.push(data);
result.get_mut(address_type).unwrap().insert(
typeindex,
type_index,
AnyAddressIndex::from(FundedAddressIndex::from(next_index)),
);
next_index += 1;
@@ -97,17 +97,17 @@ pub(crate) fn process_empty_addresses(
let mut pushes: Vec<(OutputType, TypeIndex, EmptyAddressData)> = Vec::with_capacity(total);
for (address_type, items) in empty_updates.into_iter() {
for (typeindex, source) in items {
for (type_index, source) in items {
match source {
WithAddressDataSource::New(data) => {
pushes.push((address_type, typeindex, data));
pushes.push((address_type, type_index, data));
}
WithAddressDataSource::FromEmpty(index, data) => {
updates.push((index, data));
}
WithAddressDataSource::FromFunded(funded_index, data) => {
deletes.push(funded_index);
pushes.push((address_type, typeindex, data));
pushes.push((address_type, type_index, data));
}
}
}
@@ -128,21 +128,21 @@ pub(crate) fn process_empty_addresses(
let holes_count = addresses_data.empty.holes().len();
let mut pushes_iter = pushes.into_iter();
for (address_type, typeindex, data) in pushes_iter.by_ref().take(holes_count) {
for (address_type, type_index, data) in pushes_iter.by_ref().take(holes_count) {
let index = addresses_data.empty.fill_first_hole_or_push(data)?;
result
.get_mut(address_type)
.unwrap()
.insert(typeindex, AnyAddressIndex::from(index));
.insert(type_index, AnyAddressIndex::from(index));
}
// Pure pushes - no holes remain
addresses_data.empty.reserve_pushed(pushes_iter.len());
let mut next_index = addresses_data.empty.len();
for (address_type, typeindex, data) in pushes_iter {
for (address_type, type_index, data) in pushes_iter {
addresses_data.empty.push(data);
result.get_mut(address_type).unwrap().insert(
typeindex,
type_index,
AnyAddressIndex::from(EmptyAddressIndex::from(next_index)),
);
next_index += 1;
@@ -16,35 +16,35 @@ use super::with_source::WithAddressDataSource;
pub(crate) fn update_tx_counts(
funded_cache: &mut AddressTypeToTypeIndexMap<WithAddressDataSource<FundedAddressData>>,
empty_cache: &mut AddressTypeToTypeIndexMap<WithAddressDataSource<EmptyAddressData>>,
mut txindex_vecs: AddressTypeToTypeIndexMap<SmallVec<[TxIndex; 4]>>,
mut tx_index_vecs: AddressTypeToTypeIndexMap<SmallVec<[TxIndex; 4]>>,
) {
// First, deduplicate txindex_vecs for addresses that appear multiple times in a block
for (_, map) in txindex_vecs.iter_mut() {
for (_, txindex_vec) in map.iter_mut() {
if txindex_vec.len() > 1 {
txindex_vec.sort_unstable();
txindex_vec.dedup();
// First, deduplicate tx_index_vecs for addresses that appear multiple times in a block
for (_, map) in tx_index_vecs.iter_mut() {
for (_, tx_index_vec) in map.iter_mut() {
if tx_index_vec.len() > 1 {
tx_index_vec.sort_unstable();
tx_index_vec.dedup();
}
}
}
// Update tx_count on address data
for (address_type, typeindex, txindex_vec) in txindex_vecs
for (address_type, type_index, tx_index_vec) in tx_index_vecs
.into_iter()
.flat_map(|(t, m)| m.into_iter().map(move |(i, v)| (t, i, v)))
{
let tx_count = txindex_vec.len() as u32;
let tx_count = tx_index_vec.len() as u32;
if let Some(addr_data) = funded_cache
.get_mut(address_type)
.unwrap()
.get_mut(&typeindex)
.get_mut(&type_index)
{
addr_data.tx_count += tx_count;
} else if let Some(addr_data) = empty_cache
.get_mut(address_type)
.unwrap()
.get_mut(&typeindex)
.get_mut(&type_index)
{
addr_data.tx_count += tx_count;
}
@@ -22,20 +22,20 @@ use super::super::{
pub struct InputsResult {
/// Map from UTXO creation height -> aggregated sent supply.
pub height_to_sent: FxHashMap<Height, Transacted>,
/// Per-height, per-address-type sent data: (typeindex, value) for each address.
/// Per-height, per-address-type sent data: (type_index, value) for each address.
pub sent_data: HeightToAddressTypeToVec<(TypeIndex, Sats)>,
/// Address data looked up during processing, keyed by (address_type, typeindex).
/// Address data looked up during processing, keyed by (address_type, type_index).
pub address_data: AddressTypeToTypeIndexMap<WithAddressDataSource<FundedAddressData>>,
/// Transaction indexes per address for tx_count tracking.
pub txindex_vecs: AddressTypeToTypeIndexMap<SmallVec<[TxIndex; 4]>>,
pub tx_index_vecs: AddressTypeToTypeIndexMap<SmallVec<[TxIndex; 4]>>,
}
/// Process inputs (spent UTXOs) for a block.
///
/// For each input:
/// 1. Use pre-collected outpoint (from reusable iterator, avoids PcoVec re-decompression)
/// 2. Resolve outpoint to txoutindex
/// 3. Get the creation height from txoutindex_to_height map
/// 2. Resolve outpoint to txout_index
/// 3. Get the creation height from txout_index_to_height map
/// 4. Read value and type from the referenced output (random access via mmap)
/// 5. Look up address data if input references an address type
/// 6. Accumulate into height_to_sent map
@@ -46,35 +46,35 @@ pub struct InputsResult {
#[allow(clippy::too_many_arguments)]
pub(crate) fn process_inputs(
input_count: usize,
txinindex_to_txindex: &[TxIndex],
txinindex_to_value: &[Sats],
txinindex_to_outputtype: &[OutputType],
txinindex_to_typeindex: &[TypeIndex],
txinindex_to_prev_height: &[Height],
first_addressindexes: &ByAddressType<TypeIndex>,
txin_index_to_tx_index: &[TxIndex],
txin_index_to_value: &[Sats],
txin_index_to_output_type: &[OutputType],
txin_index_to_type_index: &[TypeIndex],
txin_index_to_prev_height: &[Height],
first_address_indexes: &ByAddressType<TypeIndex>,
cache: &AddressCache,
vr: &VecsReaders,
any_address_indexes: &AnyAddressIndexesVecs,
addresses_data: &AddressesDataVecs,
) -> Result<InputsResult> {
let map_fn = |local_idx: usize| -> Result<_> {
let txindex = txinindex_to_txindex[local_idx];
let tx_index = txin_index_to_tx_index[local_idx];
let prev_height = txinindex_to_prev_height[local_idx];
let value = txinindex_to_value[local_idx];
let input_type = txinindex_to_outputtype[local_idx];
let prev_height = txin_index_to_prev_height[local_idx];
let value = txin_index_to_value[local_idx];
let input_type = txin_index_to_output_type[local_idx];
if input_type.is_not_address() {
return Ok((prev_height, value, input_type, None));
}
let typeindex = txinindex_to_typeindex[local_idx];
let type_index = txin_index_to_type_index[local_idx];
// Look up address data
let addr_data_opt = load_uncached_address_data(
input_type,
typeindex,
first_addressindexes,
type_index,
first_address_indexes,
cache,
vr,
any_address_indexes,
@@ -85,7 +85,7 @@ pub(crate) fn process_inputs(
prev_height,
value,
input_type,
Some((typeindex, txindex, value, addr_data_opt)),
Some((type_index, tx_index, value, addr_data_opt)),
))
};
@@ -113,7 +113,7 @@ pub(crate) fn process_inputs(
AddressTypeToTypeIndexMap::<WithAddressDataSource<FundedAddressData>>::with_capacity(
estimated_per_type,
);
let mut txindex_vecs =
let mut tx_index_vecs =
AddressTypeToTypeIndexMap::<SmallVec<[TxIndex; 4]>>::with_capacity(estimated_per_type);
for (prev_height, value, output_type, addr_info) in items {
@@ -122,24 +122,24 @@ pub(crate) fn process_inputs(
.or_default()
.iterate(value, output_type);
if let Some((typeindex, txindex, value, addr_data_opt)) = addr_info {
if let Some((type_index, tx_index, value, addr_data_opt)) = addr_info {
sent_data
.entry(prev_height)
.or_default()
.get_mut(output_type)
.unwrap()
.push((typeindex, value));
.push((type_index, value));
if let Some(addr_data) = addr_data_opt {
address_data.insert_for_type(output_type, typeindex, addr_data);
address_data.insert_for_type(output_type, type_index, addr_data);
}
txindex_vecs
tx_index_vecs
.get_mut(output_type)
.unwrap()
.entry(typeindex)
.entry(type_index)
.or_default()
.push(txindex);
.push(tx_index);
}
}
@@ -147,6 +147,6 @@ pub(crate) fn process_inputs(
height_to_sent,
sent_data,
address_data,
txindex_vecs,
tx_index_vecs,
})
}
@@ -21,50 +21,50 @@ use super::super::{
pub struct OutputsResult {
/// Aggregated supply transacted in this block.
pub transacted: Transacted,
/// Per-address-type received data: (typeindex, value) for each address.
/// Per-address-type received data: (type_index, value) for each address.
pub received_data: AddressTypeToVec<(TypeIndex, Sats)>,
/// Address data looked up during processing, keyed by (address_type, typeindex).
/// Address data looked up during processing, keyed by (address_type, type_index).
pub address_data: AddressTypeToTypeIndexMap<WithAddressDataSource<FundedAddressData>>,
/// Transaction indexes per address for tx_count tracking.
pub txindex_vecs: AddressTypeToTypeIndexMap<SmallVec<[TxIndex; 4]>>,
pub tx_index_vecs: AddressTypeToTypeIndexMap<SmallVec<[TxIndex; 4]>>,
}
/// Process outputs (new UTXOs) for a block.
///
/// For each output:
/// 1. Read pre-collected value, output type, and typeindex
/// 1. Read pre-collected value, output type, and type_index
/// 2. Accumulate into Transacted by type and amount
/// 3. Look up address data if output is an address type
/// 4. Track address-specific data for address cohort processing
#[allow(clippy::too_many_arguments)]
pub(crate) fn process_outputs(
txoutindex_to_txindex: &[TxIndex],
txoutdata_vec: &[TxOutData],
first_addressindexes: &ByAddressType<TypeIndex>,
txout_index_to_tx_index: &[TxIndex],
txout_data_vec: &[TxOutData],
first_address_indexes: &ByAddressType<TypeIndex>,
cache: &AddressCache,
vr: &VecsReaders,
any_address_indexes: &AnyAddressIndexesVecs,
addresses_data: &AddressesDataVecs,
) -> Result<OutputsResult> {
let output_count = txoutdata_vec.len();
let output_count = txout_data_vec.len();
// Phase 1: Address lookups (mmap reads) — parallel for large blocks, sequential for small
let map_fn = |local_idx: usize| -> Result<_> {
let txoutdata = &txoutdata_vec[local_idx];
let value = txoutdata.value;
let output_type = txoutdata.outputtype;
let txout_data = &txout_data_vec[local_idx];
let value = txout_data.value;
let output_type = txout_data.output_type;
if output_type.is_not_address() {
return Ok((value, output_type, None));
}
let typeindex = txoutdata.typeindex;
let txindex = txoutindex_to_txindex[local_idx];
let type_index = txout_data.type_index;
let tx_index = txout_index_to_tx_index[local_idx];
let addr_data_opt = load_uncached_address_data(
output_type,
typeindex,
first_addressindexes,
type_index,
first_address_indexes,
cache,
vr,
any_address_indexes,
@@ -74,7 +74,7 @@ pub(crate) fn process_outputs(
Ok((
value,
output_type,
Some((typeindex, txindex, value, addr_data_opt)),
Some((type_index, tx_index, value, addr_data_opt)),
))
};
@@ -97,28 +97,28 @@ pub(crate) fn process_outputs(
AddressTypeToTypeIndexMap::<WithAddressDataSource<FundedAddressData>>::with_capacity(
estimated_per_type,
);
let mut txindex_vecs =
let mut tx_index_vecs =
AddressTypeToTypeIndexMap::<SmallVec<[TxIndex; 4]>>::with_capacity(estimated_per_type);
for (value, output_type, addr_info) in items {
transacted.iterate(value, output_type);
if let Some((typeindex, txindex, value, addr_data_opt)) = addr_info {
if let Some((type_index, tx_index, value, addr_data_opt)) = addr_info {
received_data
.get_mut(output_type)
.unwrap()
.push((typeindex, value));
.push((type_index, value));
if let Some(addr_data) = addr_data_opt {
address_data.insert_for_type(output_type, typeindex, addr_data);
address_data.insert_for_type(output_type, type_index, addr_data);
}
txindex_vecs
tx_index_vecs
.get_mut(output_type)
.unwrap()
.entry(typeindex)
.entry(type_index)
.or_default()
.push(txindex);
.push(tx_index);
}
}
@@ -126,6 +126,6 @@ pub(crate) fn process_outputs(
transacted,
received_data,
address_data,
txindex_vecs,
tx_index_vecs,
})
}
@@ -45,7 +45,7 @@ pub(crate) fn process_blocks(
starting_height: Height,
last_height: Height,
chain_state: &mut Vec<BlockState>,
txindex_to_height: &mut RangeMap<TxIndex, Height>,
tx_index_to_height: &mut RangeMap<TxIndex, Height>,
cached_prices: &[Cents],
cached_timestamps: &[Timestamp],
cached_price_range_max: &PriceRangeMax,
@@ -63,14 +63,14 @@ pub(crate) fn process_blocks(
return Ok(());
}
let height_to_first_txindex = &indexer.vecs.transactions.first_txindex;
let height_to_first_txoutindex = &indexer.vecs.outputs.first_txoutindex;
let height_to_first_txinindex = &indexer.vecs.inputs.first_txinindex;
let height_to_first_tx_index = &indexer.vecs.transactions.first_tx_index;
let height_to_first_txout_index = &indexer.vecs.outputs.first_txout_index;
let height_to_first_txin_index = &indexer.vecs.inputs.first_txin_index;
let height_to_tx_count = &transactions.count.total.base.height;
let height_to_output_count = &outputs.count.total.full.sum;
let height_to_input_count = &inputs.count.full.sum;
let txindex_to_output_count = &indexes.txindex.output_count;
let txindex_to_input_count = &indexes.txindex.input_count;
let tx_index_to_output_count = &indexes.tx_index.output_count;
let tx_index_to_input_count = &indexes.tx_index.input_count;
let height_to_price_vec = cached_prices;
let height_to_timestamp_vec = cached_timestamps;
@@ -78,12 +78,12 @@ pub(crate) fn process_blocks(
let start_usize = starting_height.to_usize();
let end_usize = last_height.to_usize() + 1;
let height_to_first_txindex_vec: Vec<TxIndex> =
height_to_first_txindex.collect_range_at(start_usize, end_usize);
let height_to_first_txoutindex_vec: Vec<_> =
height_to_first_txoutindex.collect_range_at(start_usize, end_usize);
let height_to_first_txinindex_vec: Vec<_> =
height_to_first_txinindex.collect_range_at(start_usize, end_usize);
let height_to_first_tx_index_vec: Vec<TxIndex> =
height_to_first_tx_index.collect_range_at(start_usize, end_usize);
let height_to_first_txout_index_vec: Vec<_> =
height_to_first_txout_index.collect_range_at(start_usize, end_usize);
let height_to_first_txin_index_vec: Vec<_> =
height_to_first_txin_index.collect_range_at(start_usize, end_usize);
let height_to_tx_count_vec: Vec<_> =
height_to_tx_count.collect_range_at(start_usize, end_usize);
let height_to_output_count_vec: Vec<_> =
@@ -106,39 +106,39 @@ pub(crate) fn process_blocks(
let mut vr = VecsReaders::new(&vecs.any_address_indexes, &vecs.addresses_data);
debug!("VecsReaders created");
// Extend txindex_to_height RangeMap with new entries (incremental, O(new_blocks))
let target_len = indexer.vecs.transactions.first_txindex.len();
let current_len = txindex_to_height.len();
// Extend tx_index_to_height RangeMap with new entries (incremental, O(new_blocks))
let target_len = indexer.vecs.transactions.first_tx_index.len();
let current_len = tx_index_to_height.len();
if current_len < target_len {
debug!(
"extending txindex_to_height RangeMap from {} to {}",
"extending tx_index_to_height RangeMap from {} to {}",
current_len, target_len
);
let new_entries: Vec<TxIndex> = indexer
.vecs
.transactions
.first_txindex
.first_tx_index
.collect_range_at(current_len, target_len);
for first_txindex in new_entries {
txindex_to_height.push(first_txindex);
for first_tx_index in new_entries {
tx_index_to_height.push(first_tx_index);
}
} else if current_len > target_len {
debug!(
"truncating txindex_to_height RangeMap from {} to {}",
"truncating tx_index_to_height RangeMap from {} to {}",
current_len, target_len
);
txindex_to_height.truncate(target_len);
tx_index_to_height.truncate(target_len);
}
debug!(
"txindex_to_height RangeMap ready ({} entries)",
txindex_to_height.len()
"tx_index_to_height RangeMap ready ({} entries)",
tx_index_to_height.len()
);
// Create reusable iterators and buffers for per-block reads
let mut txout_iters = TxOutReaders::new(indexer);
let mut txin_iters = TxInReaders::new(indexer, inputs, txindex_to_height);
let mut txout_to_txindex_buf = IndexToTxIndexBuf::new();
let mut txin_to_txindex_buf = IndexToTxIndexBuf::new();
let mut txin_iters = TxInReaders::new(indexer, inputs, tx_index_to_height);
let mut txout_to_tx_index_buf = IndexToTxIndexBuf::new();
let mut txin_to_tx_index_buf = IndexToTxIndexBuf::new();
// Pre-collect first address indexes per type for the block range
let first_p2a_vec = indexer
@@ -186,9 +186,9 @@ pub(crate) fn process_blocks(
debug!("recovering address_counts from height {}", starting_height);
let (mut address_counts, mut empty_address_counts) = if starting_height > Height::ZERO {
let address_counts =
AddressTypeToAddressCount::from((&vecs.addresses.funded.by_addresstype, starting_height));
AddressTypeToAddressCount::from((&vecs.addresses.funded.by_address_type, starting_height));
let empty_address_counts = AddressTypeToAddressCount::from((
&vecs.addresses.empty.by_addresstype,
&vecs.addresses.empty.by_address_type,
starting_height,
));
(address_counts, empty_address_counts)
@@ -225,11 +225,11 @@ pub(crate) fn process_blocks(
// Get block metadata from pre-collected vecs
let offset = height.to_usize() - start_usize;
let first_txindex = height_to_first_txindex_vec[offset];
let first_tx_index = height_to_first_tx_index_vec[offset];
let tx_count = u64::from(height_to_tx_count_vec[offset]);
let first_txoutindex = height_to_first_txoutindex_vec[offset].to_usize();
let first_txout_index = height_to_first_txout_index_vec[offset].to_usize();
let output_count = u64::from(height_to_output_count_vec[offset]) as usize;
let first_txinindex = height_to_first_txinindex_vec[offset].to_usize();
let first_txin_index = height_to_first_txin_index_vec[offset].to_usize();
let input_count = u64::from(height_to_input_count_vec[offset]) as usize;
let timestamp = height_to_timestamp_collected[offset];
let block_price = height_to_price_collected[offset];
@@ -239,7 +239,7 @@ pub(crate) fn process_blocks(
debug_assert_eq!(ctx.price_at(height), block_price);
// Get first address indexes for this height from pre-collected vecs
let first_addressindexes = ByAddressType {
let first_address_indexes = ByAddressType {
p2a: TypeIndex::from(first_p2a_vec[offset].to_usize()),
p2pk33: TypeIndex::from(first_p2pk33_vec[offset].to_usize()),
p2pk65: TypeIndex::from(first_p2pk65_vec[offset].to_usize()),
@@ -254,7 +254,7 @@ pub(crate) fn process_blocks(
activity_counts.reset();
// Process outputs, inputs, and tick-tock in parallel via rayon::join.
// Collection (build txindex mappings + bulk mmap reads) is merged into the
// Collection (build tx_index mappings + bulk mmap reads) is merged into the
// processing closures so outputs and inputs collection overlap each other
// and tick-tock, instead of running sequentially before the join.
let (matured, oi_result) = rayon::join(
@@ -262,14 +262,14 @@ pub(crate) fn process_blocks(
|| -> Result<_> {
let (outputs_result, inputs_result) = rayon::join(
|| {
let txoutindex_to_txindex = txout_to_txindex_buf
.build(first_txindex, tx_count, txindex_to_output_count);
let txoutdata_vec =
txout_iters.collect_block_outputs(first_txoutindex, output_count);
let txout_index_to_tx_index = txout_to_tx_index_buf
.build(first_tx_index, tx_count, tx_index_to_output_count);
let txout_data_vec =
txout_iters.collect_block_outputs(first_txout_index, output_count);
process_outputs(
txoutindex_to_txindex,
txoutdata_vec,
&first_addressindexes,
txout_index_to_tx_index,
txout_data_vec,
&first_address_indexes,
&cache,
&vr,
&vecs.any_address_indexes,
@@ -278,22 +278,22 @@ pub(crate) fn process_blocks(
},
|| -> Result<_> {
if input_count > 1 {
let txinindex_to_txindex = txin_to_txindex_buf
.build(first_txindex, tx_count, txindex_to_input_count);
let (input_values, input_prev_heights, input_outputtypes, input_typeindexes) =
let txin_index_to_tx_index = txin_to_tx_index_buf
.build(first_tx_index, tx_count, tx_index_to_input_count);
let (input_values, input_prev_heights, input_output_types, input_type_indexes) =
txin_iters.collect_block_inputs(
first_txinindex + 1,
first_txin_index + 1,
input_count - 1,
height,
);
process_inputs(
input_count - 1,
&txinindex_to_txindex[1..],
&txin_index_to_tx_index[1..],
input_values,
input_outputtypes,
input_typeindexes,
input_output_types,
input_type_indexes,
input_prev_heights,
&first_addressindexes,
&first_address_indexes,
&cache,
&vr,
&vecs.any_address_indexes,
@@ -304,7 +304,7 @@ pub(crate) fn process_blocks(
height_to_sent: Default::default(),
sent_data: Default::default(),
address_data: Default::default(),
txindex_vecs: Default::default(),
tx_index_vecs: Default::default(),
})
}
},
@@ -318,11 +318,11 @@ pub(crate) fn process_blocks(
cache.merge_funded(outputs_result.address_data);
cache.merge_funded(inputs_result.address_data);
// Combine txindex_vecs from outputs and inputs, then update tx_count
let combined_txindex_vecs = outputs_result
.txindex_vecs
.merge_vec(inputs_result.txindex_vecs);
cache.update_tx_counts(combined_txindex_vecs);
// Combine tx_index_vecs from outputs and inputs, then update tx_count
let combined_tx_index_vecs = outputs_result
.tx_index_vecs
.merge_vec(inputs_result.tx_index_vecs);
cache.update_tx_counts(combined_tx_index_vecs);
let mut transacted = outputs_result.transacted;
let mut height_to_sent = inputs_result.height_to_sent;
@@ -15,17 +15,17 @@ use crate::{
#[derive(Debug, Clone, Copy)]
pub struct TxOutData {
pub value: Sats,
pub outputtype: OutputType,
pub typeindex: TypeIndex,
pub output_type: OutputType,
pub type_index: TypeIndex,
}
/// Readers for txout vectors. Reuses internal buffers across blocks.
pub struct TxOutReaders<'a> {
indexer: &'a Indexer,
values_buf: Vec<Sats>,
outputtypes_buf: Vec<OutputType>,
typeindexes_buf: Vec<TypeIndex>,
txoutdata_buf: Vec<TxOutData>,
output_types_buf: Vec<OutputType>,
type_indexes_buf: Vec<TypeIndex>,
txout_data_buf: Vec<TxOutData>,
}
impl<'a> TxOutReaders<'a> {
@@ -33,48 +33,48 @@ impl<'a> TxOutReaders<'a> {
Self {
indexer,
values_buf: Vec::new(),
outputtypes_buf: Vec::new(),
typeindexes_buf: Vec::new(),
txoutdata_buf: Vec::new(),
output_types_buf: Vec::new(),
type_indexes_buf: Vec::new(),
txout_data_buf: Vec::new(),
}
}
/// Collect output data for a block range using bulk reads with buffer reuse.
pub(crate) fn collect_block_outputs(
&mut self,
first_txoutindex: usize,
first_txout_index: usize,
output_count: usize,
) -> &[TxOutData] {
let end = first_txoutindex + output_count;
let end = first_txout_index + output_count;
self.indexer.vecs.outputs.value.collect_range_into_at(
first_txoutindex,
first_txout_index,
end,
&mut self.values_buf,
);
self.indexer.vecs.outputs.outputtype.collect_range_into_at(
first_txoutindex,
self.indexer.vecs.outputs.output_type.collect_range_into_at(
first_txout_index,
end,
&mut self.outputtypes_buf,
&mut self.output_types_buf,
);
self.indexer.vecs.outputs.typeindex.collect_range_into_at(
first_txoutindex,
self.indexer.vecs.outputs.type_index.collect_range_into_at(
first_txout_index,
end,
&mut self.typeindexes_buf,
&mut self.type_indexes_buf,
);
self.txoutdata_buf.clear();
self.txoutdata_buf.extend(
self.txout_data_buf.clear();
self.txout_data_buf.extend(
self.values_buf
.iter()
.zip(&self.outputtypes_buf)
.zip(&self.typeindexes_buf)
.map(|((&value, &outputtype), &typeindex)| TxOutData {
.zip(&self.output_types_buf)
.zip(&self.type_indexes_buf)
.map(|((&value, &output_type), &type_index)| TxOutData {
value,
outputtype,
typeindex,
output_type,
type_index,
}),
);
&self.txoutdata_buf
&self.txout_data_buf
}
}
@@ -82,59 +82,59 @@ impl<'a> TxOutReaders<'a> {
pub struct TxInReaders<'a> {
indexer: &'a Indexer,
txins: &'a inputs::Vecs,
txindex_to_height: &'a mut RangeMap<TxIndex, Height>,
tx_index_to_height: &'a mut RangeMap<TxIndex, Height>,
outpoints_buf: Vec<OutPoint>,
values_buf: Vec<Sats>,
prev_heights_buf: Vec<Height>,
outputtypes_buf: Vec<OutputType>,
typeindexes_buf: Vec<TypeIndex>,
output_types_buf: Vec<OutputType>,
type_indexes_buf: Vec<TypeIndex>,
}
impl<'a> TxInReaders<'a> {
pub(crate) fn new(
indexer: &'a Indexer,
txins: &'a inputs::Vecs,
txindex_to_height: &'a mut RangeMap<TxIndex, Height>,
tx_index_to_height: &'a mut RangeMap<TxIndex, Height>,
) -> Self {
Self {
indexer,
txins,
txindex_to_height,
tx_index_to_height,
outpoints_buf: Vec::new(),
values_buf: Vec::new(),
prev_heights_buf: Vec::new(),
outputtypes_buf: Vec::new(),
typeindexes_buf: Vec::new(),
output_types_buf: Vec::new(),
type_indexes_buf: Vec::new(),
}
}
/// Collect input data for a block range using bulk reads with buffer reuse.
pub(crate) fn collect_block_inputs(
&mut self,
first_txinindex: usize,
first_txin_index: usize,
input_count: usize,
current_height: Height,
) -> (&[Sats], &[Height], &[OutputType], &[TypeIndex]) {
let end = first_txinindex + input_count;
let end = first_txin_index + input_count;
self.txins.spent.value.collect_range_into_at(
first_txinindex,
first_txin_index,
end,
&mut self.values_buf,
);
self.indexer.vecs.inputs.outpoint.collect_range_into_at(
first_txinindex,
first_txin_index,
end,
&mut self.outpoints_buf,
);
self.indexer.vecs.inputs.outputtype.collect_range_into_at(
first_txinindex,
self.indexer.vecs.inputs.output_type.collect_range_into_at(
first_txin_index,
end,
&mut self.outputtypes_buf,
&mut self.output_types_buf,
);
self.indexer.vecs.inputs.typeindex.collect_range_into_at(
first_txinindex,
self.indexer.vecs.inputs.type_index.collect_range_into_at(
first_txin_index,
end,
&mut self.typeindexes_buf,
&mut self.type_indexes_buf,
);
self.prev_heights_buf.clear();
@@ -143,8 +143,8 @@ impl<'a> TxInReaders<'a> {
if outpoint.is_coinbase() {
current_height
} else {
self.txindex_to_height
.get(outpoint.txindex())
self.tx_index_to_height
.get(outpoint.tx_index())
.unwrap_or(current_height)
}
}),
@@ -153,16 +153,16 @@ impl<'a> TxInReaders<'a> {
(
&self.values_buf,
&self.prev_heights_buf,
&self.outputtypes_buf,
&self.typeindexes_buf,
&self.output_types_buf,
&self.type_indexes_buf,
)
}
}
/// Cached readers for stateful vectors.
pub struct VecsReaders {
pub addresstypeindex_to_anyaddressindex: ByAddressType<Reader>,
pub anyaddressindex_to_anyaddressdata: ByAnyAddress<Reader>,
pub address_type_index_to_any_address_index: ByAddressType<Reader>,
pub any_address_index_to_any_address_data: ByAnyAddress<Reader>,
}
impl VecsReaders {
@@ -171,7 +171,7 @@ impl VecsReaders {
addresses_data: &AddressesDataVecs,
) -> Self {
Self {
addresstypeindex_to_anyaddressindex: ByAddressType {
address_type_index_to_any_address_index: ByAddressType {
p2a: any_address_indexes.p2a.create_reader(),
p2pk33: any_address_indexes.p2pk33.create_reader(),
p2pk65: any_address_indexes.p2pk65.create_reader(),
@@ -181,7 +181,7 @@ impl VecsReaders {
p2wpkh: any_address_indexes.p2wpkh.create_reader(),
p2wsh: any_address_indexes.p2wsh.create_reader(),
},
anyaddressindex_to_anyaddressdata: ByAnyAddress {
any_address_index_to_any_address_data: ByAnyAddress {
funded: addresses_data.funded.create_reader(),
empty: addresses_data.empty.create_reader(),
},
@@ -190,13 +190,13 @@ impl VecsReaders {
/// Get reader for specific address type.
pub(crate) fn address_reader(&self, address_type: OutputType) -> &Reader {
self.addresstypeindex_to_anyaddressindex
self.address_type_index_to_any_address_index
.get(address_type)
.unwrap()
}
}
/// Reusable buffers for per-block txindex mapping construction.
/// Reusable buffers for per-block tx_index mapping construction.
pub(crate) struct IndexToTxIndexBuf {
counts: Vec<StoredU64>,
result: Vec<TxIndex>,
@@ -210,15 +210,15 @@ impl IndexToTxIndexBuf {
}
}
/// Build index -> txindex mapping for a block, reusing internal buffers.
/// Build index -> tx_index mapping for a block, reusing internal buffers.
pub(crate) fn build(
&mut self,
block_first_txindex: TxIndex,
block_first_tx_index: TxIndex,
block_tx_count: u64,
txindex_to_count: &impl ReadableVec<TxIndex, StoredU64>,
tx_index_to_count: &impl ReadableVec<TxIndex, StoredU64>,
) -> &[TxIndex] {
let first = block_first_txindex.to_usize();
txindex_to_count.collect_range_into_at(
let first = block_first_tx_index.to_usize();
tx_index_to_count.collect_range_into_at(
first,
first + block_tx_count as usize,
&mut self.counts,
@@ -229,9 +229,9 @@ impl IndexToTxIndexBuf {
self.result.reserve(total as usize);
for (offset, count) in self.counts.iter().enumerate() {
let txindex = TxIndex::from(first + offset);
let tx_index = TxIndex::from(first + offset);
self.result
.extend(std::iter::repeat_n(txindex, u64::from(*count) as usize));
.extend(std::iter::repeat_n(tx_index, u64::from(*count) as usize));
}
&self.result
@@ -34,16 +34,16 @@ impl<R: RealizedOps> AddressCohortState<R> {
pub(crate) fn send(
&mut self,
addressdata: &mut FundedAddressData,
address_data: &mut FundedAddressData,
value: Sats,
current_price: Cents,
prev_price: Cents,
ath: Cents,
age: Age,
) -> Result<()> {
let prev = addressdata.cost_basis_snapshot();
addressdata.send(value, prev_price)?;
let current = addressdata.cost_basis_snapshot();
let prev = address_data.cost_basis_snapshot();
address_data.send(value, prev_price)?;
let current = address_data.cost_basis_snapshot();
self.inner.send_address(
&SupplyState {
@@ -83,14 +83,14 @@ impl<R: RealizedOps> AddressCohortState<R> {
);
}
pub(crate) fn add(&mut self, addressdata: &FundedAddressData) {
pub(crate) fn add(&mut self, address_data: &FundedAddressData) {
self.address_count += 1;
self.inner
.increment_snapshot(&addressdata.cost_basis_snapshot());
.increment_snapshot(&address_data.cost_basis_snapshot());
}
pub(crate) fn subtract(&mut self, addressdata: &FundedAddressData) {
let snapshot = addressdata.cost_basis_snapshot();
pub(crate) fn subtract(&mut self, address_data: &FundedAddressData) {
let snapshot = address_data.cost_basis_snapshot();
// Check for potential underflow before it happens
if unlikely(self.inner.supply.utxo_count < snapshot.supply_state.utxo_count) {
@@ -103,7 +103,7 @@ impl<R: RealizedOps> AddressCohortState<R> {
This means the address is not properly tracked in this cohort.",
self.address_count,
self.inner.supply,
addressdata,
address_data,
snapshot.supply_state,
snapshot.realized_price
);
@@ -118,7 +118,7 @@ impl<R: RealizedOps> AddressCohortState<R> {
This means the address is not properly tracked in this cohort.",
self.address_count,
self.inner.supply,
addressdata,
address_data,
snapshot.supply_state,
snapshot.realized_price
);
@@ -129,7 +129,7 @@ impl<R: RealizedOps> AddressCohortState<R> {
"AddressCohortState::subtract address_count underflow! address_count=0\n\
Address being subtracted: {}\n\
Realized price: {}",
addressdata, snapshot.realized_price
address_data, snapshot.realized_price
)
});
+23 -22
View File
@@ -23,7 +23,7 @@ use crate::{
state::BlockState,
},
indexes, inputs,
internal::{CachedWindowStarts, PerBlockCumulative, db_utils::{finalize_db, open_db}},
internal::{CachedWindowStarts, PerBlockCumulativeWithSums, db_utils::{finalize_db, open_db}},
outputs, prices, transactions,
};
@@ -70,16 +70,16 @@ pub struct Vecs<M: StorageMode = Rw> {
#[traversable(wrap = "cohorts", rename = "address")]
pub address_cohorts: AddressCohorts<M>,
#[traversable(wrap = "cointime")]
pub coinblocks_destroyed: PerBlockCumulative<StoredF64, M>,
pub coinblocks_destroyed: PerBlockCumulativeWithSums<StoredF64, StoredF64, M>,
pub addresses: AddressMetricsVecs<M>,
/// In-memory block state for UTXO processing. Persisted via supply_state.
/// Kept across compute() calls to avoid O(n) rebuild on resume.
#[traversable(skip)]
chain_state: Vec<BlockState>,
/// In-memory txindex→height reverse lookup. Kept across compute() calls.
/// In-memory tx_index→height reverse lookup. Kept across compute() calls.
#[traversable(skip)]
txindex_to_height: RangeMap<TxIndex, Height>,
tx_index_to_height: RangeMap<TxIndex, Height>,
/// Cached height→price mapping. Incrementally extended, O(new_blocks) on resume.
#[traversable(skip)]
@@ -114,12 +114,12 @@ impl Vecs {
let address_cohorts = AddressCohorts::forced_import(&db, version, indexes, &states_path, cached_starts)?;
// Create address data BytesVecs first so we can also use them for identity mappings
let fundedaddressindex_to_fundedaddressdata = BytesVec::forced_import_with(
vecdb::ImportOptions::new(&db, "fundedaddressdata", version)
let funded_address_index_to_funded_address_data = BytesVec::forced_import_with(
vecdb::ImportOptions::new(&db, "funded_address_data", version)
.with_saved_stamped_changes(SAVED_STAMPED_CHANGES),
)?;
let emptyaddressindex_to_emptyaddressdata = BytesVec::forced_import_with(
vecdb::ImportOptions::new(&db, "emptyaddressdata", version)
let empty_address_index_to_empty_address_data = BytesVec::forced_import_with(
vecdb::ImportOptions::new(&db, "empty_address_data", version)
.with_saved_stamped_changes(SAVED_STAMPED_CHANGES),
)?;
@@ -127,13 +127,13 @@ impl Vecs {
let funded_address_index = LazyVecFrom1::init(
"funded_address_index",
version,
fundedaddressindex_to_fundedaddressdata.read_only_boxed_clone(),
funded_address_index_to_funded_address_data.read_only_boxed_clone(),
|index, _| index,
);
let empty_address_index = LazyVecFrom1::init(
"empty_address_index",
version,
emptyaddressindex_to_emptyaddressdata.read_only_boxed_clone(),
empty_address_index_to_empty_address_data.read_only_boxed_clone(),
|index, _| index,
);
@@ -173,20 +173,21 @@ impl Vecs {
utxo_cohorts,
address_cohorts,
coinblocks_destroyed: PerBlockCumulative::forced_import(
coinblocks_destroyed: PerBlockCumulativeWithSums::forced_import(
&db,
"coinblocks_destroyed",
version + Version::TWO,
indexes,
cached_starts,
)?,
any_address_indexes: AnyAddressIndexesVecs::forced_import(&db, version)?,
addresses_data: AddressesDataVecs {
funded: fundedaddressindex_to_fundedaddressdata,
empty: emptyaddressindex_to_emptyaddressdata,
funded: funded_address_index_to_funded_address_data,
empty: empty_address_index_to_empty_address_data,
},
chain_state: Vec::new(),
txindex_to_height: RangeMap::default(),
tx_index_to_height: RangeMap::default(),
cached_prices: Vec::new(),
cached_timestamps: Vec::new(),
@@ -294,9 +295,9 @@ impl Vecs {
debug!("recovered_height={}", recovered_height);
// Take chain_state and txindex_to_height out of self to avoid borrow conflicts
// Take chain_state and tx_index_to_height out of self to avoid borrow conflicts
let mut chain_state = std::mem::take(&mut self.chain_state);
let mut txindex_to_height = std::mem::take(&mut self.txindex_to_height);
let mut tx_index_to_height = std::mem::take(&mut self.tx_index_to_height);
// Recover or reuse chain_state
let starting_height = if recovered_height.is_zero() {
@@ -312,7 +313,7 @@ impl Vecs {
)?;
chain_state.clear();
txindex_to_height.truncate(0);
tx_index_to_height.truncate(0);
info!("State recovery: fresh start");
Height::ZERO
@@ -341,7 +342,7 @@ impl Vecs {
debug!("chain_state rebuilt");
// Truncate RangeMap to match (entries are immutable, safe to keep)
txindex_to_height.truncate(end);
tx_index_to_height.truncate(end);
recovered_height
};
@@ -384,7 +385,7 @@ impl Vecs {
starting_height,
last_height,
&mut chain_state,
&mut txindex_to_height,
&mut tx_index_to_height,
&cached_prices,
&cached_timestamps,
&cached_price_range_max,
@@ -396,9 +397,9 @@ impl Vecs {
self.cached_price_range_max = cached_price_range_max;
}
// Put chain_state and txindex_to_height back
// Put chain_state and tx_index_to_height back
self.chain_state = chain_state;
self.txindex_to_height = txindex_to_height;
self.tx_index_to_height = tx_index_to_height;
// 5. Compute aggregates (overlapping cohorts from separate cohorts)
info!("Computing overlapping cohorts...");
@@ -426,7 +427,7 @@ impl Vecs {
r2?;
}
// 6b. Compute address count sum (by addresstype → all)
// 6b. Compute address count sum (by address_type → all)
self.addresses.funded.compute_rest(starting_indexes, exit)?;
self.addresses.empty.compute_rest(starting_indexes, exit)?;
+16 -16
View File
@@ -92,7 +92,7 @@ impl Vecs {
Self {
p2pk33: P2PK33Vecs {
identity: LazyVecFrom1::init(
"p2pk33addressindex",
"p2pk33_address_index",
version,
indexer.vecs.addresses.p2pk33.bytes.read_only_boxed_clone(),
|index, _| index,
@@ -100,7 +100,7 @@ impl Vecs {
},
p2pk65: P2PK65Vecs {
identity: LazyVecFrom1::init(
"p2pk65addressindex",
"p2pk65_address_index",
version,
indexer.vecs.addresses.p2pk65.bytes.read_only_boxed_clone(),
|index, _| index,
@@ -108,7 +108,7 @@ impl Vecs {
},
p2pkh: P2PKHVecs {
identity: LazyVecFrom1::init(
"p2pkhaddressindex",
"p2pkh_address_index",
version,
indexer.vecs.addresses.p2pkh.bytes.read_only_boxed_clone(),
|index, _| index,
@@ -116,7 +116,7 @@ impl Vecs {
},
p2sh: P2SHVecs {
identity: LazyVecFrom1::init(
"p2shaddressindex",
"p2sh_address_index",
version,
indexer.vecs.addresses.p2sh.bytes.read_only_boxed_clone(),
|index, _| index,
@@ -124,7 +124,7 @@ impl Vecs {
},
p2tr: P2TRVecs {
identity: LazyVecFrom1::init(
"p2traddressindex",
"p2tr_address_index",
version,
indexer.vecs.addresses.p2tr.bytes.read_only_boxed_clone(),
|index, _| index,
@@ -132,7 +132,7 @@ impl Vecs {
},
p2wpkh: P2WPKHVecs {
identity: LazyVecFrom1::init(
"p2wpkhaddressindex",
"p2wpkh_address_index",
version,
indexer.vecs.addresses.p2wpkh.bytes.read_only_boxed_clone(),
|index, _| index,
@@ -140,7 +140,7 @@ impl Vecs {
},
p2wsh: P2WSHVecs {
identity: LazyVecFrom1::init(
"p2wshaddressindex",
"p2wsh_address_index",
version,
indexer.vecs.addresses.p2wsh.bytes.read_only_boxed_clone(),
|index, _| index,
@@ -148,7 +148,7 @@ impl Vecs {
},
p2a: P2AVecs {
identity: LazyVecFrom1::init(
"p2aaddressindex",
"p2a_address_index",
version,
indexer.vecs.addresses.p2a.bytes.read_only_boxed_clone(),
|index, _| index,
@@ -156,44 +156,44 @@ impl Vecs {
},
p2ms: P2MSVecs {
identity: LazyVecFrom1::init(
"p2msoutputindex",
"p2ms_output_index",
version,
indexer.vecs.scripts.p2ms.to_txindex.read_only_boxed_clone(),
indexer.vecs.scripts.p2ms.to_tx_index.read_only_boxed_clone(),
|index, _| index,
),
},
empty: EmptyVecs {
identity: LazyVecFrom1::init(
"emptyoutputindex",
"empty_output_index",
version,
indexer
.vecs
.scripts
.empty.to_txindex
.empty.to_tx_index
.read_only_boxed_clone(),
|index, _| index,
),
},
unknown: UnknownVecs {
identity: LazyVecFrom1::init(
"unknownoutputindex",
"unknown_output_index",
version,
indexer
.vecs
.scripts
.unknown.to_txindex
.unknown.to_tx_index
.read_only_boxed_clone(),
|index, _| index,
),
},
opreturn: OpReturnVecs {
identity: LazyVecFrom1::init(
"opreturnindex",
"op_return_index",
version,
indexer
.vecs
.scripts
.opreturn.to_txindex
.opreturn.to_tx_index
.read_only_boxed_clone(),
|index, _| index,
),
+2 -2
View File
@@ -25,7 +25,7 @@ pub struct Vecs<M: StorageMode = Rw> {
pub month6: M::Stored<EagerVec<PcoVec<Height, Month6>>>,
pub year1: M::Stored<EagerVec<PcoVec<Height, Year1>>>,
pub year10: M::Stored<EagerVec<PcoVec<Height, Year10>>>,
pub txindex_count: M::Stored<EagerVec<PcoVec<Height, StoredU64>>>,
pub tx_index_count: M::Stored<EagerVec<PcoVec<Height, StoredU64>>>,
}
impl Vecs {
@@ -47,7 +47,7 @@ impl Vecs {
month6: EagerVec::forced_import(db, "month6", version)?,
year1: EagerVec::forced_import(db, "year1", version)?,
year10: EagerVec::forced_import(db, "year10", version)?,
txindex_count: EagerVec::forced_import(db, "txindex_count", version)?,
tx_index_count: EagerVec::forced_import(db, "tx_index_count", version)?,
})
}
}
+23 -23
View File
@@ -13,9 +13,9 @@ mod minute30;
mod month1;
mod month3;
mod month6;
mod txindex;
mod txinindex;
mod txoutindex;
mod tx_index;
mod txin_index;
mod txout_index;
mod week1;
mod year1;
mod year10;
@@ -51,9 +51,9 @@ pub use minute30::Vecs as Minute30Vecs;
pub use month1::Vecs as Month1Vecs;
pub use month3::Vecs as Month3Vecs;
pub use month6::Vecs as Month6Vecs;
pub use txindex::Vecs as TxIndexVecs;
pub use txinindex::Vecs as TxInIndexVecs;
pub use txoutindex::Vecs as TxOutIndexVecs;
pub use tx_index::Vecs as TxIndexVecs;
pub use txin_index::Vecs as TxInIndexVecs;
pub use txout_index::Vecs as TxOutIndexVecs;
pub use week1::Vecs as Week1Vecs;
pub use year1::Vecs as Year1Vecs;
pub use year10::Vecs as Year10Vecs;
@@ -82,9 +82,9 @@ pub struct Vecs<M: StorageMode = Rw> {
pub month6: Month6Vecs<M>,
pub year1: Year1Vecs<M>,
pub year10: Year10Vecs<M>,
pub txindex: TxIndexVecs<M>,
pub txinindex: TxInIndexVecs,
pub txoutindex: TxOutIndexVecs,
pub tx_index: TxIndexVecs<M>,
pub txin_index: TxInIndexVecs,
pub txout_index: TxOutIndexVecs,
}
impl Vecs {
@@ -114,9 +114,9 @@ impl Vecs {
let month6 = Month6Vecs::forced_import(&db, version)?;
let year1 = Year1Vecs::forced_import(&db, version)?;
let year10 = Year10Vecs::forced_import(&db, version)?;
let txindex = TxIndexVecs::forced_import(&db, version, indexer)?;
let txinindex = TxInIndexVecs::forced_import(version, indexer);
let txoutindex = TxOutIndexVecs::forced_import(version, indexer);
let tx_index = TxIndexVecs::forced_import(&db, version, indexer)?;
let txin_index = TxInIndexVecs::forced_import(version, indexer);
let txout_index = TxOutIndexVecs::forced_import(version, indexer);
let cached_mappings = CachedMappings {
minute10_first_height: CachedVec::new(&minute10.first_height),
@@ -155,9 +155,9 @@ impl Vecs {
month6,
year1,
year10,
txindex,
txinindex,
txoutindex,
tx_index,
txin_index,
txout_index,
db,
};
@@ -221,15 +221,15 @@ impl Vecs {
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.txindex.input_count.compute_count_from_indexes(
starting_indexes.txindex,
&indexer.vecs.transactions.first_txinindex,
self.tx_index.input_count.compute_count_from_indexes(
starting_indexes.tx_index,
&indexer.vecs.transactions.first_txin_index,
&indexer.vecs.inputs.outpoint,
exit,
)?;
self.txindex.output_count.compute_count_from_indexes(
starting_indexes.txindex,
&indexer.vecs.transactions.first_txoutindex,
self.tx_index.output_count.compute_count_from_indexes(
starting_indexes.tx_index,
&indexer.vecs.transactions.first_txout_index,
&indexer.vecs.outputs.value,
exit,
)?;
@@ -242,9 +242,9 @@ impl Vecs {
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.height.txindex_count.compute_count_from_indexes(
self.height.tx_index_count.compute_count_from_indexes(
starting_indexes.height,
&indexer.vecs.transactions.first_txindex,
&indexer.vecs.transactions.first_tx_index,
&indexer.vecs.transactions.txid,
exit,
)?;
+1 -1
View File
@@ -22,7 +22,7 @@ impl Vecs {
) -> Result<Self> {
Ok(Self {
identity: LazyVecFrom1::init(
"txindex",
"tx_index",
version,
indexer.vecs.transactions.txid.read_only_boxed_clone(),
|index, _| index,
@@ -12,7 +12,7 @@ impl Vecs {
pub(crate) fn forced_import(version: Version, indexer: &Indexer) -> Self {
Self {
identity: LazyVecFrom1::init(
"txinindex",
"txin_index",
version,
indexer.vecs.inputs.outpoint.read_only_boxed_clone(),
|index, _| index,
@@ -12,7 +12,7 @@ impl Vecs {
pub(crate) fn forced_import(version: Version, indexer: &Indexer) -> Self {
Self {
identity: LazyVecFrom1::init(
"txoutindex",
"txout_index",
version,
indexer.vecs.outputs.value.read_only_boxed_clone(),
|index, _| index,
@@ -20,9 +20,9 @@ impl Vecs {
.compute(starting_indexes.height, &window_starts, exit, |full| {
full.compute_with_skip(
starting_indexes.height,
&indexes.txindex.input_count,
&indexer.vecs.transactions.first_txindex,
&indexes.height.txindex_count,
&indexes.tx_index.input_count,
&indexer.vecs.transactions.first_tx_index,
&indexes.height.tx_index_count,
exit,
0,
)
+27 -27
View File
@@ -18,9 +18,9 @@ impl Vecs {
) -> Result<()> {
// Validate computed versions against dependencies
let dep_version = indexer.vecs.inputs.outpoint.version()
+ indexer.vecs.transactions.first_txoutindex.version()
+ indexer.vecs.transactions.first_txout_index.version()
+ indexer.vecs.outputs.value.version();
self.txoutindex
self.txout_index
.validate_computed_version_or_reset(dep_version)?;
self.value.validate_computed_version_or_reset(dep_version)?;
@@ -29,21 +29,21 @@ impl Vecs {
return Ok(());
}
let len1 = self.txoutindex.len();
let len1 = self.txout_index.len();
let len2 = self.value.len();
let starting = starting_indexes.txinindex.to_usize();
let starting = starting_indexes.txin_index.to_usize();
let min = len1.min(len2).min(starting);
if min >= target {
return Ok(());
}
let first_txoutindex_reader = indexer.vecs.transactions.first_txoutindex.reader();
let first_txout_index_reader = indexer.vecs.transactions.first_txout_index.reader();
let value_reader = indexer.vecs.outputs.value.reader();
let actual_total = target - min;
let mut entries: Vec<Entry> = Vec::with_capacity(actual_total.min(BATCH_SIZE));
// Pre-allocate output buffers for scatter-write pattern
let mut out_txoutindex: Vec<TxOutIndex> = Vec::new();
let mut out_txout_index: Vec<TxOutIndex> = Vec::new();
let mut out_value: Vec<Sats> = Vec::new();
let mut batch_start = min;
@@ -60,49 +60,49 @@ impl Vecs {
.for_each_range_at(batch_start, batch_end, |outpoint| {
entries.push(Entry {
original_idx: j,
txindex: outpoint.txindex(),
tx_index: outpoint.tx_index(),
vout: outpoint.vout(),
txoutindex: TxOutIndex::COINBASE,
txout_index: TxOutIndex::COINBASE,
value: Sats::MAX,
});
j += 1;
});
// Sort 1: by txindex (group by transaction for sequential first_txoutindex reads)
entries.sort_unstable_by_key(|e| e.txindex);
// Sort 1: by tx_index (group by transaction for sequential first_txout_index reads)
entries.sort_unstable_by_key(|e| e.tx_index);
for entry in &mut entries {
if entry.txindex.is_coinbase() {
if entry.tx_index.is_coinbase() {
break;
}
entry.txoutindex =
first_txoutindex_reader.get(entry.txindex.to_usize()) + entry.vout;
entry.txout_index =
first_txout_index_reader.get(entry.tx_index.to_usize()) + entry.vout;
}
// Sort 2: by txoutindex (sequential value reads)
entries.sort_unstable_by_key(|e| e.txoutindex);
// Sort 2: by txout_index (sequential value reads)
entries.sort_unstable_by_key(|e| e.txout_index);
for entry in &mut entries {
if entry.txoutindex.is_coinbase() {
if entry.txout_index.is_coinbase() {
break;
}
entry.value = value_reader.get(entry.txoutindex.to_usize());
entry.value = value_reader.get(entry.txout_index.to_usize());
}
// Scatter-write to output buffers using original_idx (avoids Sort 3)
out_txoutindex.clear();
out_txoutindex.resize(batch_len, TxOutIndex::COINBASE);
out_txout_index.clear();
out_txout_index.resize(batch_len, TxOutIndex::COINBASE);
out_value.clear();
out_value.resize(batch_len, Sats::MAX);
for entry in &entries {
out_txoutindex[entry.original_idx] = entry.txoutindex;
out_txout_index[entry.original_idx] = entry.txout_index;
out_value[entry.original_idx] = entry.value;
}
for i in 0..batch_len {
let txinindex = TxInIndex::from(batch_start + i);
self.txoutindex
.truncate_push(txinindex, out_txoutindex[i])?;
self.value.truncate_push(txinindex, out_value[i])?;
let txin_index = TxInIndex::from(batch_start + i);
self.txout_index
.truncate_push(txin_index, out_txout_index[i])?;
self.value.truncate_push(txin_index, out_value[i])?;
}
if batch_end < target {
@@ -110,7 +110,7 @@ impl Vecs {
}
let _lock = exit.lock();
self.txoutindex.write()?;
self.txout_index.write()?;
self.value.write()?;
db.flush()?;
@@ -123,8 +123,8 @@ impl Vecs {
struct Entry {
original_idx: usize,
txindex: TxIndex,
tx_index: TxIndex,
vout: Vout,
txoutindex: TxOutIndex,
txout_index: TxOutIndex,
value: Sats,
}
@@ -7,7 +7,7 @@ use super::Vecs;
impl Vecs {
pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> {
Ok(Self {
txoutindex: PcoVec::forced_import(db, "txoutindex", version)?,
txout_index: PcoVec::forced_import(db, "txout_index", version)?,
value: PcoVec::forced_import(db, "value", version)?,
})
}
+1 -1
View File
@@ -4,6 +4,6 @@ use vecdb::{PcoVec, Rw, StorageMode};
#[derive(Traversable)]
pub struct Vecs<M: StorageMode = Rw> {
pub txoutindex: M::Stored<PcoVec<TxInIndex, TxOutIndex>>,
pub txout_index: M::Stored<PcoVec<TxInIndex, TxOutIndex>>,
pub value: M::Stored<PcoVec<TxInIndex, Sats>>,
}
@@ -62,14 +62,14 @@ where
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
txindex_source: &impl ReadableVec<TxIndex, T>,
tx_index_source: &impl ReadableVec<TxIndex, T>,
exit: &Exit,
) -> Result<()>
where
T: Copy + Ord + From<f64> + Default,
f64: From<T>,
{
self.derive_from_with_skip(indexer, indexes, starting_indexes, txindex_source, exit, 0)
self.derive_from_with_skip(indexer, indexes, starting_indexes, tx_index_source, exit, 0)
}
/// Derive from source, skipping first N transactions per block from per-block stats.
@@ -82,7 +82,7 @@ where
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
txindex_source: &impl ReadableVec<TxIndex, T>,
tx_index_source: &impl ReadableVec<TxIndex, T>,
exit: &Exit,
skip_count: usize,
) -> Result<()>
@@ -93,9 +93,9 @@ where
// Per-block distribution (supports skip for coinbase exclusion)
self.block.compute_with_skip(
starting_indexes.height,
txindex_source,
&indexer.vecs.transactions.first_txindex,
&indexes.height.txindex_count,
tx_index_source,
&indexer.vecs.transactions.first_tx_index,
&indexes.height.tx_index_count,
exit,
skip_count,
)?;
@@ -103,9 +103,9 @@ where
// 6-block rolling: true distribution from all txs in last 6 blocks
self.rolling._6b.compute_from_nblocks(
starting_indexes.height,
txindex_source,
&indexer.vecs.transactions.first_txindex,
&indexes.height.txindex_count,
tx_index_source,
&indexer.vecs.transactions.first_tx_index,
&indexes.height.tx_index_count,
6,
exit,
)?;
@@ -20,7 +20,7 @@ pub struct PerTxDistribution<T, M: StorageMode = Rw>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
{
pub txindex: M::Stored<EagerVec<PcoVec<TxIndex, T>>>,
pub tx_index: M::Stored<EagerVec<PcoVec<TxIndex, T>>>,
#[traversable(flatten)]
pub distribution: TxDerivedDistribution<T, M>,
}
@@ -30,10 +30,10 @@ where
T: NumericValue + JsonSchema,
{
pub(crate) fn forced_import(db: &Database, name: &str, version: Version) -> Result<Self> {
let txindex = EagerVec::forced_import(db, name, version)?;
let tx_index = EagerVec::forced_import(db, name, version)?;
let distribution = TxDerivedDistribution::forced_import(db, name, version)?;
Ok(Self {
txindex,
tx_index,
distribution,
})
}
@@ -55,7 +55,7 @@ where
indexer,
indexes,
starting_indexes,
&self.txindex,
&self.tx_index,
exit,
skip_count,
)
@@ -17,7 +17,7 @@ where
S1: ComputedVecValue,
S2: ComputedVecValue,
{
pub txindex: LazyVecFrom2<TxIndex, T, TxIndex, S1, TxIndex, S2>,
pub tx_index: LazyVecFrom2<TxIndex, T, TxIndex, S1, TxIndex, S2>,
#[traversable(flatten)]
pub distribution: TxDerivedDistribution<T, M>,
}
@@ -32,11 +32,11 @@ where
db: &Database,
name: &str,
version: Version,
txindex: LazyVecFrom2<TxIndex, T, TxIndex, S1, TxIndex, S2>,
tx_index: LazyVecFrom2<TxIndex, T, TxIndex, S1, TxIndex, S2>,
) -> Result<Self> {
let distribution = TxDerivedDistribution::forced_import(db, name, version)?;
Ok(Self {
txindex,
tx_index,
distribution,
})
}
@@ -54,6 +54,6 @@ where
LazyVecFrom2<TxIndex, T, TxIndex, S1, TxIndex, S2>: ReadableVec<TxIndex, T>,
{
self.distribution
.derive_from(indexer, indexes, starting_indexes, &self.txindex, exit)
.derive_from(indexer, indexes, starting_indexes, &self.tx_index, exit)
}
}
@@ -15,7 +15,7 @@ where
S2: ComputedVecValue,
DSource: ComputedVecValue,
{
pub txindex: LazyVecFrom2<TxIndex, T, TxIndex, S1, TxIndex, S2>,
pub tx_index: LazyVecFrom2<TxIndex, T, TxIndex, S1, TxIndex, S2>,
#[traversable(flatten)]
pub distribution: LazyTxDerivedDistribution<T, DSource>,
}
@@ -30,13 +30,13 @@ where
pub(crate) fn new<F: UnaryTransform<DSource, T>>(
name: &str,
version: Version,
txindex: LazyVecFrom2<TxIndex, T, TxIndex, S1, TxIndex, S2>,
tx_index: LazyVecFrom2<TxIndex, T, TxIndex, S1, TxIndex, S2>,
source_distribution: &TxDerivedDistribution<DSource>,
) -> Self {
let distribution =
LazyTxDerivedDistribution::from_tx_derived::<F>(name, version, source_distribution);
Self {
txindex,
tx_index,
distribution,
}
}
@@ -24,26 +24,26 @@ impl Vecs {
exit,
|vec| {
// Cursors avoid per-height PcoVec page decompression for the
// tx-indexed lookups. Coinbase txindex values are strictly
// tx-indexed lookups. Coinbase tx_index values are strictly
// increasing, so the cursors only advance forward.
let mut txout_cursor = indexer.vecs.transactions.first_txoutindex.cursor();
let mut count_cursor = indexes.txindex.output_count.cursor();
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_indexes.height,
&indexer.vecs.transactions.first_txindex,
|(height, txindex, ..)| {
let ti = txindex.to_usize();
&indexer.vecs.transactions.first_tx_index,
|(height, tx_index, ..)| {
let ti = tx_index.to_usize();
txout_cursor.advance(ti - txout_cursor.position());
let first_txoutindex = txout_cursor.next().unwrap().to_usize();
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_txoutindex,
first_txoutindex + output_count,
first_txout_index,
first_txout_index + output_count,
Sats::ZERO,
|acc, v| acc + v,
);
@@ -66,9 +66,9 @@ impl Vecs {
|vec| {
vec.compute_sum_from_indexes(
starting_indexes.height,
&indexer.vecs.transactions.first_txindex,
&indexes.height.txindex_count,
&transactions_fees.fee.txindex,
&indexer.vecs.transactions.first_tx_index,
&indexes.height.tx_index_count,
&transactions_fees.fee.tx_index,
exit,
)?;
Ok(())
@@ -23,9 +23,9 @@ impl Vecs {
.compute(starting_indexes.height, &window_starts, exit, |full| {
full.compute_with_skip(
starting_indexes.height,
&indexes.txindex.output_count,
&indexer.vecs.transactions.first_txindex,
&indexes.height.txindex_count,
&indexes.tx_index.output_count,
&indexer.vecs.transactions.first_tx_index,
&indexes.height.tx_index_count,
exit,
0,
)
@@ -25,29 +25,29 @@ impl Vecs {
let target_height = Height::from(target_height - 1);
// Find min_height from current vec length
let current_txoutindex = self.txinindex.len();
let min_txoutindex = current_txoutindex.min(starting_indexes.txoutindex.to_usize());
let current_txout_index = self.txin_index.len();
let min_txout_index = current_txout_index.min(starting_indexes.txout_index.to_usize());
let starting_stamp = Stamp::from(starting_indexes.height);
let _ = self.txinindex.rollback_before(starting_stamp);
let _ = self.txin_index.rollback_before(starting_stamp);
self.txinindex
.truncate_if_needed(TxOutIndex::from(min_txoutindex))?;
self.txin_index
.truncate_if_needed(TxOutIndex::from(min_txout_index))?;
let txinindex_to_txoutindex = &inputs.spent.txoutindex;
let txin_index_to_txout_index = &inputs.spent.txout_index;
// Find min_height via binary search (first_txoutindex is monotonically non-decreasing)
let first_txoutindex_vec = &indexer.vecs.outputs.first_txoutindex;
let min_height = if min_txoutindex == 0 {
// Find min_height via binary search (first_txout_index is monotonically non-decreasing)
let first_txout_index_vec = &indexer.vecs.outputs.first_txout_index;
let min_height = if min_txout_index == 0 {
Height::ZERO
} else if min_txoutindex >= starting_indexes.txoutindex.to_usize() {
} else if min_txout_index >= starting_indexes.txout_index.to_usize() {
starting_indexes.height
} else {
let mut lo = 0usize;
let mut hi = starting_indexes.height.to_usize() + 1;
while lo < hi {
let mid = lo + (hi - lo) / 2;
if first_txoutindex_vec.collect_one_at(mid).unwrap().to_usize() <= min_txoutindex {
if first_txout_index_vec.collect_one_at(mid).unwrap().to_usize() <= min_txout_index {
lo = mid + 1;
} else {
hi = mid;
@@ -58,12 +58,12 @@ 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_txinindex_data = indexer
let first_txout_index_data =
first_txout_index_vec.collect_range_at(offset, target_height.to_usize() + 1);
let first_txin_index_data = indexer
.vecs
.inputs
.first_txinindex
.first_txin_index
.collect_range_at(offset, target_height.to_usize() + 2);
// Validate: computed height must not exceed starting height
@@ -80,47 +80,47 @@ impl Vecs {
while batch_start_height <= target_height {
let batch_end_height = (batch_start_height + HEIGHT_BATCH).min(target_height);
// Fill txoutindex up to batch_end_height + 1
let batch_txoutindex = if batch_end_height >= target_height {
// Fill txout_index up to batch_end_height + 1
let batch_txout_index = if batch_end_height >= target_height {
indexer.vecs.outputs.value.len()
} else {
first_txoutindex_data[batch_end_height.to_usize() + 1 - offset].to_usize()
first_txout_index_data[batch_end_height.to_usize() + 1 - offset].to_usize()
};
self.txinindex
.fill_to(batch_txoutindex, TxInIndex::UNSPENT)?;
self.txin_index
.fill_to(batch_txout_index, TxInIndex::UNSPENT)?;
// Get txin range for this height batch
let txin_start =
first_txinindex_data[batch_start_height.to_usize() - offset].to_usize();
first_txin_index_data[batch_start_height.to_usize() - offset].to_usize();
let txin_end = if batch_end_height >= target_height {
inputs.spent.txoutindex.len()
inputs.spent.txout_index.len()
} else {
first_txinindex_data[batch_end_height.to_usize() + 1 - offset].to_usize()
first_txin_index_data[batch_end_height.to_usize() + 1 - offset].to_usize()
};
// Stream txins directly into pairs — avoids intermediate Vec allocation
pairs.clear();
let mut j = txin_start;
txinindex_to_txoutindex.for_each_range_at(
txin_index_to_txout_index.for_each_range_at(
txin_start,
txin_end,
|txoutindex: TxOutIndex| {
if !txoutindex.is_coinbase() {
pairs.push((txoutindex, TxInIndex::from(j)));
|txout_index: TxOutIndex| {
if !txout_index.is_coinbase() {
pairs.push((txout_index, TxInIndex::from(j)));
}
j += 1;
},
);
pairs.sort_unstable_by_key(|(txoutindex, _)| *txoutindex);
pairs.sort_unstable_by_key(|(txout_index, _)| *txout_index);
for &(txoutindex, txinindex) in &pairs {
self.txinindex.update(txoutindex, txinindex)?;
for &(txout_index, txin_index) in &pairs {
self.txin_index.update(txout_index, txin_index)?;
}
if batch_end_height < target_height {
let _lock = exit.lock();
self.txinindex.write()?;
self.txin_index.write()?;
info!(
"TxOuts: {:.2}%",
batch_end_height.to_usize() as f64 / target_height.to_usize() as f64 * 100.0
@@ -132,7 +132,7 @@ impl Vecs {
}
let _lock = exit.lock();
self.txinindex
self.txin_index
.stamped_write_with_changes(Stamp::from(target_height))?;
db.flush()?;
@@ -7,7 +7,7 @@ use super::Vecs;
impl Vecs {
pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> {
Ok(Self {
txinindex: BytesVec::forced_import(db, "txinindex", version)?,
txin_index: BytesVec::forced_import(db, "txin_index", version)?,
})
}
}
@@ -4,5 +4,5 @@ use vecdb::{BytesVec, Rw, StorageMode};
#[derive(Traversable)]
pub struct Vecs<M: StorageMode = Rw> {
pub txinindex: M::Stored<BytesVec<TxOutIndex, TxInIndex>>,
pub txin_index: M::Stored<BytesVec<TxOutIndex, TxInIndex>>,
}
+15 -15
View File
@@ -118,9 +118,9 @@ impl Vecs {
self.height_to_pool
.validate_computed_version_or_reset(indexer.stores.height_to_coinbase_tag.version())?;
let first_txoutindex = indexer.vecs.transactions.first_txoutindex.reader();
let outputtype = indexer.vecs.outputs.outputtype.reader();
let typeindex = indexer.vecs.outputs.typeindex.reader();
let first_txout_index = indexer.vecs.transactions.first_txout_index.reader();
let output_type = indexer.vecs.outputs.output_type.reader();
let type_index = indexer.vecs.outputs.type_index.reader();
let p2pk65 = indexer.vecs.addresses.p2pk65.bytes.reader();
let p2pk33 = indexer.vecs.addresses.p2pk33.bytes.reader();
let p2pkh = indexer.vecs.addresses.p2pkh.bytes.reader();
@@ -138,11 +138,11 @@ impl Vecs {
.min(self.height_to_pool.len());
// Cursors avoid per-height PcoVec page decompression.
// Heights are sequential, txindex values derived from them are monotonically
// Heights are sequential, tx_index values derived from them are monotonically
// increasing, so both cursors only advance forward.
let mut first_txindex_cursor = indexer.vecs.transactions.first_txindex.cursor();
first_txindex_cursor.advance(min);
let mut output_count_cursor = indexes.txindex.output_count.cursor();
let mut first_tx_index_cursor = indexer.vecs.transactions.first_tx_index.cursor();
first_tx_index_cursor.advance(min);
let mut output_count_cursor = indexes.tx_index.output_count.cursor();
indexer
.stores
@@ -150,18 +150,18 @@ impl Vecs {
.iter()
.skip(min)
.try_for_each(|(height, coinbase_tag)| -> Result<()> {
let txindex = first_txindex_cursor.next().unwrap();
let out_start = first_txoutindex.get(txindex.to_usize());
let tx_index = first_tx_index_cursor.next().unwrap();
let out_start = first_txout_index.get(tx_index.to_usize());
let ti = txindex.to_usize();
let ti = tx_index.to_usize();
output_count_cursor.advance(ti - output_count_cursor.position());
let outputcount = output_count_cursor.next().unwrap();
let output_count_val = output_count_cursor.next().unwrap();
let pool = (*out_start..(*out_start + *outputcount))
let pool = (*out_start..(*out_start + *output_count_val))
.map(TxOutIndex::from)
.find_map(|txoutindex| {
let ot = outputtype.get(txoutindex.to_usize());
let ti = usize::from(typeindex.get(txoutindex.to_usize()));
.find_map(|txout_index| {
let ot = output_type.get(txout_index.to_usize());
let ti = usize::from(type_index.get(txout_index.to_usize()));
match ot {
OutputType::P2PK65 => Some(AddressBytes::from(p2pk65.get(ti))),
OutputType::P2PK33 => Some(AddressBytes::from(p2pk33.get(ti))),
+9 -9
View File
@@ -83,20 +83,20 @@ impl Vecs {
self.check_xor_bytes(parser)?;
// Validate computed versions against dependencies
let dep_version = indexer.vecs.transactions.first_txindex.version()
let dep_version = indexer.vecs.transactions.first_tx_index.version()
+ indexer.vecs.transactions.height.version();
self.block
.validate_computed_version_or_reset(dep_version)?;
self.tx
.validate_computed_version_or_reset(dep_version)?;
let min_txindex = TxIndex::from(self.tx.len()).min(starting_indexes.txindex);
let min_tx_index = TxIndex::from(self.tx.len()).min(starting_indexes.tx_index);
let Some(min_height) = indexer
.vecs
.transactions
.height
.collect_one(min_txindex)
.collect_one(min_tx_index)
.map(|h: Height| h.min(starting_indexes.height))
else {
return Ok(());
@@ -104,13 +104,13 @@ impl Vecs {
// Cursor avoids per-height PcoVec page decompression.
// Heights are sequential, so the cursor only advances forward.
let mut first_txindex_cursor = indexer.vecs.transactions.first_txindex.cursor();
first_txindex_cursor.advance(min_height.to_usize());
let mut first_tx_index_cursor = indexer.vecs.transactions.first_tx_index.cursor();
first_tx_index_cursor.advance(min_height.to_usize());
parser
.read(
Some(min_height),
Some((indexer.vecs.transactions.first_txindex.len() - 1).into()),
Some((indexer.vecs.transactions.first_tx_index.len() - 1).into()),
)
.iter()
.try_for_each(|block| -> Result<()> {
@@ -119,13 +119,13 @@ impl Vecs {
self.block
.truncate_push(height, block.metadata().position())?;
let txindex = first_txindex_cursor.next().unwrap();
let tx_index = first_tx_index_cursor.next().unwrap();
block.tx_metadata().iter().enumerate().try_for_each(
|(index, metadata)| -> Result<()> {
let txindex = txindex + index;
let tx_index = tx_index + index;
self.tx
.truncate_push(txindex, metadata.position())?;
.truncate_push(tx_index, metadata.position())?;
Ok(())
},
)?;
+13 -13
View File
@@ -59,7 +59,7 @@ impl Vecs {
exit: &Exit,
) -> Result<()> {
let source_version =
indexer.vecs.outputs.value.version() + indexer.vecs.outputs.outputtype.version();
indexer.vecs.outputs.value.version() + indexer.vecs.outputs.output_type.version();
self.spot
.cents
.height
@@ -156,34 +156,34 @@ impl Vecs {
let total_outputs = indexer.vecs.outputs.value.len();
// Pre-collect height-indexed data for the range (plus one extra for next-block lookups)
let collect_end = (range.end + 1).min(indexer.vecs.transactions.first_txindex.len());
let first_txindexes: Vec<TxIndex> = indexer
let collect_end = (range.end + 1).min(indexer.vecs.transactions.first_tx_index.len());
let first_tx_indexes: Vec<TxIndex> = indexer
.vecs
.transactions
.first_txindex
.first_tx_index
.collect_range_at(range.start, collect_end);
let out_firsts: Vec<TxOutIndex> = indexer
.vecs
.outputs
.first_txoutindex
.first_txout_index
.collect_range_at(range.start, collect_end);
let mut ref_bins = Vec::with_capacity(range.len());
// Cursor avoids per-block PcoVec page decompression for
// the tx-indexed first_txoutindex lookup. The accessed
// txindex values (first_txindex + 1) are strictly increasing
// the tx-indexed first_txout_index lookup. The accessed
// tx_index values (first_tx_index + 1) are strictly increasing
// across blocks, so the cursor only advances forward.
let mut txout_cursor = indexer.vecs.transactions.first_txoutindex.cursor();
let mut txout_cursor = indexer.vecs.transactions.first_txout_index.cursor();
// Reusable buffers — avoid per-block allocation
let mut values: Vec<Sats> = Vec::new();
let mut output_types: Vec<OutputType> = Vec::new();
for (idx, _h) in range.enumerate() {
let first_txindex = first_txindexes[idx];
let next_first_txindex = first_txindexes
let first_tx_index = first_tx_indexes[idx];
let next_first_tx_index = first_tx_indexes
.get(idx + 1)
.copied()
.unwrap_or(TxIndex::from(total_txs));
@@ -193,8 +193,8 @@ impl Vecs {
.copied()
.unwrap_or(TxOutIndex::from(total_outputs))
.to_usize();
let out_start = if first_txindex.to_usize() + 1 < next_first_txindex.to_usize() {
let target = first_txindex.to_usize() + 1;
let out_start = if first_tx_index.to_usize() + 1 < next_first_tx_index.to_usize() {
let target = first_tx_index.to_usize() + 1;
txout_cursor.advance(target - txout_cursor.position());
txout_cursor.next().unwrap().to_usize()
} else {
@@ -207,7 +207,7 @@ impl Vecs {
.outputs
.value
.collect_range_into_at(out_start, out_end, &mut values);
indexer.vecs.outputs.outputtype.collect_range_into_at(
indexer.vecs.outputs.output_type.collect_range_into_at(
out_start,
out_end,
&mut output_types,
@@ -27,7 +27,7 @@ impl Vecs {
Ok(v.compute_count_from_indexes(
starting_indexes.height,
&indexer.vecs.scripts.p2ms.first_index,
&indexer.vecs.scripts.p2ms.to_txindex,
&indexer.vecs.scripts.p2ms.to_tx_index,
exit,
)?)
})?;
@@ -107,27 +107,27 @@ impl Vecs {
Ok(v.compute_count_from_indexes(
starting_indexes.height,
&indexer.vecs.scripts.opreturn.first_index,
&indexer.vecs.scripts.opreturn.to_txindex,
&indexer.vecs.scripts.opreturn.to_tx_index,
exit,
)?)
})?;
self.unknownoutput
self.unknown_output
.compute(starting_indexes.height, exit, |v| {
Ok(v.compute_count_from_indexes(
starting_indexes.height,
&indexer.vecs.scripts.unknown.first_index,
&indexer.vecs.scripts.unknown.to_txindex,
&indexer.vecs.scripts.unknown.to_tx_index,
exit,
)?)
})?;
self.emptyoutput
self.empty_output
.compute(starting_indexes.height, exit, |v| {
Ok(v.compute_count_from_indexes(
starting_indexes.height,
&indexer.vecs.scripts.empty.first_index,
&indexer.vecs.scripts.empty.to_txindex,
&indexer.vecs.scripts.empty.to_tx_index,
exit,
)?)
})?;
@@ -53,16 +53,16 @@ impl Vecs {
indexes,
cached_starts,
)?,
emptyoutput: PerBlockCumulativeWithSums::forced_import(
empty_output: PerBlockCumulativeWithSums::forced_import(
db,
"emptyoutput_count",
"empty_output_count",
version,
indexes,
cached_starts,
)?,
unknownoutput: PerBlockCumulativeWithSums::forced_import(
unknown_output: PerBlockCumulativeWithSums::forced_import(
db,
"unknownoutput_count",
"unknown_output_count",
version,
indexes,
cached_starts,
@@ -16,8 +16,8 @@ pub struct Vecs<M: StorageMode = Rw> {
pub p2wpkh: PerBlockCumulativeWithSums<StoredU64, StoredU64, M>,
pub p2wsh: PerBlockCumulativeWithSums<StoredU64, StoredU64, M>,
pub opreturn: PerBlockCumulativeWithSums<StoredU64, StoredU64, M>,
pub emptyoutput: PerBlockCumulativeWithSums<StoredU64, StoredU64, M>,
pub unknownoutput: PerBlockCumulativeWithSums<StoredU64, StoredU64, M>,
pub empty_output: PerBlockCumulativeWithSums<StoredU64, StoredU64, M>,
pub unknown_output: PerBlockCumulativeWithSums<StoredU64, StoredU64, M>,
pub segwit: PerBlockCumulativeWithSums<StoredU64, StoredU64, M>,
}
@@ -20,13 +20,13 @@ impl Vecs {
exit,
|height_vec| {
// Validate computed versions against dependencies
let dep_version = indexer.vecs.outputs.first_txoutindex.version()
+ indexer.vecs.outputs.outputtype.version()
let dep_version = indexer.vecs.outputs.first_txout_index.version()
+ indexer.vecs.outputs.output_type.version()
+ indexer.vecs.outputs.value.version();
height_vec.validate_computed_version_or_reset(dep_version)?;
// Get target height
let target_len = indexer.vecs.outputs.first_txoutindex.len();
let target_len = indexer.vecs.outputs.first_txout_index.len();
if target_len == 0 {
return Ok(());
}
@@ -42,14 +42,14 @@ impl Vecs {
}
// Pre-collect height-indexed data
let first_txoutindexes: Vec<TxOutIndex> =
indexer.vecs.outputs.first_txoutindex.collect_range_at(
let first_txout_indexes: Vec<TxOutIndex> =
indexer.vecs.outputs.first_txout_index.collect_range_at(
starting_height.to_usize(),
target_height.to_usize()
+ 2.min(indexer.vecs.outputs.first_txoutindex.len()),
+ 2.min(indexer.vecs.outputs.first_txout_index.len()),
);
let mut outputtypes_buf: Vec<OutputType> = Vec::new();
let mut output_types_buf: Vec<OutputType> = Vec::new();
let mut values_buf: Vec<Sats> = Vec::new();
// Iterate blocks
@@ -58,23 +58,23 @@ impl Vecs {
let local_idx = h - starting_height.to_usize();
// 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) {
let first_txout_index = first_txout_indexes[local_idx];
let next_first_txout_index =
if let Some(&next) = first_txout_indexes.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();
let out_start = first_txout_index.to_usize();
let out_end = next_first_txout_index.to_usize();
// Pre-collect both vecs into reusable buffers
indexer
.vecs
.outputs
.outputtype
.collect_range_into_at(out_start, out_end, &mut outputtypes_buf);
.output_type
.collect_range_into_at(out_start, out_end, &mut output_types_buf);
indexer
.vecs
.outputs
@@ -82,7 +82,7 @@ impl Vecs {
.collect_range_into_at(out_start, out_end, &mut values_buf);
let mut opreturn_value = Sats::ZERO;
for (ot, val) in outputtypes_buf.iter().zip(values_buf.iter()) {
for (ot, val) in output_types_buf.iter().zip(values_buf.iter()) {
if *ot == OutputType::OpReturn {
opreturn_value += *val;
}
@@ -19,7 +19,7 @@ impl Vecs {
.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.first_tx_index,
&indexer.vecs.transactions.txid,
exit,
)?)
@@ -14,16 +14,16 @@ impl Vecs {
indexes: &indexes::Vecs,
cached_starts: &CachedWindowStarts,
) -> Result<Self> {
let txindex_to_is_coinbase = LazyVecFrom2::init(
let tx_index_to_is_coinbase = LazyVecFrom2::init(
"is_coinbase",
version,
indexer.vecs.transactions.height.read_only_boxed_clone(),
indexer
.vecs
.transactions
.first_txindex
.first_tx_index
.read_only_boxed_clone(),
|index: TxIndex, _height, first_txindex| StoredBool::from(index == first_txindex),
|index: TxIndex, _height, first_tx_index| StoredBool::from(index == first_tx_index),
);
Ok(Self {
@@ -34,7 +34,7 @@ impl Vecs {
indexes,
cached_starts,
)?,
is_coinbase: txindex_to_is_coinbase,
is_coinbase: tx_index_to_is_coinbase,
})
}
}
@@ -19,23 +19,23 @@ impl Vecs {
exit: &Exit,
) -> Result<()> {
self.input_value.compute_sum_from_indexes(
starting_indexes.txindex,
&indexer.vecs.transactions.first_txinindex,
&indexes.txindex.input_count,
starting_indexes.tx_index,
&indexer.vecs.transactions.first_txin_index,
&indexes.tx_index.input_count,
&txins.spent.value,
exit,
)?;
self.output_value.compute_sum_from_indexes(
starting_indexes.txindex,
&indexer.vecs.transactions.first_txoutindex,
&indexes.txindex.output_count,
starting_indexes.tx_index,
&indexer.vecs.transactions.first_txout_index,
&indexes.tx_index.output_count,
&indexer.vecs.outputs.value,
exit,
)?;
self.fee.txindex.compute_transform2(
starting_indexes.txindex,
self.fee.tx_index.compute_transform2(
starting_indexes.tx_index,
&self.input_value,
&self.output_value,
|(i, input, output, ..)| {
@@ -49,11 +49,11 @@ impl Vecs {
exit,
)?;
self.fee_rate.txindex.compute_transform2(
starting_indexes.txindex,
&self.fee.txindex,
&size_vecs.vsize.txindex,
|(txindex, fee, vsize, ..)| (txindex, FeeRate::from((fee, vsize))),
self.fee_rate.tx_index.compute_transform2(
starting_indexes.tx_index,
&self.fee.tx_index,
&size_vecs.vsize.tx_index,
|(tx_index, fee, vsize, ..)| (tx_index, FeeRate::from((fee, vsize))),
exit,
)?;
@@ -12,7 +12,7 @@ impl Vecs {
version: Version,
indexer: &Indexer,
) -> Result<Self> {
let txindex_to_vsize = LazyVecFrom2::init(
let tx_index_to_vsize = LazyVecFrom2::init(
"tx_vsize",
version,
indexer.vecs.transactions.base_size.read_only_boxed_clone(),
@@ -23,9 +23,9 @@ impl Vecs {
);
let vsize =
LazyPerTxDistribution::forced_import(db, "tx_vsize", version, txindex_to_vsize)?;
LazyPerTxDistribution::forced_import(db, "tx_vsize", version, tx_index_to_vsize)?;
let txindex_to_weight = LazyVecFrom2::init(
let tx_index_to_weight = LazyVecFrom2::init(
"tx_weight",
version,
indexer.vecs.transactions.base_size.read_only_boxed_clone(),
@@ -36,7 +36,7 @@ impl Vecs {
let weight = LazyPerTxDistributionTransformed::new::<VSizeToWeight>(
"tx_weight",
version,
txindex_to_weight,
tx_index_to_weight,
&vsize.distribution,
);
@@ -14,20 +14,20 @@ impl Vecs {
exit: &Exit,
) -> Result<()> {
let tx_vany = |tx_vany: &mut PerBlockCumulativeWithSums<StoredU64, StoredU64>,
txversion: TxVersion| {
let txversion_vec = &indexer.vecs.transactions.txversion;
tx_version: TxVersion| {
let tx_version_vec = &indexer.vecs.transactions.tx_version;
// Cursor avoids per-transaction PcoVec page decompression.
// Txindex values are sequential, so the cursor only advances forward.
let mut cursor = txversion_vec.cursor();
let mut cursor = tx_version_vec.cursor();
tx_vany.compute(starting_indexes.height, exit, |vec| {
vec.compute_filtered_count_from_indexes(
starting_indexes.height,
&indexer.vecs.transactions.first_txindex,
&indexer.vecs.transactions.first_tx_index,
&indexer.vecs.transactions.txid,
|txindex| {
let ti = txindex.to_usize();
|tx_index| {
let ti = tx_index.to_usize();
cursor.advance(ti - cursor.position());
cursor.next().unwrap() == txversion
cursor.next().unwrap() == tx_version
},
exit,
)?;
@@ -29,8 +29,8 @@ impl Vecs {
|sats_vec| {
Ok(sats_vec.compute_filtered_sum_from_indexes(
starting_indexes.height,
&indexer.vecs.transactions.first_txindex,
&indexes.height.txindex_count,
&indexer.vecs.transactions.first_tx_index,
&indexes.height.tx_index_count,
&fees_vecs.input_value,
|sats| !sats.is_max(),
exit,
@@ -45,8 +45,8 @@ impl Vecs {
|sats_vec| {
Ok(sats_vec.compute_sum_from_indexes(
starting_indexes.height,
&indexer.vecs.transactions.first_txindex,
&indexes.height.txindex_count,
&indexer.vecs.transactions.first_tx_index,
&indexes.height.tx_index_count,
&fees_vecs.output_value,
exit,
)?)