mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-10 23:13:33 -07:00
global: renames part 2
This commit is contained in:
+426
-476
File diff suppressed because it is too large
Load Diff
@@ -14,23 +14,23 @@ pub fn main() -> Result<()> {
|
||||
|
||||
let computer = Computer::forced_import(&outputs_dir, &indexer)?;
|
||||
|
||||
// Test emptyaddressdata (underlying BytesVec) - direct access
|
||||
// Test empty_address_data (underlying BytesVec) - direct access
|
||||
let empty_data = &computer.distribution.addresses_data.empty;
|
||||
println!("emptyaddressdata (BytesVec) len: {}", empty_data.len());
|
||||
println!("empty_address_data (BytesVec) len: {}", empty_data.len());
|
||||
|
||||
let start = Instant::now();
|
||||
let mut buf = Vec::new();
|
||||
empty_data.write_json(Some(empty_data.len() - 1), Some(empty_data.len()), &mut buf)?;
|
||||
println!(
|
||||
"emptyaddressdata last item JSON: {}",
|
||||
"empty_address_data last item JSON: {}",
|
||||
String::from_utf8_lossy(&buf)
|
||||
);
|
||||
println!("Time for BytesVec write_json: {:?}", start.elapsed());
|
||||
|
||||
// Test emptyaddressindex (LazyVecFrom1 wrapper) - computed access
|
||||
// Test empty_address_index (LazyVecFrom1 wrapper) - computed access
|
||||
let empty_index = &computer.distribution.addresses.empty_index;
|
||||
println!(
|
||||
"\nemptyaddressindex (LazyVecFrom1) len: {}",
|
||||
"\nempty_address_index (LazyVecFrom1) len: {}",
|
||||
empty_index.len()
|
||||
);
|
||||
|
||||
@@ -42,14 +42,14 @@ pub fn main() -> Result<()> {
|
||||
&mut buf,
|
||||
)?;
|
||||
println!(
|
||||
"emptyaddressindex last item JSON: {}",
|
||||
"empty_address_index last item JSON: {}",
|
||||
String::from_utf8_lossy(&buf)
|
||||
);
|
||||
println!("Time for LazyVecFrom1 write_json: {:?}", start.elapsed());
|
||||
|
||||
// Compare with funded versions
|
||||
let funded_data = &computer.distribution.addresses_data.funded;
|
||||
println!("\nfundedaddressdata (BytesVec) len: {}", funded_data.len());
|
||||
println!("\nfunded_address_data (BytesVec) len: {}", funded_data.len());
|
||||
|
||||
let start = Instant::now();
|
||||
let mut buf = Vec::new();
|
||||
@@ -59,7 +59,7 @@ pub fn main() -> Result<()> {
|
||||
&mut buf,
|
||||
)?;
|
||||
println!(
|
||||
"fundedaddressdata last item JSON: {}",
|
||||
"funded_address_data last item JSON: {}",
|
||||
String::from_utf8_lossy(&buf)
|
||||
);
|
||||
println!("Time for BytesVec write_json: {:?}", start.elapsed());
|
||||
|
||||
@@ -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
@@ -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,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)?;
|
||||
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
)?;
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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)?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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>>,
|
||||
}
|
||||
|
||||
@@ -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))),
|
||||
|
||||
@@ -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(())
|
||||
},
|
||||
)?;
|
||||
|
||||
@@ -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,
|
||||
)?)
|
||||
|
||||
@@ -9,7 +9,7 @@ pub const SNAPSHOT_BLOCK_RANGE: usize = 1_000;
|
||||
|
||||
/// Known duplicate Bitcoin transactions (BIP30)
|
||||
/// https://github.com/bitcoin/bips/blob/master/bip-0030.mediawiki
|
||||
/// Each entry is (txid_str, txindex) - these are coinbase txs that were duplicated.
|
||||
/// Each entry is (txid_str, tx_index) - these are coinbase txs that were duplicated.
|
||||
pub const DUPLICATE_TXID_STRS: [(&str, u32); 2] = [
|
||||
(
|
||||
"d5d27987d2a3dfc724e359870c6644b40e497bdc0589a033220fe15429d88599",
|
||||
@@ -34,10 +34,10 @@ pub static DUPLICATE_TXIDS: std::sync::LazyLock<[Txid; 2]> = std::sync::LazyLock
|
||||
|
||||
pub static DUPLICATE_TXID_PREFIXES: std::sync::LazyLock<[(TxidPrefix, TxIndex); 2]> =
|
||||
std::sync::LazyLock::new(|| {
|
||||
DUPLICATE_TXID_STRS.map(|(s, txindex)| {
|
||||
DUPLICATE_TXID_STRS.map(|(s, tx_index)| {
|
||||
(
|
||||
TxidPrefix::from(&Txid::from(bitcoin::Txid::from_str(s).unwrap())),
|
||||
TxIndex::new(txindex),
|
||||
TxIndex::new(tx_index),
|
||||
)
|
||||
})
|
||||
});
|
||||
|
||||
@@ -21,50 +21,50 @@ impl IndexesExt for Indexes {
|
||||
fn checked_push(&self, vecs: &mut Vecs) -> Result<()> {
|
||||
let height = self.height;
|
||||
vecs.transactions
|
||||
.first_txindex
|
||||
.checked_push(height, self.txindex)?;
|
||||
.first_tx_index
|
||||
.checked_push(height, self.tx_index)?;
|
||||
vecs.inputs
|
||||
.first_txinindex
|
||||
.checked_push(height, self.txinindex)?;
|
||||
.first_txin_index
|
||||
.checked_push(height, self.txin_index)?;
|
||||
vecs.outputs
|
||||
.first_txoutindex
|
||||
.checked_push(height, self.txoutindex)?;
|
||||
.first_txout_index
|
||||
.checked_push(height, self.txout_index)?;
|
||||
vecs.scripts
|
||||
.empty.first_index
|
||||
.checked_push(height, self.emptyoutputindex)?;
|
||||
.checked_push(height, self.empty_output_index)?;
|
||||
vecs.scripts
|
||||
.p2ms.first_index
|
||||
.checked_push(height, self.p2msoutputindex)?;
|
||||
.checked_push(height, self.p2ms_output_index)?;
|
||||
vecs.scripts
|
||||
.opreturn.first_index
|
||||
.checked_push(height, self.opreturnindex)?;
|
||||
.checked_push(height, self.op_return_index)?;
|
||||
vecs.addresses
|
||||
.p2a.first_index
|
||||
.checked_push(height, self.p2aaddressindex)?;
|
||||
.checked_push(height, self.p2a_address_index)?;
|
||||
vecs.scripts
|
||||
.unknown.first_index
|
||||
.checked_push(height, self.unknownoutputindex)?;
|
||||
.checked_push(height, self.unknown_output_index)?;
|
||||
vecs.addresses
|
||||
.p2pk33.first_index
|
||||
.checked_push(height, self.p2pk33addressindex)?;
|
||||
.checked_push(height, self.p2pk33_address_index)?;
|
||||
vecs.addresses
|
||||
.p2pk65.first_index
|
||||
.checked_push(height, self.p2pk65addressindex)?;
|
||||
.checked_push(height, self.p2pk65_address_index)?;
|
||||
vecs.addresses
|
||||
.p2pkh.first_index
|
||||
.checked_push(height, self.p2pkhaddressindex)?;
|
||||
.checked_push(height, self.p2pkh_address_index)?;
|
||||
vecs.addresses
|
||||
.p2sh.first_index
|
||||
.checked_push(height, self.p2shaddressindex)?;
|
||||
.checked_push(height, self.p2sh_address_index)?;
|
||||
vecs.addresses
|
||||
.p2tr.first_index
|
||||
.checked_push(height, self.p2traddressindex)?;
|
||||
.checked_push(height, self.p2tr_address_index)?;
|
||||
vecs.addresses
|
||||
.p2wpkh.first_index
|
||||
.checked_push(height, self.p2wpkhaddressindex)?;
|
||||
.checked_push(height, self.p2wpkh_address_index)?;
|
||||
vecs.addresses
|
||||
.p2wsh.first_index
|
||||
.checked_push(height, self.p2wshaddressindex)?;
|
||||
.checked_push(height, self.p2wsh_address_index)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -97,113 +97,113 @@ impl IndexesExt for Indexes {
|
||||
local_height
|
||||
};
|
||||
|
||||
let emptyoutputindex = starting_index(
|
||||
let empty_output_index = starting_index(
|
||||
&vecs.scripts.empty.first_index,
|
||||
&vecs.scripts.empty.to_txindex,
|
||||
&vecs.scripts.empty.to_tx_index,
|
||||
starting_height,
|
||||
)?;
|
||||
|
||||
let p2msoutputindex = starting_index(
|
||||
let p2ms_output_index = starting_index(
|
||||
&vecs.scripts.p2ms.first_index,
|
||||
&vecs.scripts.p2ms.to_txindex,
|
||||
&vecs.scripts.p2ms.to_tx_index,
|
||||
starting_height,
|
||||
)?;
|
||||
|
||||
let opreturnindex = starting_index(
|
||||
let op_return_index = starting_index(
|
||||
&vecs.scripts.opreturn.first_index,
|
||||
&vecs.scripts.opreturn.to_txindex,
|
||||
&vecs.scripts.opreturn.to_tx_index,
|
||||
starting_height,
|
||||
)?;
|
||||
|
||||
let p2pk33addressindex = starting_index(
|
||||
let p2pk33_address_index = starting_index(
|
||||
&vecs.addresses.p2pk33.first_index,
|
||||
&vecs.addresses.p2pk33.bytes,
|
||||
starting_height,
|
||||
)?;
|
||||
|
||||
let p2pk65addressindex = starting_index(
|
||||
let p2pk65_address_index = starting_index(
|
||||
&vecs.addresses.p2pk65.first_index,
|
||||
&vecs.addresses.p2pk65.bytes,
|
||||
starting_height,
|
||||
)?;
|
||||
|
||||
let p2pkhaddressindex = starting_index(
|
||||
let p2pkh_address_index = starting_index(
|
||||
&vecs.addresses.p2pkh.first_index,
|
||||
&vecs.addresses.p2pkh.bytes,
|
||||
starting_height,
|
||||
)?;
|
||||
|
||||
let p2shaddressindex = starting_index(
|
||||
let p2sh_address_index = starting_index(
|
||||
&vecs.addresses.p2sh.first_index,
|
||||
&vecs.addresses.p2sh.bytes,
|
||||
starting_height,
|
||||
)?;
|
||||
|
||||
let p2traddressindex = starting_index(
|
||||
let p2tr_address_index = starting_index(
|
||||
&vecs.addresses.p2tr.first_index,
|
||||
&vecs.addresses.p2tr.bytes,
|
||||
starting_height,
|
||||
)?;
|
||||
|
||||
let p2wpkhaddressindex = starting_index(
|
||||
let p2wpkh_address_index = starting_index(
|
||||
&vecs.addresses.p2wpkh.first_index,
|
||||
&vecs.addresses.p2wpkh.bytes,
|
||||
starting_height,
|
||||
)?;
|
||||
|
||||
let p2wshaddressindex = starting_index(
|
||||
let p2wsh_address_index = starting_index(
|
||||
&vecs.addresses.p2wsh.first_index,
|
||||
&vecs.addresses.p2wsh.bytes,
|
||||
starting_height,
|
||||
)?;
|
||||
|
||||
let p2aaddressindex = starting_index(
|
||||
let p2a_address_index = starting_index(
|
||||
&vecs.addresses.p2a.first_index,
|
||||
&vecs.addresses.p2a.bytes,
|
||||
starting_height,
|
||||
)?;
|
||||
|
||||
let txindex = starting_index(
|
||||
&vecs.transactions.first_txindex,
|
||||
let tx_index = starting_index(
|
||||
&vecs.transactions.first_tx_index,
|
||||
&vecs.transactions.txid,
|
||||
starting_height,
|
||||
)?;
|
||||
|
||||
let txinindex = starting_index(
|
||||
&vecs.inputs.first_txinindex,
|
||||
let txin_index = starting_index(
|
||||
&vecs.inputs.first_txin_index,
|
||||
&vecs.inputs.outpoint,
|
||||
starting_height,
|
||||
)?;
|
||||
|
||||
let txoutindex = starting_index(
|
||||
&vecs.outputs.first_txoutindex,
|
||||
let txout_index = starting_index(
|
||||
&vecs.outputs.first_txout_index,
|
||||
&vecs.outputs.value,
|
||||
starting_height,
|
||||
)?;
|
||||
|
||||
let unknownoutputindex = starting_index(
|
||||
let unknown_output_index = starting_index(
|
||||
&vecs.scripts.unknown.first_index,
|
||||
&vecs.scripts.unknown.to_txindex,
|
||||
&vecs.scripts.unknown.to_tx_index,
|
||||
starting_height,
|
||||
)?;
|
||||
|
||||
Some(Indexes {
|
||||
emptyoutputindex,
|
||||
empty_output_index,
|
||||
height: starting_height,
|
||||
p2msoutputindex,
|
||||
opreturnindex,
|
||||
p2pk33addressindex,
|
||||
p2pk65addressindex,
|
||||
p2pkhaddressindex,
|
||||
p2shaddressindex,
|
||||
p2traddressindex,
|
||||
p2wpkhaddressindex,
|
||||
p2wshaddressindex,
|
||||
p2aaddressindex,
|
||||
txindex,
|
||||
txinindex,
|
||||
txoutindex,
|
||||
unknownoutputindex,
|
||||
p2ms_output_index,
|
||||
op_return_index,
|
||||
p2pk33_address_index,
|
||||
p2pk65_address_index,
|
||||
p2pkh_address_index,
|
||||
p2sh_address_index,
|
||||
p2tr_address_index,
|
||||
p2wpkh_address_index,
|
||||
p2wsh_address_index,
|
||||
p2a_address_index,
|
||||
tx_index,
|
||||
txin_index,
|
||||
txout_index,
|
||||
unknown_output_index,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ impl BlockProcessor<'_> {
|
||||
|
||||
if self
|
||||
.stores
|
||||
.blockhashprefix_to_height
|
||||
.blockhash_prefix_to_height
|
||||
.get(&blockhash_prefix)?
|
||||
.is_some_and(|prev_height| *prev_height != height)
|
||||
{
|
||||
@@ -25,7 +25,7 @@ impl BlockProcessor<'_> {
|
||||
self.indexes.checked_push(self.vecs)?;
|
||||
|
||||
self.stores
|
||||
.blockhashprefix_to_height
|
||||
.blockhash_prefix_to_height
|
||||
.insert(blockhash_prefix, height);
|
||||
|
||||
self.stores
|
||||
|
||||
@@ -27,9 +27,9 @@ pub struct BlockProcessor<'a> {
|
||||
impl BlockProcessor<'_> {
|
||||
/// Update global indexes after processing a block.
|
||||
pub fn update_indexes(&mut self, tx_count: usize, input_count: usize, output_count: usize) {
|
||||
self.indexes.txindex += TxIndex::from(tx_count);
|
||||
self.indexes.txinindex += TxInIndex::from(input_count);
|
||||
self.indexes.txoutindex += TxOutIndex::from(output_count);
|
||||
self.indexes.tx_index += TxIndex::from(tx_count);
|
||||
self.indexes.txin_index += TxInIndex::from(input_count);
|
||||
self.indexes.txout_index += TxOutIndex::from(output_count);
|
||||
}
|
||||
|
||||
/// Finalizes outputs/inputs in parallel with storing tx metadata.
|
||||
@@ -46,8 +46,8 @@ impl BlockProcessor<'_> {
|
||||
let height = self.height;
|
||||
let indexes = &mut *self.indexes;
|
||||
|
||||
// Split transactions vecs: finalize needs first_txoutindex/first_txinindex, metadata needs the rest
|
||||
let (first_txoutindex, first_txinindex, mut tx_metadata) =
|
||||
// Split transactions vecs: finalize needs first_txout_index/first_txin_index, metadata needs the rest
|
||||
let (first_txout_index, first_txin_index, mut tx_metadata) =
|
||||
self.vecs.transactions.split_for_finalize();
|
||||
|
||||
let outputs = &mut self.vecs.outputs;
|
||||
@@ -55,21 +55,21 @@ impl BlockProcessor<'_> {
|
||||
let addresses = &mut self.vecs.addresses;
|
||||
let scripts = &mut self.vecs.scripts;
|
||||
|
||||
let addr_hash_stores = &mut self.stores.addresstype_to_addresshash_to_addressindex;
|
||||
let addr_txindex_stores = &mut self.stores.addresstype_to_addressindex_and_txindex;
|
||||
let addr_outpoint_stores = &mut self.stores.addresstype_to_addressindex_and_unspentoutpoint;
|
||||
let txidprefix_store = &mut self.stores.txidprefix_to_txindex;
|
||||
let addr_hash_stores = &mut self.stores.address_type_to_address_hash_to_address_index;
|
||||
let addr_tx_index_stores = &mut self.stores.address_type_to_address_index_and_tx_index;
|
||||
let addr_outpoint_stores = &mut self.stores.address_type_to_address_index_and_unspent_outpoint;
|
||||
let txid_prefix_store = &mut self.stores.txid_prefix_to_tx_index;
|
||||
|
||||
let (finalize_result, metadata_result) = rayon::join(
|
||||
|| -> Result<()> {
|
||||
txout::finalize_outputs(
|
||||
indexes,
|
||||
first_txoutindex,
|
||||
first_txout_index,
|
||||
outputs,
|
||||
addresses,
|
||||
scripts,
|
||||
addr_hash_stores,
|
||||
addr_txindex_stores,
|
||||
addr_tx_index_stores,
|
||||
addr_outpoint_stores,
|
||||
txouts,
|
||||
same_block_spent_outpoints,
|
||||
@@ -77,15 +77,15 @@ impl BlockProcessor<'_> {
|
||||
same_block_info,
|
||||
)?;
|
||||
txin::finalize_inputs(
|
||||
first_txinindex,
|
||||
first_txin_index,
|
||||
inputs,
|
||||
addr_txindex_stores,
|
||||
addr_tx_index_stores,
|
||||
addr_outpoint_stores,
|
||||
txins,
|
||||
same_block_info,
|
||||
)
|
||||
},
|
||||
|| tx::store_tx_metadata(height, txs, txidprefix_store, &mut tx_metadata),
|
||||
|| tx::store_tx_metadata(height, txs, txid_prefix_store, &mut tx_metadata),
|
||||
);
|
||||
|
||||
finalize_result?;
|
||||
|
||||
@@ -13,7 +13,7 @@ use super::{BlockProcessor, ComputedTx};
|
||||
impl<'a> BlockProcessor<'a> {
|
||||
pub fn compute_txids(&self) -> Result<Vec<ComputedTx<'a>>> {
|
||||
let will_check_collisions = self.check_collisions;
|
||||
let base_txindex = self.indexes.txindex;
|
||||
let base_tx_index = self.indexes.tx_index;
|
||||
|
||||
self.block
|
||||
.txdata
|
||||
@@ -24,9 +24,9 @@ impl<'a> BlockProcessor<'a> {
|
||||
let txid = Txid::from(btc_txid);
|
||||
let txid_prefix = TxidPrefix::from(&txid);
|
||||
|
||||
let prev_txindex_opt = if will_check_collisions {
|
||||
let prev_tx_index_opt = if will_check_collisions {
|
||||
self.stores
|
||||
.txidprefix_to_txindex
|
||||
.txid_prefix_to_tx_index
|
||||
.get(&txid_prefix)?
|
||||
.map(|v| *v)
|
||||
} else {
|
||||
@@ -34,11 +34,11 @@ impl<'a> BlockProcessor<'a> {
|
||||
};
|
||||
|
||||
Ok(ComputedTx {
|
||||
txindex: base_txindex + TxIndex::from(index),
|
||||
tx_index: base_tx_index + TxIndex::from(index),
|
||||
tx,
|
||||
txid,
|
||||
txid_prefix,
|
||||
prev_txindex_opt,
|
||||
prev_tx_index_opt,
|
||||
base_size,
|
||||
total_size,
|
||||
})
|
||||
@@ -53,11 +53,11 @@ impl<'a> BlockProcessor<'a> {
|
||||
}
|
||||
|
||||
for ct in txs.iter() {
|
||||
let Some(prev_txindex) = ct.prev_txindex_opt else {
|
||||
let Some(prev_tx_index) = ct.prev_tx_index_opt else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if ct.txindex == prev_txindex {
|
||||
if ct.tx_index == prev_tx_index {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -66,18 +66,18 @@ impl<'a> BlockProcessor<'a> {
|
||||
.vecs
|
||||
.transactions
|
||||
.txid
|
||||
.get_pushed_or_read(prev_txindex, &self.readers.txid)
|
||||
.ok_or(Error::Internal("Missing txid for txindex"))
|
||||
.get_pushed_or_read(prev_tx_index, &self.readers.txid)
|
||||
.ok_or(Error::Internal("Missing txid for tx_index"))
|
||||
.inspect_err(|_| {
|
||||
error!(txindex = ?ct.txindex, len, "Missing txid for txindex");
|
||||
error!(tx_index = ?ct.tx_index, len, "Missing txid for tx_index");
|
||||
})?;
|
||||
|
||||
let is_dup = DUPLICATE_TXIDS.contains(&prev_txid);
|
||||
|
||||
if !is_dup {
|
||||
error!(
|
||||
height = ?self.height, txindex = ?ct.txindex,
|
||||
?prev_txid, ?prev_txindex,
|
||||
height = ?self.height, tx_index = ?ct.tx_index,
|
||||
?prev_txid, ?prev_tx_index,
|
||||
"Unexpected TXID collision"
|
||||
);
|
||||
return Err(Error::Internal("Unexpected TXID collision"));
|
||||
@@ -95,20 +95,20 @@ pub(super) fn store_tx_metadata(
|
||||
md: &mut TxMetadataVecs<'_>,
|
||||
) -> Result<()> {
|
||||
for ct in txs {
|
||||
if ct.prev_txindex_opt.is_none() {
|
||||
store.insert(ct.txid_prefix, ct.txindex);
|
||||
if ct.prev_tx_index_opt.is_none() {
|
||||
store.insert(ct.txid_prefix, ct.tx_index);
|
||||
}
|
||||
md.height.checked_push(ct.txindex, height)?;
|
||||
md.txversion
|
||||
.checked_push(ct.txindex, ct.tx.version.into())?;
|
||||
md.txid.checked_push(ct.txindex, ct.txid)?;
|
||||
md.rawlocktime
|
||||
.checked_push(ct.txindex, ct.tx.lock_time.into())?;
|
||||
md.base_size.checked_push(ct.txindex, ct.base_size.into())?;
|
||||
md.height.checked_push(ct.tx_index, height)?;
|
||||
md.tx_version
|
||||
.checked_push(ct.tx_index, ct.tx.version.into())?;
|
||||
md.txid.checked_push(ct.tx_index, ct.txid)?;
|
||||
md.raw_locktime
|
||||
.checked_push(ct.tx_index, ct.tx.lock_time.into())?;
|
||||
md.base_size.checked_push(ct.tx_index, ct.base_size.into())?;
|
||||
md.total_size
|
||||
.checked_push(ct.txindex, ct.total_size.into())?;
|
||||
.checked_push(ct.tx_index, ct.total_size.into())?;
|
||||
md.is_explicitly_rbf
|
||||
.checked_push(ct.txindex, StoredBool::from(ct.tx.is_explicitly_rbf()))?;
|
||||
.checked_push(ct.tx_index, StoredBool::from(ct.tx.is_explicitly_rbf()))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -17,13 +17,13 @@ impl<'a> BlockProcessor<'a> {
|
||||
pub fn process_inputs(
|
||||
&self,
|
||||
txs: &[ComputedTx],
|
||||
txid_prefix_to_txindex: &mut FxHashMap<TxidPrefix, TxIndex>,
|
||||
txid_prefix_to_tx_index: &mut FxHashMap<TxidPrefix, TxIndex>,
|
||||
) -> Result<Vec<(TxInIndex, InputSource)>> {
|
||||
txid_prefix_to_txindex.clear();
|
||||
txid_prefix_to_txindex.extend(txs.iter().map(|ct| (ct.txid_prefix, ct.txindex)));
|
||||
txid_prefix_to_tx_index.clear();
|
||||
txid_prefix_to_tx_index.extend(txs.iter().map(|ct| (ct.txid_prefix, ct.tx_index)));
|
||||
|
||||
let base_txindex = self.indexes.txindex;
|
||||
let base_txinindex = self.indexes.txinindex;
|
||||
let base_tx_index = self.indexes.tx_index;
|
||||
let base_txin_index = self.indexes.txin_index;
|
||||
|
||||
let total_inputs: usize = self.block.txdata.iter().map(|tx| tx.input.len()).sum();
|
||||
let mut items = Vec::with_capacity(total_inputs);
|
||||
@@ -33,21 +33,21 @@ impl<'a> BlockProcessor<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
let txid_prefix_to_txindex = &*txid_prefix_to_txindex;
|
||||
let txid_prefix_to_tx_index = &*txid_prefix_to_tx_index;
|
||||
|
||||
let txins = items
|
||||
.into_par_iter()
|
||||
.enumerate()
|
||||
.map(
|
||||
|(block_txinindex, (block_txindex, vin, txin, tx))| -> Result<(TxInIndex, InputSource)> {
|
||||
let txindex = base_txindex + block_txindex;
|
||||
let txinindex = base_txinindex + TxInIndex::from(block_txinindex);
|
||||
|(block_txin_index, (block_tx_index, vin, txin, tx))| -> Result<(TxInIndex, InputSource)> {
|
||||
let tx_index = base_tx_index + block_tx_index;
|
||||
let txin_index = base_txin_index + TxInIndex::from(block_txin_index);
|
||||
|
||||
if tx.is_coinbase() {
|
||||
return Ok((
|
||||
txinindex,
|
||||
txin_index,
|
||||
InputSource::SameBlock {
|
||||
txindex,
|
||||
tx_index,
|
||||
vin,
|
||||
outpoint: OutPoint::COINBASE,
|
||||
},
|
||||
@@ -59,13 +59,13 @@ impl<'a> BlockProcessor<'a> {
|
||||
let txid_prefix = TxidPrefix::from(&txid);
|
||||
let vout = Vout::from(outpoint.vout);
|
||||
|
||||
if let Some(&same_block_txindex) = txid_prefix_to_txindex
|
||||
if let Some(&same_block_tx_index) = txid_prefix_to_tx_index
|
||||
.get(&txid_prefix) {
|
||||
let outpoint = OutPoint::new(same_block_txindex, vout);
|
||||
let outpoint = OutPoint::new(same_block_tx_index, vout);
|
||||
return Ok((
|
||||
txinindex,
|
||||
txin_index,
|
||||
InputSource::SameBlock {
|
||||
txindex,
|
||||
tx_index,
|
||||
vin,
|
||||
outpoint,
|
||||
},
|
||||
@@ -74,53 +74,53 @@ impl<'a> BlockProcessor<'a> {
|
||||
|
||||
let store_result = self
|
||||
.stores
|
||||
.txidprefix_to_txindex
|
||||
.txid_prefix_to_tx_index
|
||||
.get(&txid_prefix)?
|
||||
.map(|v| *v);
|
||||
|
||||
let prev_txindex = match store_result {
|
||||
Some(txindex) if txindex < self.indexes.txindex => txindex,
|
||||
let prev_tx_index = match store_result {
|
||||
Some(tx_index) if tx_index < self.indexes.tx_index => tx_index,
|
||||
_ => {
|
||||
error!(
|
||||
"UnknownTxid: txid={}, prefix={:?}, store_result={:?}, current_txindex={:?}",
|
||||
txid, txid_prefix, store_result, self.indexes.txindex
|
||||
"UnknownTxid: txid={}, prefix={:?}, store_result={:?}, current_tx_index={:?}",
|
||||
txid, txid_prefix, store_result, self.indexes.tx_index
|
||||
);
|
||||
return Err(Error::UnknownTxid);
|
||||
}
|
||||
};
|
||||
|
||||
let txoutindex = self
|
||||
let txout_index = self
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txoutindex
|
||||
.get_pushed_or_read(prev_txindex, &self.readers.txindex_to_first_txoutindex)
|
||||
.ok_or(Error::Internal("Missing txoutindex"))?
|
||||
.first_txout_index
|
||||
.get_pushed_or_read(prev_tx_index, &self.readers.tx_index_to_first_txout_index)
|
||||
.ok_or(Error::Internal("Missing txout_index"))?
|
||||
+ vout;
|
||||
|
||||
let outpoint = OutPoint::new(prev_txindex, vout);
|
||||
let outpoint = OutPoint::new(prev_tx_index, vout);
|
||||
|
||||
let outputtype = self
|
||||
let output_type = self
|
||||
.vecs
|
||||
.outputs
|
||||
.outputtype
|
||||
.get_pushed_or_read(txoutindex, &self.readers.txoutindex_to_outputtype)
|
||||
.ok_or(Error::Internal("Missing outputtype"))?;
|
||||
.output_type
|
||||
.get_pushed_or_read(txout_index, &self.readers.txout_index_to_output_type)
|
||||
.ok_or(Error::Internal("Missing output_type"))?;
|
||||
|
||||
let typeindex = self
|
||||
let type_index = self
|
||||
.vecs
|
||||
.outputs
|
||||
.typeindex
|
||||
.get_pushed_or_read(txoutindex, &self.readers.txoutindex_to_typeindex)
|
||||
.ok_or(Error::Internal("Missing typeindex"))?;
|
||||
.type_index
|
||||
.get_pushed_or_read(txout_index, &self.readers.txout_index_to_type_index)
|
||||
.ok_or(Error::Internal("Missing type_index"))?;
|
||||
|
||||
Ok((
|
||||
txinindex,
|
||||
txin_index,
|
||||
InputSource::PreviousBlock {
|
||||
vin,
|
||||
txindex,
|
||||
tx_index,
|
||||
outpoint,
|
||||
outputtype,
|
||||
typeindex,
|
||||
output_type,
|
||||
type_index,
|
||||
},
|
||||
))
|
||||
},
|
||||
@@ -149,31 +149,31 @@ impl<'a> BlockProcessor<'a> {
|
||||
}
|
||||
|
||||
pub(super) fn finalize_inputs(
|
||||
first_txinindex: &mut PcoVec<TxIndex, TxInIndex>,
|
||||
first_txin_index: &mut PcoVec<TxIndex, TxInIndex>,
|
||||
inputs: &mut InputsVecs,
|
||||
addr_txindex_stores: &mut ByAddressType<Store<AddressIndexTxIndex, Unit>>,
|
||||
addr_tx_index_stores: &mut ByAddressType<Store<AddressIndexTxIndex, Unit>>,
|
||||
addr_outpoint_stores: &mut ByAddressType<Store<AddressIndexOutPoint, Unit>>,
|
||||
txins: Vec<(TxInIndex, InputSource)>,
|
||||
same_block_output_info: &mut FxHashMap<OutPoint, SameBlockOutputInfo>,
|
||||
) -> Result<()> {
|
||||
for (txinindex, input_source) in txins {
|
||||
let (vin, txindex, outpoint, outputtype, typeindex) = match input_source {
|
||||
for (txin_index, input_source) in txins {
|
||||
let (vin, tx_index, outpoint, output_type, type_index) = match input_source {
|
||||
InputSource::PreviousBlock {
|
||||
vin,
|
||||
txindex,
|
||||
tx_index,
|
||||
outpoint,
|
||||
outputtype,
|
||||
typeindex,
|
||||
} => (vin, txindex, outpoint, outputtype, typeindex),
|
||||
output_type,
|
||||
type_index,
|
||||
} => (vin, tx_index, outpoint, output_type, type_index),
|
||||
InputSource::SameBlock {
|
||||
txindex,
|
||||
tx_index,
|
||||
vin,
|
||||
outpoint,
|
||||
} => {
|
||||
if outpoint.is_coinbase() {
|
||||
(
|
||||
vin,
|
||||
txindex,
|
||||
tx_index,
|
||||
outpoint,
|
||||
OutputType::Unknown,
|
||||
TypeIndex::COINBASE,
|
||||
@@ -189,33 +189,33 @@ pub(super) fn finalize_inputs(
|
||||
"Same-block output not found"
|
||||
);
|
||||
})?;
|
||||
(vin, txindex, outpoint, info.outputtype, info.typeindex)
|
||||
(vin, tx_index, outpoint, info.output_type, info.type_index)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if vin.is_zero() {
|
||||
first_txinindex.checked_push(txindex, txinindex)?;
|
||||
first_txin_index.checked_push(tx_index, txin_index)?;
|
||||
}
|
||||
|
||||
inputs.txindex.checked_push(txinindex, txindex)?;
|
||||
inputs.outpoint.checked_push(txinindex, outpoint)?;
|
||||
inputs.outputtype.checked_push(txinindex, outputtype)?;
|
||||
inputs.typeindex.checked_push(txinindex, typeindex)?;
|
||||
inputs.tx_index.checked_push(txin_index, tx_index)?;
|
||||
inputs.outpoint.checked_push(txin_index, outpoint)?;
|
||||
inputs.output_type.checked_push(txin_index, output_type)?;
|
||||
inputs.type_index.checked_push(txin_index, type_index)?;
|
||||
|
||||
if !outputtype.is_address() {
|
||||
if !output_type.is_address() {
|
||||
continue;
|
||||
}
|
||||
let addresstype = outputtype;
|
||||
let addressindex = typeindex;
|
||||
let address_type = output_type;
|
||||
let address_index = type_index;
|
||||
|
||||
addr_txindex_stores
|
||||
.get_mut_unwrap(addresstype)
|
||||
.insert(AddressIndexTxIndex::from((addressindex, txindex)), Unit);
|
||||
addr_tx_index_stores
|
||||
.get_mut_unwrap(address_type)
|
||||
.insert(AddressIndexTxIndex::from((address_index, tx_index)), Unit);
|
||||
|
||||
addr_outpoint_stores
|
||||
.get_mut_unwrap(addresstype)
|
||||
.remove(AddressIndexOutPoint::from((addressindex, outpoint)));
|
||||
.get_mut_unwrap(address_type)
|
||||
.remove(AddressIndexOutPoint::from((address_index, outpoint)));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -18,8 +18,8 @@ impl<'a> BlockProcessor<'a> {
|
||||
let height = self.height;
|
||||
let check_collisions = self.check_collisions;
|
||||
|
||||
let base_txindex = self.indexes.txindex;
|
||||
let base_txoutindex = self.indexes.txoutindex;
|
||||
let base_tx_index = self.indexes.tx_index;
|
||||
let base_txout_index = self.indexes.txout_index;
|
||||
|
||||
let total_outputs: usize = self.block.txdata.iter().map(|tx| tx.output.len()).sum();
|
||||
let mut items = Vec::with_capacity(total_outputs);
|
||||
@@ -33,56 +33,56 @@ impl<'a> BlockProcessor<'a> {
|
||||
.into_par_iter()
|
||||
.enumerate()
|
||||
.map(
|
||||
|(block_txoutindex, (block_txindex, vout, txout))| -> Result<ProcessedOutput> {
|
||||
let txindex = base_txindex + block_txindex;
|
||||
let txoutindex = base_txoutindex + TxOutIndex::from(block_txoutindex);
|
||||
|(block_txout_index, (block_tx_index, vout, txout))| -> Result<ProcessedOutput> {
|
||||
let tx_index = base_tx_index + block_tx_index;
|
||||
let txout_index = base_txout_index + TxOutIndex::from(block_txout_index);
|
||||
|
||||
let script = &txout.script_pubkey;
|
||||
let outputtype = OutputType::from(script);
|
||||
let output_type = OutputType::from(script);
|
||||
|
||||
if outputtype.is_not_address() {
|
||||
if output_type.is_not_address() {
|
||||
return Ok(ProcessedOutput {
|
||||
txoutindex,
|
||||
txout_index,
|
||||
txout,
|
||||
txindex,
|
||||
tx_index,
|
||||
vout,
|
||||
outputtype,
|
||||
output_type,
|
||||
address_info: None,
|
||||
existing_typeindex: None,
|
||||
existing_type_index: None,
|
||||
});
|
||||
}
|
||||
|
||||
let addresstype = outputtype;
|
||||
let address_bytes = AddressBytes::try_from((script, addresstype)).unwrap();
|
||||
let address_type = output_type;
|
||||
let address_bytes = AddressBytes::try_from((script, address_type)).unwrap();
|
||||
let address_hash = AddressHash::from(&address_bytes);
|
||||
|
||||
let existing_typeindex = self
|
||||
let existing_type_index = self
|
||||
.stores
|
||||
.addresstype_to_addresshash_to_addressindex
|
||||
.get_unwrap(addresstype)
|
||||
.address_type_to_address_hash_to_address_index
|
||||
.get_unwrap(address_type)
|
||||
.get(&address_hash)?
|
||||
.map(|v| *v)
|
||||
.and_then(|typeindex_local| {
|
||||
(typeindex_local < self.indexes.to_typeindex(addresstype))
|
||||
.then_some(typeindex_local)
|
||||
.and_then(|type_index_local| {
|
||||
(type_index_local < self.indexes.to_type_index(address_type))
|
||||
.then_some(type_index_local)
|
||||
});
|
||||
|
||||
if check_collisions && let Some(typeindex) = existing_typeindex {
|
||||
if check_collisions && let Some(type_index) = existing_type_index {
|
||||
let prev_addressbytes = self
|
||||
.vecs
|
||||
.addresses
|
||||
.get_bytes_by_type(addresstype, typeindex, &self.readers.addressbytes)
|
||||
.get_bytes_by_type(address_type, type_index, &self.readers.addressbytes)
|
||||
.ok_or(Error::Internal("Missing addressbytes"))?;
|
||||
|
||||
if prev_addressbytes != address_bytes {
|
||||
error!(
|
||||
?height,
|
||||
?vout,
|
||||
?block_txindex,
|
||||
?addresstype,
|
||||
?block_tx_index,
|
||||
?address_type,
|
||||
?prev_addressbytes,
|
||||
?address_bytes,
|
||||
?typeindex,
|
||||
?type_index,
|
||||
"Address hash collision"
|
||||
);
|
||||
return Err(Error::Internal("Address hash collision"));
|
||||
@@ -90,13 +90,13 @@ impl<'a> BlockProcessor<'a> {
|
||||
}
|
||||
|
||||
Ok(ProcessedOutput {
|
||||
txoutindex,
|
||||
txout_index,
|
||||
txout,
|
||||
txindex,
|
||||
tx_index,
|
||||
vout,
|
||||
outputtype,
|
||||
output_type,
|
||||
address_info: Some((address_bytes, address_hash)),
|
||||
existing_typeindex,
|
||||
existing_type_index,
|
||||
})
|
||||
},
|
||||
)
|
||||
@@ -107,125 +107,125 @@ impl<'a> BlockProcessor<'a> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(super) fn finalize_outputs(
|
||||
indexes: &mut Indexes,
|
||||
first_txoutindex: &mut BytesVec<TxIndex, TxOutIndex>,
|
||||
first_txout_index: &mut BytesVec<TxIndex, TxOutIndex>,
|
||||
outputs: &mut OutputsVecs,
|
||||
addresses: &mut AddressesVecs,
|
||||
scripts: &mut ScriptsVecs,
|
||||
addr_hash_stores: &mut ByAddressType<Store<AddressHash, TypeIndex>>,
|
||||
addr_txindex_stores: &mut ByAddressType<Store<AddressIndexTxIndex, Unit>>,
|
||||
addr_tx_index_stores: &mut ByAddressType<Store<AddressIndexTxIndex, Unit>>,
|
||||
addr_outpoint_stores: &mut ByAddressType<Store<AddressIndexOutPoint, Unit>>,
|
||||
txouts: Vec<ProcessedOutput>,
|
||||
same_block_spent_outpoints: &FxHashSet<OutPoint>,
|
||||
already_added_addresshash: &mut ByAddressType<FxHashMap<AddressHash, TypeIndex>>,
|
||||
already_added_address_hash: &mut ByAddressType<FxHashMap<AddressHash, TypeIndex>>,
|
||||
same_block_output_info: &mut FxHashMap<OutPoint, SameBlockOutputInfo>,
|
||||
) -> Result<()> {
|
||||
already_added_addresshash
|
||||
already_added_address_hash
|
||||
.values_mut()
|
||||
.for_each(|m| m.clear());
|
||||
same_block_output_info.clear();
|
||||
|
||||
for ProcessedOutput {
|
||||
txoutindex,
|
||||
txout_index,
|
||||
txout,
|
||||
txindex,
|
||||
tx_index,
|
||||
vout,
|
||||
outputtype,
|
||||
output_type,
|
||||
address_info,
|
||||
existing_typeindex,
|
||||
existing_type_index,
|
||||
} in txouts
|
||||
{
|
||||
let sats = Sats::from(txout.value);
|
||||
|
||||
if vout.is_zero() {
|
||||
first_txoutindex.checked_push(txindex, txoutindex)?;
|
||||
first_txout_index.checked_push(tx_index, txout_index)?;
|
||||
}
|
||||
|
||||
outputs.txindex.checked_push(txoutindex, txindex)?;
|
||||
outputs.tx_index.checked_push(txout_index, tx_index)?;
|
||||
|
||||
let typeindex = if let Some(ti) = existing_typeindex {
|
||||
let type_index = if let Some(ti) = existing_type_index {
|
||||
ti
|
||||
} else if let Some((address_bytes, address_hash)) = address_info {
|
||||
let addresstype = outputtype;
|
||||
if let Some(&ti) = already_added_addresshash
|
||||
.get_unwrap(addresstype)
|
||||
let address_type = output_type;
|
||||
if let Some(&ti) = already_added_address_hash
|
||||
.get_unwrap(address_type)
|
||||
.get(&address_hash)
|
||||
{
|
||||
ti
|
||||
} else {
|
||||
let ti = indexes.increment_address_index(addresstype);
|
||||
let ti = indexes.increment_address_index(address_type);
|
||||
|
||||
already_added_addresshash
|
||||
.get_mut_unwrap(addresstype)
|
||||
already_added_address_hash
|
||||
.get_mut_unwrap(address_type)
|
||||
.insert(address_hash, ti);
|
||||
addr_hash_stores
|
||||
.get_mut_unwrap(addresstype)
|
||||
.get_mut_unwrap(address_type)
|
||||
.insert(address_hash, ti);
|
||||
addresses.push_bytes_if_needed(ti, address_bytes)?;
|
||||
|
||||
ti
|
||||
}
|
||||
} else {
|
||||
match outputtype {
|
||||
match output_type {
|
||||
OutputType::P2MS => {
|
||||
scripts
|
||||
.p2ms.to_txindex
|
||||
.checked_push(indexes.p2msoutputindex, txindex)?;
|
||||
indexes.p2msoutputindex.copy_then_increment()
|
||||
.p2ms.to_tx_index
|
||||
.checked_push(indexes.p2ms_output_index, tx_index)?;
|
||||
indexes.p2ms_output_index.copy_then_increment()
|
||||
}
|
||||
OutputType::OpReturn => {
|
||||
scripts
|
||||
.opreturn.to_txindex
|
||||
.checked_push(indexes.opreturnindex, txindex)?;
|
||||
indexes.opreturnindex.copy_then_increment()
|
||||
.opreturn.to_tx_index
|
||||
.checked_push(indexes.op_return_index, tx_index)?;
|
||||
indexes.op_return_index.copy_then_increment()
|
||||
}
|
||||
OutputType::Empty => {
|
||||
scripts
|
||||
.empty.to_txindex
|
||||
.checked_push(indexes.emptyoutputindex, txindex)?;
|
||||
indexes.emptyoutputindex.copy_then_increment()
|
||||
.empty.to_tx_index
|
||||
.checked_push(indexes.empty_output_index, tx_index)?;
|
||||
indexes.empty_output_index.copy_then_increment()
|
||||
}
|
||||
OutputType::Unknown => {
|
||||
scripts
|
||||
.unknown.to_txindex
|
||||
.checked_push(indexes.unknownoutputindex, txindex)?;
|
||||
indexes.unknownoutputindex.copy_then_increment()
|
||||
.unknown.to_tx_index
|
||||
.checked_push(indexes.unknown_output_index, tx_index)?;
|
||||
indexes.unknown_output_index.copy_then_increment()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
};
|
||||
|
||||
outputs.value.checked_push(txoutindex, sats)?;
|
||||
outputs.outputtype.checked_push(txoutindex, outputtype)?;
|
||||
outputs.typeindex.checked_push(txoutindex, typeindex)?;
|
||||
outputs.value.checked_push(txout_index, sats)?;
|
||||
outputs.output_type.checked_push(txout_index, output_type)?;
|
||||
outputs.type_index.checked_push(txout_index, type_index)?;
|
||||
|
||||
if outputtype.is_unspendable() {
|
||||
if output_type.is_unspendable() {
|
||||
continue;
|
||||
} else if outputtype.is_address() {
|
||||
let addresstype = outputtype;
|
||||
let addressindex = typeindex;
|
||||
} else if output_type.is_address() {
|
||||
let address_type = output_type;
|
||||
let address_index = type_index;
|
||||
|
||||
addr_txindex_stores
|
||||
.get_mut_unwrap(addresstype)
|
||||
.insert(AddressIndexTxIndex::from((addressindex, txindex)), Unit);
|
||||
addr_tx_index_stores
|
||||
.get_mut_unwrap(address_type)
|
||||
.insert(AddressIndexTxIndex::from((address_index, tx_index)), Unit);
|
||||
}
|
||||
|
||||
let outpoint = OutPoint::new(txindex, vout);
|
||||
let outpoint = OutPoint::new(tx_index, vout);
|
||||
|
||||
if same_block_spent_outpoints.contains(&outpoint) {
|
||||
same_block_output_info.insert(
|
||||
outpoint,
|
||||
SameBlockOutputInfo {
|
||||
outputtype,
|
||||
typeindex,
|
||||
output_type,
|
||||
type_index,
|
||||
},
|
||||
);
|
||||
} else if outputtype.is_address() {
|
||||
let addresstype = outputtype;
|
||||
let addressindex = typeindex;
|
||||
} else if output_type.is_address() {
|
||||
let address_type = output_type;
|
||||
let address_index = type_index;
|
||||
|
||||
addr_outpoint_stores
|
||||
.get_mut_unwrap(addresstype)
|
||||
.insert(AddressIndexOutPoint::from((addressindex, outpoint)), Unit);
|
||||
.get_mut_unwrap(address_type)
|
||||
.insert(AddressIndexOutPoint::from((address_index, outpoint)), Unit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@ use rustc_hash::{FxHashMap, FxHashSet};
|
||||
pub enum InputSource {
|
||||
PreviousBlock {
|
||||
vin: Vin,
|
||||
txindex: TxIndex,
|
||||
tx_index: TxIndex,
|
||||
outpoint: OutPoint,
|
||||
outputtype: OutputType,
|
||||
typeindex: TypeIndex,
|
||||
output_type: OutputType,
|
||||
type_index: TypeIndex,
|
||||
},
|
||||
SameBlock {
|
||||
txindex: TxIndex,
|
||||
tx_index: TxIndex,
|
||||
vin: Vin,
|
||||
outpoint: OutPoint,
|
||||
},
|
||||
@@ -24,26 +24,26 @@ pub enum InputSource {
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct SameBlockOutputInfo {
|
||||
pub outputtype: OutputType,
|
||||
pub typeindex: TypeIndex,
|
||||
pub output_type: OutputType,
|
||||
pub type_index: TypeIndex,
|
||||
}
|
||||
|
||||
pub struct ProcessedOutput<'a> {
|
||||
pub txoutindex: TxOutIndex,
|
||||
pub txout_index: TxOutIndex,
|
||||
pub txout: &'a TxOut,
|
||||
pub txindex: TxIndex,
|
||||
pub tx_index: TxIndex,
|
||||
pub vout: Vout,
|
||||
pub outputtype: OutputType,
|
||||
pub output_type: OutputType,
|
||||
pub address_info: Option<(AddressBytes, AddressHash)>,
|
||||
pub existing_typeindex: Option<TypeIndex>,
|
||||
pub existing_type_index: Option<TypeIndex>,
|
||||
}
|
||||
|
||||
pub struct ComputedTx<'a> {
|
||||
pub txindex: TxIndex,
|
||||
pub tx_index: TxIndex,
|
||||
pub tx: &'a Transaction,
|
||||
pub txid: Txid,
|
||||
pub txid_prefix: TxidPrefix,
|
||||
pub prev_txindex_opt: Option<TxIndex>,
|
||||
pub prev_tx_index_opt: Option<TxIndex>,
|
||||
pub base_size: u32,
|
||||
pub total_size: u32,
|
||||
}
|
||||
|
||||
@@ -21,9 +21,9 @@ pub struct AddressReaders {
|
||||
}
|
||||
|
||||
impl AddressReaders {
|
||||
pub fn script_pubkey(&self, outputtype: OutputType, typeindex: TypeIndex) -> ScriptBuf {
|
||||
let idx = usize::from(typeindex);
|
||||
let bytes: Option<AddressBytes> = match outputtype {
|
||||
pub fn script_pubkey(&self, output_type: OutputType, type_index: TypeIndex) -> ScriptBuf {
|
||||
let idx = usize::from(type_index);
|
||||
let bytes: Option<AddressBytes> = match output_type {
|
||||
OutputType::P2PK65 => self.p2pk65.try_get(idx).map(Into::into),
|
||||
OutputType::P2PK33 => self.p2pk33.try_get(idx).map(Into::into),
|
||||
OutputType::P2PKH => self.p2pkh.try_get(idx).map(Into::into),
|
||||
@@ -44,9 +44,9 @@ impl AddressReaders {
|
||||
/// random access without recomputing `region.start() + HEADER_OFFSET` per read.
|
||||
pub struct Readers {
|
||||
pub txid: VecReader<TxIndex, Txid, BytesStrategy<Txid>>,
|
||||
pub txindex_to_first_txoutindex: VecReader<TxIndex, TxOutIndex, BytesStrategy<TxOutIndex>>,
|
||||
pub txoutindex_to_outputtype: VecReader<TxOutIndex, OutputType, BytesStrategy<OutputType>>,
|
||||
pub txoutindex_to_typeindex: VecReader<TxOutIndex, TypeIndex, BytesStrategy<TypeIndex>>,
|
||||
pub tx_index_to_first_txout_index: VecReader<TxIndex, TxOutIndex, BytesStrategy<TxOutIndex>>,
|
||||
pub txout_index_to_output_type: VecReader<TxOutIndex, OutputType, BytesStrategy<OutputType>>,
|
||||
pub txout_index_to_type_index: VecReader<TxOutIndex, TypeIndex, BytesStrategy<TypeIndex>>,
|
||||
pub addressbytes: AddressReaders,
|
||||
}
|
||||
|
||||
@@ -54,9 +54,9 @@ impl Readers {
|
||||
pub fn new(vecs: &Vecs) -> Self {
|
||||
Self {
|
||||
txid: vecs.transactions.txid.reader(),
|
||||
txindex_to_first_txoutindex: vecs.transactions.first_txoutindex.reader(),
|
||||
txoutindex_to_outputtype: vecs.outputs.outputtype.reader(),
|
||||
txoutindex_to_typeindex: vecs.outputs.typeindex.reader(),
|
||||
tx_index_to_first_txout_index: vecs.transactions.first_txout_index.reader(),
|
||||
txout_index_to_output_type: vecs.outputs.output_type.reader(),
|
||||
txout_index_to_type_index: vecs.outputs.type_index.reader(),
|
||||
addressbytes: vecs.addresses.address_readers(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,13 +22,13 @@ use super::Vecs;
|
||||
pub struct Stores {
|
||||
pub db: Database,
|
||||
|
||||
pub addresstype_to_addresshash_to_addressindex: ByAddressType<Store<AddressHash, TypeIndex>>,
|
||||
pub addresstype_to_addressindex_and_txindex: ByAddressType<Store<AddressIndexTxIndex, Unit>>,
|
||||
pub addresstype_to_addressindex_and_unspentoutpoint:
|
||||
pub address_type_to_address_hash_to_address_index: ByAddressType<Store<AddressHash, TypeIndex>>,
|
||||
pub address_type_to_address_index_and_tx_index: ByAddressType<Store<AddressIndexTxIndex, Unit>>,
|
||||
pub address_type_to_address_index_and_unspent_outpoint:
|
||||
ByAddressType<Store<AddressIndexOutPoint, Unit>>,
|
||||
pub blockhashprefix_to_height: Store<BlockHashPrefix, Height>,
|
||||
pub blockhash_prefix_to_height: Store<BlockHashPrefix, Height>,
|
||||
pub height_to_coinbase_tag: Store<Height, StoredString>,
|
||||
pub txidprefix_to_txindex: Store<TxidPrefix, TxIndex>,
|
||||
pub txid_prefix_to_tx_index: Store<TxidPrefix, TxIndex>,
|
||||
}
|
||||
|
||||
impl Stores {
|
||||
@@ -53,7 +53,7 @@ impl Stores {
|
||||
|
||||
let database_ref = &database;
|
||||
|
||||
let create_addresshash_to_addressindex_store = |index| {
|
||||
let create_address_hash_to_address_index_store = |index| {
|
||||
Store::import(
|
||||
database_ref,
|
||||
path,
|
||||
@@ -64,7 +64,7 @@ impl Stores {
|
||||
)
|
||||
};
|
||||
|
||||
let create_addressindex_to_txindex_store = |index| {
|
||||
let create_address_index_to_tx_index_store = |index| {
|
||||
Store::import(
|
||||
database_ref,
|
||||
path,
|
||||
@@ -75,7 +75,7 @@ impl Stores {
|
||||
)
|
||||
};
|
||||
|
||||
let create_addressindex_to_unspentoutpoint_store = |index| {
|
||||
let create_address_index_to_unspent_outpoint_store = |index| {
|
||||
Store::import(
|
||||
database_ref,
|
||||
path,
|
||||
@@ -97,27 +97,27 @@ impl Stores {
|
||||
Mode::PushOnly,
|
||||
Kind::Sequential,
|
||||
)?,
|
||||
addresstype_to_addresshash_to_addressindex: ByAddressType::new_with_index(
|
||||
create_addresshash_to_addressindex_store,
|
||||
address_type_to_address_hash_to_address_index: ByAddressType::new_with_index(
|
||||
create_address_hash_to_address_index_store,
|
||||
)?,
|
||||
addresstype_to_addressindex_and_txindex: ByAddressType::new_with_index(
|
||||
create_addressindex_to_txindex_store,
|
||||
address_type_to_address_index_and_tx_index: ByAddressType::new_with_index(
|
||||
create_address_index_to_tx_index_store,
|
||||
)?,
|
||||
addresstype_to_addressindex_and_unspentoutpoint: ByAddressType::new_with_index(
|
||||
create_addressindex_to_unspentoutpoint_store,
|
||||
address_type_to_address_index_and_unspent_outpoint: ByAddressType::new_with_index(
|
||||
create_address_index_to_unspent_outpoint_store,
|
||||
)?,
|
||||
blockhashprefix_to_height: Store::import(
|
||||
blockhash_prefix_to_height: Store::import(
|
||||
database_ref,
|
||||
path,
|
||||
"blockhashprefix_to_height",
|
||||
"blockhash_prefix_to_height",
|
||||
version,
|
||||
Mode::PushOnly,
|
||||
Kind::Random,
|
||||
)?,
|
||||
txidprefix_to_txindex: Store::import_cached(
|
||||
txid_prefix_to_tx_index: Store::import_cached(
|
||||
database_ref,
|
||||
path,
|
||||
"txidprefix_to_txindex",
|
||||
"txid_prefix_to_tx_index",
|
||||
version,
|
||||
Mode::PushOnly,
|
||||
Kind::Recent,
|
||||
@@ -135,23 +135,23 @@ impl Stores {
|
||||
|
||||
fn iter_any(&self) -> impl Iterator<Item = &dyn AnyStore> {
|
||||
[
|
||||
&self.blockhashprefix_to_height as &dyn AnyStore,
|
||||
&self.blockhash_prefix_to_height as &dyn AnyStore,
|
||||
&self.height_to_coinbase_tag,
|
||||
&self.txidprefix_to_txindex,
|
||||
&self.txid_prefix_to_tx_index,
|
||||
]
|
||||
.into_iter()
|
||||
.chain(
|
||||
self.addresstype_to_addresshash_to_addressindex
|
||||
self.address_type_to_address_hash_to_address_index
|
||||
.values()
|
||||
.map(|s| s as &dyn AnyStore),
|
||||
)
|
||||
.chain(
|
||||
self.addresstype_to_addressindex_and_txindex
|
||||
self.address_type_to_address_index_and_tx_index
|
||||
.values()
|
||||
.map(|s| s as &dyn AnyStore),
|
||||
)
|
||||
.chain(
|
||||
self.addresstype_to_addressindex_and_unspentoutpoint
|
||||
self.address_type_to_address_index_and_unspent_outpoint
|
||||
.values()
|
||||
.map(|s| s as &dyn AnyStore),
|
||||
)
|
||||
@@ -159,23 +159,23 @@ impl Stores {
|
||||
|
||||
fn par_iter_any_mut(&mut self) -> impl ParallelIterator<Item = &mut dyn AnyStore> {
|
||||
[
|
||||
&mut self.blockhashprefix_to_height as &mut dyn AnyStore,
|
||||
&mut self.blockhash_prefix_to_height as &mut dyn AnyStore,
|
||||
&mut self.height_to_coinbase_tag,
|
||||
&mut self.txidprefix_to_txindex,
|
||||
&mut self.txid_prefix_to_tx_index,
|
||||
]
|
||||
.into_par_iter()
|
||||
.chain(
|
||||
self.addresstype_to_addresshash_to_addressindex
|
||||
self.address_type_to_address_hash_to_address_index
|
||||
.par_values_mut()
|
||||
.map(|s| s as &mut dyn AnyStore),
|
||||
)
|
||||
.chain(
|
||||
self.addresstype_to_addressindex_and_txindex
|
||||
self.address_type_to_address_index_and_tx_index
|
||||
.par_values_mut()
|
||||
.map(|s| s as &mut dyn AnyStore),
|
||||
)
|
||||
.chain(
|
||||
self.addresstype_to_addressindex_and_unspentoutpoint
|
||||
self.address_type_to_address_index_and_unspent_outpoint
|
||||
.par_values_mut()
|
||||
.map(|s| s as &mut dyn AnyStore),
|
||||
)
|
||||
@@ -204,8 +204,8 @@ impl Stores {
|
||||
}
|
||||
|
||||
debug_assert!(starting_indexes.height != Height::ZERO);
|
||||
debug_assert!(starting_indexes.txindex != TxIndex::ZERO);
|
||||
debug_assert!(starting_indexes.txoutindex != TxOutIndex::ZERO);
|
||||
debug_assert!(starting_indexes.tx_index != TxIndex::ZERO);
|
||||
debug_assert!(starting_indexes.txout_index != TxOutIndex::ZERO);
|
||||
|
||||
self.rollback_block_metadata(vecs, starting_indexes)?;
|
||||
self.rollback_txids(vecs, starting_indexes);
|
||||
@@ -220,19 +220,19 @@ impl Stores {
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> Result<bool> {
|
||||
Ok(self.blockhashprefix_to_height.is_empty()?
|
||||
&& self.txidprefix_to_txindex.is_empty()?
|
||||
Ok(self.blockhash_prefix_to_height.is_empty()?
|
||||
&& self.txid_prefix_to_tx_index.is_empty()?
|
||||
&& self.height_to_coinbase_tag.is_empty()?
|
||||
&& self
|
||||
.addresstype_to_addresshash_to_addressindex
|
||||
.address_type_to_address_hash_to_address_index
|
||||
.values()
|
||||
.try_fold(true, |acc, s| s.is_empty().map(|empty| acc && empty))?
|
||||
&& self
|
||||
.addresstype_to_addressindex_and_txindex
|
||||
.address_type_to_address_index_and_tx_index
|
||||
.values()
|
||||
.try_fold(true, |acc, s| s.is_empty().map(|empty| acc && empty))?
|
||||
&& self
|
||||
.addresstype_to_addressindex_and_unspentoutpoint
|
||||
.address_type_to_address_index_and_unspent_outpoint
|
||||
.values()
|
||||
.try_fold(true, |acc, s| s.is_empty().map(|empty| acc && empty))?)
|
||||
}
|
||||
@@ -246,7 +246,7 @@ impl Stores {
|
||||
starting_indexes.height.to_usize(),
|
||||
vecs.blocks.blockhash.len(),
|
||||
|blockhash| {
|
||||
self.blockhashprefix_to_height
|
||||
self.blockhash_prefix_to_height
|
||||
.remove(BlockHashPrefix::from(blockhash));
|
||||
},
|
||||
);
|
||||
@@ -259,7 +259,7 @@ impl Stores {
|
||||
|
||||
for address_type in OutputType::ADDRESS_TYPES {
|
||||
for hash in vecs.iter_address_hashes_from(address_type, starting_indexes.height)? {
|
||||
self.addresstype_to_addresshash_to_addressindex
|
||||
self.address_type_to_address_hash_to_address_index
|
||||
.get_mut_unwrap(address_type)
|
||||
.remove(hash);
|
||||
}
|
||||
@@ -269,121 +269,121 @@ impl Stores {
|
||||
}
|
||||
|
||||
fn rollback_txids(&mut self, vecs: &mut Vecs, starting_indexes: &Indexes) {
|
||||
let start = starting_indexes.txindex.to_usize();
|
||||
let start = starting_indexes.tx_index.to_usize();
|
||||
let end = vecs.transactions.txid.len();
|
||||
let mut current_index = start;
|
||||
vecs.transactions
|
||||
.txid
|
||||
.for_each_range_at(start, end, |txid| {
|
||||
let txindex = TxIndex::from(current_index);
|
||||
let txidprefix = TxidPrefix::from(&txid);
|
||||
let tx_index = TxIndex::from(current_index);
|
||||
let txid_prefix = TxidPrefix::from(&txid);
|
||||
|
||||
let is_known_dup =
|
||||
DUPLICATE_TXID_PREFIXES
|
||||
.iter()
|
||||
.any(|(dup_prefix, dup_txindex)| {
|
||||
txindex == *dup_txindex && txidprefix == *dup_prefix
|
||||
.any(|(dup_prefix, dup_tx_index)| {
|
||||
tx_index == *dup_tx_index && txid_prefix == *dup_prefix
|
||||
});
|
||||
|
||||
if !is_known_dup {
|
||||
self.txidprefix_to_txindex.remove(txidprefix);
|
||||
self.txid_prefix_to_tx_index.remove(txid_prefix);
|
||||
}
|
||||
current_index += 1;
|
||||
});
|
||||
|
||||
self.txidprefix_to_txindex.clear_caches();
|
||||
self.txid_prefix_to_tx_index.clear_caches();
|
||||
}
|
||||
|
||||
fn rollback_outputs_and_inputs(&mut self, vecs: &mut Vecs, starting_indexes: &Indexes) {
|
||||
let txindex_to_first_txoutindex_reader = vecs.transactions.first_txoutindex.reader();
|
||||
let txoutindex_to_outputtype_reader = vecs.outputs.outputtype.reader();
|
||||
let txoutindex_to_typeindex_reader = vecs.outputs.typeindex.reader();
|
||||
let tx_index_to_first_txout_index_reader = vecs.transactions.first_txout_index.reader();
|
||||
let txout_index_to_output_type_reader = vecs.outputs.output_type.reader();
|
||||
let txout_index_to_type_index_reader = vecs.outputs.type_index.reader();
|
||||
|
||||
let mut addressindex_txindex_to_remove: FxHashSet<(OutputType, TypeIndex, TxIndex)> =
|
||||
let mut address_index_tx_index_to_remove: FxHashSet<(OutputType, TypeIndex, TxIndex)> =
|
||||
FxHashSet::default();
|
||||
|
||||
let rollback_start = starting_indexes.txoutindex.to_usize();
|
||||
let rollback_end = vecs.outputs.outputtype.len();
|
||||
let rollback_start = starting_indexes.txout_index.to_usize();
|
||||
let rollback_end = vecs.outputs.output_type.len();
|
||||
|
||||
let txindexes: Vec<TxIndex> = vecs
|
||||
let tx_indexes: Vec<TxIndex> = vecs
|
||||
.outputs
|
||||
.txindex
|
||||
.tx_index
|
||||
.collect_range_at(rollback_start, rollback_end);
|
||||
|
||||
for (i, txoutindex) in (rollback_start..rollback_end).enumerate() {
|
||||
let outputtype = txoutindex_to_outputtype_reader.get(txoutindex);
|
||||
if !outputtype.is_address() {
|
||||
for (i, txout_index) in (rollback_start..rollback_end).enumerate() {
|
||||
let output_type = txout_index_to_output_type_reader.get(txout_index);
|
||||
if !output_type.is_address() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let addresstype = outputtype;
|
||||
let addressindex = txoutindex_to_typeindex_reader.get(txoutindex);
|
||||
let txindex = txindexes[i];
|
||||
let address_type = output_type;
|
||||
let address_index = txout_index_to_type_index_reader.get(txout_index);
|
||||
let tx_index = tx_indexes[i];
|
||||
|
||||
addressindex_txindex_to_remove.insert((addresstype, addressindex, txindex));
|
||||
address_index_tx_index_to_remove.insert((address_type, address_index, tx_index));
|
||||
|
||||
let vout = Vout::from(
|
||||
txoutindex
|
||||
- txindex_to_first_txoutindex_reader
|
||||
.get(txindex.to_usize())
|
||||
txout_index
|
||||
- tx_index_to_first_txout_index_reader
|
||||
.get(tx_index.to_usize())
|
||||
.to_usize(),
|
||||
);
|
||||
let outpoint = OutPoint::new(txindex, vout);
|
||||
let outpoint = OutPoint::new(tx_index, vout);
|
||||
|
||||
self.addresstype_to_addressindex_and_unspentoutpoint
|
||||
.get_mut_unwrap(addresstype)
|
||||
.remove(AddressIndexOutPoint::from((addressindex, outpoint)));
|
||||
self.address_type_to_address_index_and_unspent_outpoint
|
||||
.get_mut_unwrap(address_type)
|
||||
.remove(AddressIndexOutPoint::from((address_index, outpoint)));
|
||||
}
|
||||
|
||||
let start = starting_indexes.txinindex.to_usize();
|
||||
let start = starting_indexes.txin_index.to_usize();
|
||||
let end = vecs.inputs.outpoint.len();
|
||||
let outpoints: Vec<OutPoint> = vecs.inputs.outpoint.collect_range_at(start, end);
|
||||
let spending_txindexes: Vec<TxIndex> = vecs.inputs.txindex.collect_range_at(start, end);
|
||||
let spending_tx_indexes: Vec<TxIndex> = vecs.inputs.tx_index.collect_range_at(start, end);
|
||||
|
||||
let outputs_to_unspend: Vec<_> = outpoints
|
||||
.into_iter()
|
||||
.zip(spending_txindexes)
|
||||
.filter_map(|(outpoint, spending_txindex)| {
|
||||
.zip(spending_tx_indexes)
|
||||
.filter_map(|(outpoint, spending_tx_index)| {
|
||||
if outpoint.is_coinbase() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let output_txindex = outpoint.txindex();
|
||||
let output_tx_index = outpoint.tx_index();
|
||||
let vout = outpoint.vout();
|
||||
let txoutindex =
|
||||
txindex_to_first_txoutindex_reader.get(output_txindex.to_usize()) + vout;
|
||||
let txout_index =
|
||||
tx_index_to_first_txout_index_reader.get(output_tx_index.to_usize()) + vout;
|
||||
|
||||
if txoutindex < starting_indexes.txoutindex {
|
||||
let outputtype = txoutindex_to_outputtype_reader.get(txoutindex.to_usize());
|
||||
let typeindex = txoutindex_to_typeindex_reader.get(txoutindex.to_usize());
|
||||
Some((outpoint, outputtype, typeindex, spending_txindex))
|
||||
if txout_index < starting_indexes.txout_index {
|
||||
let output_type = txout_index_to_output_type_reader.get(txout_index.to_usize());
|
||||
let type_index = txout_index_to_type_index_reader.get(txout_index.to_usize());
|
||||
Some((outpoint, output_type, type_index, spending_tx_index))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
for (outpoint, outputtype, typeindex, spending_txindex) in outputs_to_unspend {
|
||||
if outputtype.is_address() {
|
||||
let addresstype = outputtype;
|
||||
let addressindex = typeindex;
|
||||
for (outpoint, output_type, type_index, spending_tx_index) in outputs_to_unspend {
|
||||
if output_type.is_address() {
|
||||
let address_type = output_type;
|
||||
let address_index = type_index;
|
||||
|
||||
addressindex_txindex_to_remove.insert((
|
||||
addresstype,
|
||||
addressindex,
|
||||
spending_txindex,
|
||||
address_index_tx_index_to_remove.insert((
|
||||
address_type,
|
||||
address_index,
|
||||
spending_tx_index,
|
||||
));
|
||||
|
||||
self.addresstype_to_addressindex_and_unspentoutpoint
|
||||
.get_mut_unwrap(addresstype)
|
||||
.insert(AddressIndexOutPoint::from((addressindex, outpoint)), Unit);
|
||||
self.address_type_to_address_index_and_unspent_outpoint
|
||||
.get_mut_unwrap(address_type)
|
||||
.insert(AddressIndexOutPoint::from((address_index, outpoint)), Unit);
|
||||
}
|
||||
}
|
||||
|
||||
for (addresstype, addressindex, txindex) in addressindex_txindex_to_remove {
|
||||
self.addresstype_to_addressindex_and_txindex
|
||||
.get_mut_unwrap(addresstype)
|
||||
.remove(AddressIndexTxIndex::from((addressindex, txindex)));
|
||||
for (address_type, address_index, tx_index) in address_index_tx_index_to_remove {
|
||||
self.address_type_to_address_index_and_tx_index
|
||||
.get_mut_unwrap(address_type)
|
||||
.remove(AddressIndexTxIndex::from((address_index, tx_index)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,49 +38,49 @@ pub struct AddressesVecs<M: StorageMode = Rw> {
|
||||
impl AddressesVecs {
|
||||
pub fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
||||
let (
|
||||
first_p2pk65addressindex,
|
||||
first_p2pk33addressindex,
|
||||
first_p2pkhaddressindex,
|
||||
first_p2shaddressindex,
|
||||
first_p2wpkhaddressindex,
|
||||
first_p2wshaddressindex,
|
||||
first_p2traddressindex,
|
||||
first_p2aaddressindex,
|
||||
p2pk65bytes,
|
||||
p2pk33bytes,
|
||||
p2pkhbytes,
|
||||
p2shbytes,
|
||||
p2wpkhbytes,
|
||||
p2wshbytes,
|
||||
p2trbytes,
|
||||
p2abytes,
|
||||
first_p2pk65_address_index,
|
||||
first_p2pk33_address_index,
|
||||
first_p2pkh_address_index,
|
||||
first_p2sh_address_index,
|
||||
first_p2wpkh_address_index,
|
||||
first_p2wsh_address_index,
|
||||
first_p2tr_address_index,
|
||||
first_p2a_address_index,
|
||||
p2pk65_bytes,
|
||||
p2pk33_bytes,
|
||||
p2pkh_bytes,
|
||||
p2sh_bytes,
|
||||
p2wpkh_bytes,
|
||||
p2wsh_bytes,
|
||||
p2tr_bytes,
|
||||
p2a_bytes,
|
||||
) = parallel_import! {
|
||||
first_p2pk65addressindex = PcoVec::forced_import(db, "first_p2pk65addressindex", version),
|
||||
first_p2pk33addressindex = PcoVec::forced_import(db, "first_p2pk33addressindex", version),
|
||||
first_p2pkhaddressindex = PcoVec::forced_import(db, "first_p2pkhaddressindex", version),
|
||||
first_p2shaddressindex = PcoVec::forced_import(db, "first_p2shaddressindex", version),
|
||||
first_p2wpkhaddressindex = PcoVec::forced_import(db, "first_p2wpkhaddressindex", version),
|
||||
first_p2wshaddressindex = PcoVec::forced_import(db, "first_p2wshaddressindex", version),
|
||||
first_p2traddressindex = PcoVec::forced_import(db, "first_p2traddressindex", version),
|
||||
first_p2aaddressindex = PcoVec::forced_import(db, "first_p2aaddressindex", version),
|
||||
p2pk65bytes = BytesVec::forced_import(db, "p2pk65bytes", version),
|
||||
p2pk33bytes = BytesVec::forced_import(db, "p2pk33bytes", version),
|
||||
p2pkhbytes = BytesVec::forced_import(db, "p2pkhbytes", version),
|
||||
p2shbytes = BytesVec::forced_import(db, "p2shbytes", version),
|
||||
p2wpkhbytes = BytesVec::forced_import(db, "p2wpkhbytes", version),
|
||||
p2wshbytes = BytesVec::forced_import(db, "p2wshbytes", version),
|
||||
p2trbytes = BytesVec::forced_import(db, "p2trbytes", version),
|
||||
p2abytes = BytesVec::forced_import(db, "p2abytes", version),
|
||||
first_p2pk65_address_index = PcoVec::forced_import(db, "first_p2pk65_address_index", version),
|
||||
first_p2pk33_address_index = PcoVec::forced_import(db, "first_p2pk33_address_index", version),
|
||||
first_p2pkh_address_index = PcoVec::forced_import(db, "first_p2pkh_address_index", version),
|
||||
first_p2sh_address_index = PcoVec::forced_import(db, "first_p2sh_address_index", version),
|
||||
first_p2wpkh_address_index = PcoVec::forced_import(db, "first_p2wpkh_address_index", version),
|
||||
first_p2wsh_address_index = PcoVec::forced_import(db, "first_p2wsh_address_index", version),
|
||||
first_p2tr_address_index = PcoVec::forced_import(db, "first_p2tr_address_index", version),
|
||||
first_p2a_address_index = PcoVec::forced_import(db, "first_p2a_address_index", version),
|
||||
p2pk65_bytes = BytesVec::forced_import(db, "p2pk65_bytes", version),
|
||||
p2pk33_bytes = BytesVec::forced_import(db, "p2pk33_bytes", version),
|
||||
p2pkh_bytes = BytesVec::forced_import(db, "p2pkh_bytes", version),
|
||||
p2sh_bytes = BytesVec::forced_import(db, "p2sh_bytes", version),
|
||||
p2wpkh_bytes = BytesVec::forced_import(db, "p2wpkh_bytes", version),
|
||||
p2wsh_bytes = BytesVec::forced_import(db, "p2wsh_bytes", version),
|
||||
p2tr_bytes = BytesVec::forced_import(db, "p2tr_bytes", version),
|
||||
p2a_bytes = BytesVec::forced_import(db, "p2a_bytes", version),
|
||||
};
|
||||
Ok(Self {
|
||||
p2pk65: AddressTypeVecs { first_index: first_p2pk65addressindex, bytes: p2pk65bytes },
|
||||
p2pk33: AddressTypeVecs { first_index: first_p2pk33addressindex, bytes: p2pk33bytes },
|
||||
p2pkh: AddressTypeVecs { first_index: first_p2pkhaddressindex, bytes: p2pkhbytes },
|
||||
p2sh: AddressTypeVecs { first_index: first_p2shaddressindex, bytes: p2shbytes },
|
||||
p2wpkh: AddressTypeVecs { first_index: first_p2wpkhaddressindex, bytes: p2wpkhbytes },
|
||||
p2wsh: AddressTypeVecs { first_index: first_p2wshaddressindex, bytes: p2wshbytes },
|
||||
p2tr: AddressTypeVecs { first_index: first_p2traddressindex, bytes: p2trbytes },
|
||||
p2a: AddressTypeVecs { first_index: first_p2aaddressindex, bytes: p2abytes },
|
||||
p2pk65: AddressTypeVecs { first_index: first_p2pk65_address_index, bytes: p2pk65_bytes },
|
||||
p2pk33: AddressTypeVecs { first_index: first_p2pk33_address_index, bytes: p2pk33_bytes },
|
||||
p2pkh: AddressTypeVecs { first_index: first_p2pkh_address_index, bytes: p2pkh_bytes },
|
||||
p2sh: AddressTypeVecs { first_index: first_p2sh_address_index, bytes: p2sh_bytes },
|
||||
p2wpkh: AddressTypeVecs { first_index: first_p2wpkh_address_index, bytes: p2wpkh_bytes },
|
||||
p2wsh: AddressTypeVecs { first_index: first_p2wsh_address_index, bytes: p2wsh_bytes },
|
||||
p2tr: AddressTypeVecs { first_index: first_p2tr_address_index, bytes: p2tr_bytes },
|
||||
p2a: AddressTypeVecs { first_index: first_p2a_address_index, bytes: p2a_bytes },
|
||||
})
|
||||
}
|
||||
|
||||
@@ -88,14 +88,14 @@ impl AddressesVecs {
|
||||
pub fn truncate(
|
||||
&mut self,
|
||||
height: Height,
|
||||
p2pk65addressindex: P2PK65AddressIndex,
|
||||
p2pk33addressindex: P2PK33AddressIndex,
|
||||
p2pkhaddressindex: P2PKHAddressIndex,
|
||||
p2shaddressindex: P2SHAddressIndex,
|
||||
p2wpkhaddressindex: P2WPKHAddressIndex,
|
||||
p2wshaddressindex: P2WSHAddressIndex,
|
||||
p2traddressindex: P2TRAddressIndex,
|
||||
p2aaddressindex: P2AAddressIndex,
|
||||
p2pk65_address_index: P2PK65AddressIndex,
|
||||
p2pk33_address_index: P2PK33AddressIndex,
|
||||
p2pkh_address_index: P2PKHAddressIndex,
|
||||
p2sh_address_index: P2SHAddressIndex,
|
||||
p2wpkh_address_index: P2WPKHAddressIndex,
|
||||
p2wsh_address_index: P2WSHAddressIndex,
|
||||
p2tr_address_index: P2TRAddressIndex,
|
||||
p2a_address_index: P2AAddressIndex,
|
||||
stamp: Stamp,
|
||||
) -> Result<()> {
|
||||
self.p2pk65.first_index
|
||||
@@ -115,21 +115,21 @@ impl AddressesVecs {
|
||||
self.p2a.first_index
|
||||
.truncate_if_needed_with_stamp(height, stamp)?;
|
||||
self.p2pk65.bytes
|
||||
.truncate_if_needed_with_stamp(p2pk65addressindex, stamp)?;
|
||||
.truncate_if_needed_with_stamp(p2pk65_address_index, stamp)?;
|
||||
self.p2pk33.bytes
|
||||
.truncate_if_needed_with_stamp(p2pk33addressindex, stamp)?;
|
||||
.truncate_if_needed_with_stamp(p2pk33_address_index, stamp)?;
|
||||
self.p2pkh.bytes
|
||||
.truncate_if_needed_with_stamp(p2pkhaddressindex, stamp)?;
|
||||
.truncate_if_needed_with_stamp(p2pkh_address_index, stamp)?;
|
||||
self.p2sh.bytes
|
||||
.truncate_if_needed_with_stamp(p2shaddressindex, stamp)?;
|
||||
.truncate_if_needed_with_stamp(p2sh_address_index, stamp)?;
|
||||
self.p2wpkh.bytes
|
||||
.truncate_if_needed_with_stamp(p2wpkhaddressindex, stamp)?;
|
||||
.truncate_if_needed_with_stamp(p2wpkh_address_index, stamp)?;
|
||||
self.p2wsh.bytes
|
||||
.truncate_if_needed_with_stamp(p2wshaddressindex, stamp)?;
|
||||
.truncate_if_needed_with_stamp(p2wsh_address_index, stamp)?;
|
||||
self.p2tr.bytes
|
||||
.truncate_if_needed_with_stamp(p2traddressindex, stamp)?;
|
||||
.truncate_if_needed_with_stamp(p2tr_address_index, stamp)?;
|
||||
self.p2a.bytes
|
||||
.truncate_if_needed_with_stamp(p2aaddressindex, stamp)?;
|
||||
.truncate_if_needed_with_stamp(p2a_address_index, stamp)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -159,42 +159,42 @@ impl AddressesVecs {
|
||||
/// Returns None if the index doesn't exist yet.
|
||||
pub fn get_bytes_by_type(
|
||||
&self,
|
||||
addresstype: OutputType,
|
||||
typeindex: TypeIndex,
|
||||
address_type: OutputType,
|
||||
type_index: TypeIndex,
|
||||
readers: &AddressReaders,
|
||||
) -> Option<AddressBytes> {
|
||||
match addresstype {
|
||||
match address_type {
|
||||
OutputType::P2PK65 => self
|
||||
.p2pk65.bytes
|
||||
.get_pushed_or_read(typeindex.into(), &readers.p2pk65)
|
||||
.get_pushed_or_read(type_index.into(), &readers.p2pk65)
|
||||
.map(AddressBytes::from),
|
||||
OutputType::P2PK33 => self
|
||||
.p2pk33.bytes
|
||||
.get_pushed_or_read(typeindex.into(), &readers.p2pk33)
|
||||
.get_pushed_or_read(type_index.into(), &readers.p2pk33)
|
||||
.map(AddressBytes::from),
|
||||
OutputType::P2PKH => self
|
||||
.p2pkh.bytes
|
||||
.get_pushed_or_read(typeindex.into(), &readers.p2pkh)
|
||||
.get_pushed_or_read(type_index.into(), &readers.p2pkh)
|
||||
.map(AddressBytes::from),
|
||||
OutputType::P2SH => self
|
||||
.p2sh.bytes
|
||||
.get_pushed_or_read(typeindex.into(), &readers.p2sh)
|
||||
.get_pushed_or_read(type_index.into(), &readers.p2sh)
|
||||
.map(AddressBytes::from),
|
||||
OutputType::P2WPKH => self
|
||||
.p2wpkh.bytes
|
||||
.get_pushed_or_read(typeindex.into(), &readers.p2wpkh)
|
||||
.get_pushed_or_read(type_index.into(), &readers.p2wpkh)
|
||||
.map(AddressBytes::from),
|
||||
OutputType::P2WSH => self
|
||||
.p2wsh.bytes
|
||||
.get_pushed_or_read(typeindex.into(), &readers.p2wsh)
|
||||
.get_pushed_or_read(type_index.into(), &readers.p2wsh)
|
||||
.map(AddressBytes::from),
|
||||
OutputType::P2TR => self
|
||||
.p2tr.bytes
|
||||
.get_pushed_or_read(typeindex.into(), &readers.p2tr)
|
||||
.get_pushed_or_read(type_index.into(), &readers.p2tr)
|
||||
.map(AddressBytes::from),
|
||||
OutputType::P2A => self
|
||||
.p2a.bytes
|
||||
.get_pushed_or_read(typeindex.into(), &readers.p2a)
|
||||
.get_pushed_or_read(type_index.into(), &readers.p2a)
|
||||
.map(AddressBytes::from),
|
||||
_ => unreachable!("get_bytes_by_type called with non-address type"),
|
||||
}
|
||||
|
||||
@@ -8,52 +8,52 @@ use crate::parallel_import;
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct InputsVecs<M: StorageMode = Rw> {
|
||||
pub first_txinindex: M::Stored<PcoVec<Height, TxInIndex>>,
|
||||
pub first_txin_index: M::Stored<PcoVec<Height, TxInIndex>>,
|
||||
pub outpoint: M::Stored<PcoVec<TxInIndex, OutPoint>>,
|
||||
pub txindex: M::Stored<PcoVec<TxInIndex, TxIndex>>,
|
||||
pub outputtype: M::Stored<PcoVec<TxInIndex, OutputType>>,
|
||||
pub typeindex: M::Stored<PcoVec<TxInIndex, TypeIndex>>,
|
||||
pub tx_index: M::Stored<PcoVec<TxInIndex, TxIndex>>,
|
||||
pub output_type: M::Stored<PcoVec<TxInIndex, OutputType>>,
|
||||
pub type_index: M::Stored<PcoVec<TxInIndex, TypeIndex>>,
|
||||
}
|
||||
|
||||
impl InputsVecs {
|
||||
pub fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
||||
let (first_txinindex, outpoint, txindex, outputtype, typeindex) = parallel_import! {
|
||||
first_txinindex = PcoVec::forced_import(db, "first_txinindex", version),
|
||||
let (first_txin_index, outpoint, tx_index, output_type, type_index) = parallel_import! {
|
||||
first_txin_index = PcoVec::forced_import(db, "first_txin_index", version),
|
||||
outpoint = PcoVec::forced_import(db, "outpoint", version),
|
||||
txindex = PcoVec::forced_import(db, "txindex", version),
|
||||
outputtype = PcoVec::forced_import(db, "outputtype", version),
|
||||
typeindex = PcoVec::forced_import(db, "typeindex", version),
|
||||
tx_index = PcoVec::forced_import(db, "tx_index", version),
|
||||
output_type = PcoVec::forced_import(db, "output_type", version),
|
||||
type_index = PcoVec::forced_import(db, "type_index", version),
|
||||
};
|
||||
Ok(Self {
|
||||
first_txinindex,
|
||||
first_txin_index,
|
||||
outpoint,
|
||||
txindex,
|
||||
outputtype,
|
||||
typeindex,
|
||||
tx_index,
|
||||
output_type,
|
||||
type_index,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn truncate(&mut self, height: Height, txinindex: TxInIndex, stamp: Stamp) -> Result<()> {
|
||||
self.first_txinindex
|
||||
pub fn truncate(&mut self, height: Height, txin_index: TxInIndex, stamp: Stamp) -> Result<()> {
|
||||
self.first_txin_index
|
||||
.truncate_if_needed_with_stamp(height, stamp)?;
|
||||
self.outpoint
|
||||
.truncate_if_needed_with_stamp(txinindex, stamp)?;
|
||||
self.txindex
|
||||
.truncate_if_needed_with_stamp(txinindex, stamp)?;
|
||||
self.outputtype
|
||||
.truncate_if_needed_with_stamp(txinindex, stamp)?;
|
||||
self.typeindex
|
||||
.truncate_if_needed_with_stamp(txinindex, stamp)?;
|
||||
.truncate_if_needed_with_stamp(txin_index, stamp)?;
|
||||
self.tx_index
|
||||
.truncate_if_needed_with_stamp(txin_index, stamp)?;
|
||||
self.output_type
|
||||
.truncate_if_needed_with_stamp(txin_index, stamp)?;
|
||||
self.type_index
|
||||
.truncate_if_needed_with_stamp(txin_index, stamp)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn par_iter_mut_any(&mut self) -> impl ParallelIterator<Item = &mut dyn AnyStoredVec> {
|
||||
[
|
||||
&mut self.first_txinindex as &mut dyn AnyStoredVec,
|
||||
&mut self.first_txin_index as &mut dyn AnyStoredVec,
|
||||
&mut self.outpoint,
|
||||
&mut self.txindex,
|
||||
&mut self.outputtype,
|
||||
&mut self.typeindex,
|
||||
&mut self.tx_index,
|
||||
&mut self.output_type,
|
||||
&mut self.type_index,
|
||||
]
|
||||
.into_par_iter()
|
||||
}
|
||||
|
||||
@@ -87,33 +87,33 @@ impl Vecs {
|
||||
self.blocks.truncate(starting_indexes.height, stamp)?;
|
||||
|
||||
self.transactions
|
||||
.truncate(starting_indexes.height, starting_indexes.txindex, stamp)?;
|
||||
.truncate(starting_indexes.height, starting_indexes.tx_index, stamp)?;
|
||||
|
||||
self.inputs
|
||||
.truncate(starting_indexes.height, starting_indexes.txinindex, stamp)?;
|
||||
.truncate(starting_indexes.height, starting_indexes.txin_index, stamp)?;
|
||||
|
||||
self.outputs
|
||||
.truncate(starting_indexes.height, starting_indexes.txoutindex, stamp)?;
|
||||
.truncate(starting_indexes.height, starting_indexes.txout_index, stamp)?;
|
||||
|
||||
self.addresses.truncate(
|
||||
starting_indexes.height,
|
||||
starting_indexes.p2pk65addressindex,
|
||||
starting_indexes.p2pk33addressindex,
|
||||
starting_indexes.p2pkhaddressindex,
|
||||
starting_indexes.p2shaddressindex,
|
||||
starting_indexes.p2wpkhaddressindex,
|
||||
starting_indexes.p2wshaddressindex,
|
||||
starting_indexes.p2traddressindex,
|
||||
starting_indexes.p2aaddressindex,
|
||||
starting_indexes.p2pk65_address_index,
|
||||
starting_indexes.p2pk33_address_index,
|
||||
starting_indexes.p2pkh_address_index,
|
||||
starting_indexes.p2sh_address_index,
|
||||
starting_indexes.p2wpkh_address_index,
|
||||
starting_indexes.p2wsh_address_index,
|
||||
starting_indexes.p2tr_address_index,
|
||||
starting_indexes.p2a_address_index,
|
||||
stamp,
|
||||
)?;
|
||||
|
||||
self.scripts.truncate(
|
||||
starting_indexes.height,
|
||||
starting_indexes.emptyoutputindex,
|
||||
starting_indexes.opreturnindex,
|
||||
starting_indexes.p2msoutputindex,
|
||||
starting_indexes.unknownoutputindex,
|
||||
starting_indexes.empty_output_index,
|
||||
starting_indexes.op_return_index,
|
||||
starting_indexes.p2ms_output_index,
|
||||
starting_indexes.unknown_output_index,
|
||||
stamp,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -10,52 +10,52 @@ use crate::parallel_import;
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct OutputsVecs<M: StorageMode = Rw> {
|
||||
pub first_txoutindex: M::Stored<PcoVec<Height, TxOutIndex>>,
|
||||
pub first_txout_index: M::Stored<PcoVec<Height, TxOutIndex>>,
|
||||
pub value: M::Stored<BytesVec<TxOutIndex, Sats>>,
|
||||
pub outputtype: M::Stored<BytesVec<TxOutIndex, OutputType>>,
|
||||
pub typeindex: M::Stored<BytesVec<TxOutIndex, TypeIndex>>,
|
||||
pub txindex: M::Stored<PcoVec<TxOutIndex, TxIndex>>,
|
||||
pub output_type: M::Stored<BytesVec<TxOutIndex, OutputType>>,
|
||||
pub type_index: M::Stored<BytesVec<TxOutIndex, TypeIndex>>,
|
||||
pub tx_index: M::Stored<PcoVec<TxOutIndex, TxIndex>>,
|
||||
}
|
||||
|
||||
impl OutputsVecs {
|
||||
pub fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
||||
let (first_txoutindex, value, outputtype, typeindex, txindex) = parallel_import! {
|
||||
first_txoutindex = PcoVec::forced_import(db, "first_txoutindex", version),
|
||||
let (first_txout_index, value, output_type, type_index, tx_index) = parallel_import! {
|
||||
first_txout_index = PcoVec::forced_import(db, "first_txout_index", version),
|
||||
value = BytesVec::forced_import(db, "value", version),
|
||||
outputtype = BytesVec::forced_import(db, "outputtype", version),
|
||||
typeindex = BytesVec::forced_import(db, "typeindex", version),
|
||||
txindex = PcoVec::forced_import(db, "txindex", version),
|
||||
output_type = BytesVec::forced_import(db, "output_type", version),
|
||||
type_index = BytesVec::forced_import(db, "type_index", version),
|
||||
tx_index = PcoVec::forced_import(db, "tx_index", version),
|
||||
};
|
||||
Ok(Self {
|
||||
first_txoutindex,
|
||||
first_txout_index,
|
||||
value,
|
||||
outputtype,
|
||||
typeindex,
|
||||
txindex,
|
||||
output_type,
|
||||
type_index,
|
||||
tx_index,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn truncate(&mut self, height: Height, txoutindex: TxOutIndex, stamp: Stamp) -> Result<()> {
|
||||
self.first_txoutindex
|
||||
pub fn truncate(&mut self, height: Height, txout_index: TxOutIndex, stamp: Stamp) -> Result<()> {
|
||||
self.first_txout_index
|
||||
.truncate_if_needed_with_stamp(height, stamp)?;
|
||||
self.value
|
||||
.truncate_if_needed_with_stamp(txoutindex, stamp)?;
|
||||
self.outputtype
|
||||
.truncate_if_needed_with_stamp(txoutindex, stamp)?;
|
||||
self.typeindex
|
||||
.truncate_if_needed_with_stamp(txoutindex, stamp)?;
|
||||
self.txindex
|
||||
.truncate_if_needed_with_stamp(txoutindex, stamp)?;
|
||||
.truncate_if_needed_with_stamp(txout_index, stamp)?;
|
||||
self.output_type
|
||||
.truncate_if_needed_with_stamp(txout_index, stamp)?;
|
||||
self.type_index
|
||||
.truncate_if_needed_with_stamp(txout_index, stamp)?;
|
||||
self.tx_index
|
||||
.truncate_if_needed_with_stamp(txout_index, stamp)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn par_iter_mut_any(&mut self) -> impl ParallelIterator<Item = &mut dyn AnyStoredVec> {
|
||||
[
|
||||
&mut self.first_txoutindex as &mut dyn AnyStoredVec,
|
||||
&mut self.first_txout_index as &mut dyn AnyStoredVec,
|
||||
&mut self.value,
|
||||
&mut self.outputtype,
|
||||
&mut self.typeindex,
|
||||
&mut self.txindex,
|
||||
&mut self.output_type,
|
||||
&mut self.type_index,
|
||||
&mut self.tx_index,
|
||||
]
|
||||
.into_par_iter()
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ use crate::parallel_import;
|
||||
#[derive(Traversable)]
|
||||
pub struct ScriptTypeVecs<I: VecIndex + PcoVecValue + Formattable + Serialize + JsonSchema, M: StorageMode = Rw> {
|
||||
pub first_index: M::Stored<PcoVec<Height, I>>,
|
||||
pub to_txindex: M::Stored<PcoVec<I, TxIndex>>,
|
||||
pub to_tx_index: M::Stored<PcoVec<I, TxIndex>>,
|
||||
}
|
||||
|
||||
#[derive(Traversable)]
|
||||
@@ -30,39 +30,39 @@ pub struct ScriptsVecs<M: StorageMode = Rw> {
|
||||
impl ScriptsVecs {
|
||||
pub fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
||||
let (
|
||||
first_emptyoutputindex,
|
||||
first_opreturnindex,
|
||||
first_p2msoutputindex,
|
||||
first_unknownoutputindex,
|
||||
emptyoutputindex_to_txindex,
|
||||
opreturnindex_to_txindex,
|
||||
p2msoutputindex_to_txindex,
|
||||
unknownoutputindex_to_txindex,
|
||||
first_empty_output_index,
|
||||
first_op_return_index,
|
||||
first_p2ms_output_index,
|
||||
first_unknown_output_index,
|
||||
empty_output_index_to_tx_index,
|
||||
op_return_index_to_tx_index,
|
||||
p2ms_output_index_to_tx_index,
|
||||
unknown_output_index_to_tx_index,
|
||||
) = parallel_import! {
|
||||
first_emptyoutputindex = PcoVec::forced_import(db, "first_emptyoutputindex", version),
|
||||
first_opreturnindex = PcoVec::forced_import(db, "first_opreturnindex", version),
|
||||
first_p2msoutputindex = PcoVec::forced_import(db, "first_p2msoutputindex", version),
|
||||
first_unknownoutputindex = PcoVec::forced_import(db, "first_unknownoutputindex", version),
|
||||
emptyoutputindex_to_txindex = PcoVec::forced_import(db, "txindex", version),
|
||||
opreturnindex_to_txindex = PcoVec::forced_import(db, "txindex", version),
|
||||
p2msoutputindex_to_txindex = PcoVec::forced_import(db, "txindex", version),
|
||||
unknownoutputindex_to_txindex = PcoVec::forced_import(db, "txindex", version),
|
||||
first_empty_output_index = PcoVec::forced_import(db, "first_empty_output_index", version),
|
||||
first_op_return_index = PcoVec::forced_import(db, "first_op_return_index", version),
|
||||
first_p2ms_output_index = PcoVec::forced_import(db, "first_p2ms_output_index", version),
|
||||
first_unknown_output_index = PcoVec::forced_import(db, "first_unknown_output_index", version),
|
||||
empty_output_index_to_tx_index = PcoVec::forced_import(db, "tx_index", version),
|
||||
op_return_index_to_tx_index = PcoVec::forced_import(db, "tx_index", version),
|
||||
p2ms_output_index_to_tx_index = PcoVec::forced_import(db, "tx_index", version),
|
||||
unknown_output_index_to_tx_index = PcoVec::forced_import(db, "tx_index", version),
|
||||
};
|
||||
Ok(Self {
|
||||
empty: ScriptTypeVecs { first_index: first_emptyoutputindex, to_txindex: emptyoutputindex_to_txindex },
|
||||
opreturn: ScriptTypeVecs { first_index: first_opreturnindex, to_txindex: opreturnindex_to_txindex },
|
||||
p2ms: ScriptTypeVecs { first_index: first_p2msoutputindex, to_txindex: p2msoutputindex_to_txindex },
|
||||
unknown: ScriptTypeVecs { first_index: first_unknownoutputindex, to_txindex: unknownoutputindex_to_txindex },
|
||||
empty: ScriptTypeVecs { first_index: first_empty_output_index, to_tx_index: empty_output_index_to_tx_index },
|
||||
opreturn: ScriptTypeVecs { first_index: first_op_return_index, to_tx_index: op_return_index_to_tx_index },
|
||||
p2ms: ScriptTypeVecs { first_index: first_p2ms_output_index, to_tx_index: p2ms_output_index_to_tx_index },
|
||||
unknown: ScriptTypeVecs { first_index: first_unknown_output_index, to_tx_index: unknown_output_index_to_tx_index },
|
||||
})
|
||||
}
|
||||
|
||||
pub fn truncate(
|
||||
&mut self,
|
||||
height: Height,
|
||||
emptyoutputindex: EmptyOutputIndex,
|
||||
opreturnindex: OpReturnIndex,
|
||||
p2msoutputindex: P2MSOutputIndex,
|
||||
unknownoutputindex: UnknownOutputIndex,
|
||||
empty_output_index: EmptyOutputIndex,
|
||||
op_return_index: OpReturnIndex,
|
||||
p2ms_output_index: P2MSOutputIndex,
|
||||
unknown_output_index: UnknownOutputIndex,
|
||||
stamp: Stamp,
|
||||
) -> Result<()> {
|
||||
self.empty.first_index
|
||||
@@ -73,14 +73,14 @@ impl ScriptsVecs {
|
||||
.truncate_if_needed_with_stamp(height, stamp)?;
|
||||
self.unknown.first_index
|
||||
.truncate_if_needed_with_stamp(height, stamp)?;
|
||||
self.empty.to_txindex
|
||||
.truncate_if_needed_with_stamp(emptyoutputindex, stamp)?;
|
||||
self.opreturn.to_txindex
|
||||
.truncate_if_needed_with_stamp(opreturnindex, stamp)?;
|
||||
self.p2ms.to_txindex
|
||||
.truncate_if_needed_with_stamp(p2msoutputindex, stamp)?;
|
||||
self.unknown.to_txindex
|
||||
.truncate_if_needed_with_stamp(unknownoutputindex, stamp)?;
|
||||
self.empty.to_tx_index
|
||||
.truncate_if_needed_with_stamp(empty_output_index, stamp)?;
|
||||
self.opreturn.to_tx_index
|
||||
.truncate_if_needed_with_stamp(op_return_index, stamp)?;
|
||||
self.p2ms.to_tx_index
|
||||
.truncate_if_needed_with_stamp(p2ms_output_index, stamp)?;
|
||||
self.unknown.to_tx_index
|
||||
.truncate_if_needed_with_stamp(unknown_output_index, stamp)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -90,10 +90,10 @@ impl ScriptsVecs {
|
||||
&mut self.opreturn.first_index,
|
||||
&mut self.p2ms.first_index,
|
||||
&mut self.unknown.first_index,
|
||||
&mut self.empty.to_txindex,
|
||||
&mut self.opreturn.to_txindex,
|
||||
&mut self.p2ms.to_txindex,
|
||||
&mut self.unknown.to_txindex,
|
||||
&mut self.empty.to_tx_index,
|
||||
&mut self.opreturn.to_tx_index,
|
||||
&mut self.p2ms.to_tx_index,
|
||||
&mut self.unknown.to_tx_index,
|
||||
]
|
||||
.into_par_iter()
|
||||
}
|
||||
|
||||
@@ -13,23 +13,23 @@ use crate::parallel_import;
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct TransactionsVecs<M: StorageMode = Rw> {
|
||||
pub first_txindex: M::Stored<PcoVec<Height, TxIndex>>,
|
||||
pub first_tx_index: M::Stored<PcoVec<Height, TxIndex>>,
|
||||
pub height: M::Stored<PcoVec<TxIndex, Height>>,
|
||||
pub txid: M::Stored<BytesVec<TxIndex, Txid>>,
|
||||
pub txversion: M::Stored<PcoVec<TxIndex, TxVersion>>,
|
||||
pub rawlocktime: M::Stored<PcoVec<TxIndex, RawLockTime>>,
|
||||
pub tx_version: M::Stored<PcoVec<TxIndex, TxVersion>>,
|
||||
pub raw_locktime: M::Stored<PcoVec<TxIndex, RawLockTime>>,
|
||||
pub base_size: M::Stored<PcoVec<TxIndex, StoredU32>>,
|
||||
pub total_size: M::Stored<PcoVec<TxIndex, StoredU32>>,
|
||||
pub is_explicitly_rbf: M::Stored<PcoVec<TxIndex, StoredBool>>,
|
||||
pub first_txinindex: M::Stored<PcoVec<TxIndex, TxInIndex>>,
|
||||
pub first_txoutindex: M::Stored<BytesVec<TxIndex, TxOutIndex>>,
|
||||
pub first_txin_index: M::Stored<PcoVec<TxIndex, TxInIndex>>,
|
||||
pub first_txout_index: M::Stored<BytesVec<TxIndex, TxOutIndex>>,
|
||||
}
|
||||
|
||||
pub struct TxMetadataVecs<'a> {
|
||||
pub height: &'a mut PcoVec<TxIndex, Height>,
|
||||
pub txversion: &'a mut PcoVec<TxIndex, TxVersion>,
|
||||
pub tx_version: &'a mut PcoVec<TxIndex, TxVersion>,
|
||||
pub txid: &'a mut BytesVec<TxIndex, Txid>,
|
||||
pub rawlocktime: &'a mut PcoVec<TxIndex, RawLockTime>,
|
||||
pub raw_locktime: &'a mut PcoVec<TxIndex, RawLockTime>,
|
||||
pub base_size: &'a mut PcoVec<TxIndex, StoredU32>,
|
||||
pub total_size: &'a mut PcoVec<TxIndex, StoredU32>,
|
||||
pub is_explicitly_rbf: &'a mut PcoVec<TxIndex, StoredBool>,
|
||||
@@ -44,13 +44,13 @@ impl TransactionsVecs {
|
||||
TxMetadataVecs<'_>,
|
||||
) {
|
||||
(
|
||||
&mut self.first_txoutindex,
|
||||
&mut self.first_txinindex,
|
||||
&mut self.first_txout_index,
|
||||
&mut self.first_txin_index,
|
||||
TxMetadataVecs {
|
||||
height: &mut self.height,
|
||||
txversion: &mut self.txversion,
|
||||
tx_version: &mut self.tx_version,
|
||||
txid: &mut self.txid,
|
||||
rawlocktime: &mut self.rawlocktime,
|
||||
raw_locktime: &mut self.raw_locktime,
|
||||
base_size: &mut self.base_size,
|
||||
total_size: &mut self.total_size,
|
||||
is_explicitly_rbf: &mut self.is_explicitly_rbf,
|
||||
@@ -60,76 +60,76 @@ impl TransactionsVecs {
|
||||
|
||||
pub fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
||||
let (
|
||||
first_txindex,
|
||||
first_tx_index,
|
||||
height,
|
||||
txid,
|
||||
txversion,
|
||||
rawlocktime,
|
||||
tx_version,
|
||||
raw_locktime,
|
||||
base_size,
|
||||
total_size,
|
||||
is_explicitly_rbf,
|
||||
first_txinindex,
|
||||
first_txoutindex,
|
||||
first_txin_index,
|
||||
first_txout_index,
|
||||
) = parallel_import! {
|
||||
first_txindex = PcoVec::forced_import(db, "first_txindex", version),
|
||||
first_tx_index = PcoVec::forced_import(db, "first_tx_index", version),
|
||||
height = PcoVec::forced_import(db, "height", version),
|
||||
txid = BytesVec::forced_import(db, "txid", version),
|
||||
txversion = PcoVec::forced_import(db, "txversion", version),
|
||||
rawlocktime = PcoVec::forced_import(db, "rawlocktime", version),
|
||||
tx_version = PcoVec::forced_import(db, "tx_version", version),
|
||||
raw_locktime = PcoVec::forced_import(db, "raw_locktime", version),
|
||||
base_size = PcoVec::forced_import(db, "base_size", version),
|
||||
total_size = PcoVec::forced_import(db, "total_size", version),
|
||||
is_explicitly_rbf = PcoVec::forced_import(db, "is_explicitly_rbf", version),
|
||||
first_txinindex = PcoVec::forced_import(db, "first_txinindex", version),
|
||||
first_txoutindex = BytesVec::forced_import(db, "first_txoutindex", version),
|
||||
first_txin_index = PcoVec::forced_import(db, "first_txin_index", version),
|
||||
first_txout_index = BytesVec::forced_import(db, "first_txout_index", version),
|
||||
};
|
||||
Ok(Self {
|
||||
first_txindex,
|
||||
first_tx_index,
|
||||
height,
|
||||
txid,
|
||||
txversion,
|
||||
rawlocktime,
|
||||
tx_version,
|
||||
raw_locktime,
|
||||
base_size,
|
||||
total_size,
|
||||
is_explicitly_rbf,
|
||||
first_txinindex,
|
||||
first_txoutindex,
|
||||
first_txin_index,
|
||||
first_txout_index,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn truncate(&mut self, height: Height, txindex: TxIndex, stamp: Stamp) -> Result<()> {
|
||||
self.first_txindex
|
||||
pub fn truncate(&mut self, height: Height, tx_index: TxIndex, stamp: Stamp) -> Result<()> {
|
||||
self.first_tx_index
|
||||
.truncate_if_needed_with_stamp(height, stamp)?;
|
||||
self.height.truncate_if_needed_with_stamp(txindex, stamp)?;
|
||||
self.txid.truncate_if_needed_with_stamp(txindex, stamp)?;
|
||||
self.txversion
|
||||
.truncate_if_needed_with_stamp(txindex, stamp)?;
|
||||
self.rawlocktime
|
||||
.truncate_if_needed_with_stamp(txindex, stamp)?;
|
||||
self.height.truncate_if_needed_with_stamp(tx_index, stamp)?;
|
||||
self.txid.truncate_if_needed_with_stamp(tx_index, stamp)?;
|
||||
self.tx_version
|
||||
.truncate_if_needed_with_stamp(tx_index, stamp)?;
|
||||
self.raw_locktime
|
||||
.truncate_if_needed_with_stamp(tx_index, stamp)?;
|
||||
self.base_size
|
||||
.truncate_if_needed_with_stamp(txindex, stamp)?;
|
||||
.truncate_if_needed_with_stamp(tx_index, stamp)?;
|
||||
self.total_size
|
||||
.truncate_if_needed_with_stamp(txindex, stamp)?;
|
||||
.truncate_if_needed_with_stamp(tx_index, stamp)?;
|
||||
self.is_explicitly_rbf
|
||||
.truncate_if_needed_with_stamp(txindex, stamp)?;
|
||||
self.first_txinindex
|
||||
.truncate_if_needed_with_stamp(txindex, stamp)?;
|
||||
self.first_txoutindex
|
||||
.truncate_if_needed_with_stamp(txindex, stamp)?;
|
||||
.truncate_if_needed_with_stamp(tx_index, stamp)?;
|
||||
self.first_txin_index
|
||||
.truncate_if_needed_with_stamp(tx_index, stamp)?;
|
||||
self.first_txout_index
|
||||
.truncate_if_needed_with_stamp(tx_index, stamp)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn par_iter_mut_any(&mut self) -> impl ParallelIterator<Item = &mut dyn AnyStoredVec> {
|
||||
[
|
||||
&mut self.first_txindex as &mut dyn AnyStoredVec,
|
||||
&mut self.first_tx_index as &mut dyn AnyStoredVec,
|
||||
&mut self.height,
|
||||
&mut self.txid,
|
||||
&mut self.txversion,
|
||||
&mut self.rawlocktime,
|
||||
&mut self.tx_version,
|
||||
&mut self.raw_locktime,
|
||||
&mut self.base_size,
|
||||
&mut self.total_size,
|
||||
&mut self.is_explicitly_rbf,
|
||||
&mut self.first_txinindex,
|
||||
&mut self.first_txoutindex,
|
||||
&mut self.first_txin_index,
|
||||
&mut self.first_txout_index,
|
||||
]
|
||||
.into_par_iter()
|
||||
}
|
||||
|
||||
@@ -153,15 +153,15 @@ fn main() {
|
||||
let total_txs = indexer.vecs.transactions.height.len();
|
||||
let total_outputs = indexer.vecs.outputs.value.len();
|
||||
|
||||
let first_txindex: Vec<TxIndex> = indexer.vecs.transactions.first_txindex.collect();
|
||||
let out_first: Vec<TxOutIndex> = indexer.vecs.outputs.first_txoutindex.collect();
|
||||
let first_tx_index: Vec<TxIndex> = indexer.vecs.transactions.first_tx_index.collect();
|
||||
let out_first: Vec<TxOutIndex> = indexer.vecs.outputs.first_txout_index.collect();
|
||||
|
||||
let ref_config = Config::default();
|
||||
let earliest_start = *start_heights.iter().min().unwrap();
|
||||
|
||||
for h in START_HEIGHT..total_heights {
|
||||
let ft = first_txindex[h];
|
||||
let next_ft = first_txindex
|
||||
let ft = first_tx_index[h];
|
||||
let next_ft = first_tx_index
|
||||
.get(h + 1)
|
||||
.copied()
|
||||
.unwrap_or(TxIndex::from(total_txs));
|
||||
@@ -170,7 +170,7 @@ fn main() {
|
||||
indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txoutindex
|
||||
.first_txout_index
|
||||
.collect_one(ft + 1)
|
||||
.unwrap()
|
||||
.to_usize()
|
||||
@@ -199,7 +199,7 @@ fn main() {
|
||||
let output_types: Vec<OutputType> = indexer
|
||||
.vecs
|
||||
.outputs
|
||||
.outputtype
|
||||
.output_type
|
||||
.collect_range_at(out_start, out_end);
|
||||
|
||||
// Build full histogram and per-digit histograms.
|
||||
|
||||
@@ -49,8 +49,8 @@ fn main() {
|
||||
let total_txs = indexer.vecs.transactions.height.len();
|
||||
let total_outputs = indexer.vecs.outputs.value.len();
|
||||
|
||||
let first_txindex: Vec<TxIndex> = indexer.vecs.transactions.first_txindex.collect();
|
||||
let out_first: Vec<TxOutIndex> = indexer.vecs.outputs.first_txoutindex.collect();
|
||||
let first_tx_index: Vec<TxIndex> = indexer.vecs.transactions.first_tx_index.collect();
|
||||
let out_first: Vec<TxOutIndex> = indexer.vecs.outputs.first_txout_index.collect();
|
||||
|
||||
let ref_config = Config::default();
|
||||
|
||||
@@ -74,8 +74,8 @@ fn main() {
|
||||
let end_height = (last_start + window_size + 100).min(total_heights);
|
||||
|
||||
for h in START_HEIGHT..end_height {
|
||||
let ft = first_txindex[h];
|
||||
let next_ft = first_txindex
|
||||
let ft = first_tx_index[h];
|
||||
let next_ft = first_tx_index
|
||||
.get(h + 1)
|
||||
.copied()
|
||||
.unwrap_or(TxIndex::from(total_txs));
|
||||
@@ -84,7 +84,7 @@ fn main() {
|
||||
indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txoutindex
|
||||
.first_txout_index
|
||||
.collect_one(ft + 1)
|
||||
.unwrap()
|
||||
.to_usize()
|
||||
@@ -109,7 +109,7 @@ fn main() {
|
||||
let output_types: Vec<OutputType> = indexer
|
||||
.vecs
|
||||
.outputs
|
||||
.outputtype
|
||||
.output_type
|
||||
.collect_range_at(out_start, out_end);
|
||||
|
||||
let mut hist = [0u32; NUM_BINS];
|
||||
|
||||
@@ -94,9 +94,9 @@ fn main() {
|
||||
let total_txs = indexer.vecs.transactions.height.len();
|
||||
let total_outputs = indexer.vecs.outputs.value.len();
|
||||
|
||||
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 outputtype_reader = indexer.vecs.outputs.outputtype.reader();
|
||||
let output_type_reader = indexer.vecs.outputs.output_type.reader();
|
||||
|
||||
let config = Config::default();
|
||||
let total_blocks = total_heights - lowest;
|
||||
@@ -110,28 +110,28 @@ fn main() {
|
||||
let mut blocks: Vec<BlockData> = Vec::with_capacity(total_blocks);
|
||||
|
||||
for h in lowest..total_heights {
|
||||
let first_txindex: TxIndex = indexer
|
||||
let first_tx_index: TxIndex = indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txindex
|
||||
.first_tx_index
|
||||
.collect_one_at(h)
|
||||
.unwrap();
|
||||
let next_first_txindex: TxIndex = indexer
|
||||
let next_first_tx_index: TxIndex = indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txindex
|
||||
.first_tx_index
|
||||
.collect_one_at(h + 1)
|
||||
.unwrap_or(TxIndex::from(total_txs));
|
||||
|
||||
let out_start = if first_txindex.to_usize() + 1 < next_first_txindex.to_usize() {
|
||||
first_txoutindex_reader
|
||||
.get(first_txindex.to_usize() + 1)
|
||||
let out_start = if first_tx_index.to_usize() + 1 < next_first_tx_index.to_usize() {
|
||||
first_txout_index_reader
|
||||
.get(first_tx_index.to_usize() + 1)
|
||||
.to_usize()
|
||||
} else {
|
||||
indexer
|
||||
.vecs
|
||||
.outputs
|
||||
.first_txoutindex
|
||||
.first_txout_index
|
||||
.collect_one_at(h + 1)
|
||||
.unwrap_or(TxOutIndex::from(total_outputs))
|
||||
.to_usize()
|
||||
@@ -139,7 +139,7 @@ fn main() {
|
||||
let out_end: usize = indexer
|
||||
.vecs
|
||||
.outputs
|
||||
.first_txoutindex
|
||||
.first_txout_index
|
||||
.collect_one_at(h + 1)
|
||||
.unwrap_or(TxOutIndex::from(total_outputs))
|
||||
.to_usize();
|
||||
@@ -147,7 +147,7 @@ fn main() {
|
||||
let mut hist = Box::new([0u32; NUM_BINS]);
|
||||
for i in out_start..out_end {
|
||||
let sats: Sats = value_reader.get(i);
|
||||
let output_type = outputtype_reader.get(i);
|
||||
let output_type = output_type_reader.get(i);
|
||||
if config.excluded_output_types.contains(&output_type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -185,8 +185,8 @@ fn main() {
|
||||
let total_outputs = indexer.vecs.outputs.value.len();
|
||||
|
||||
// Pre-collect height-indexed vecs (small). Transaction-indexed vecs are too large.
|
||||
let first_txindex: Vec<TxIndex> = indexer.vecs.transactions.first_txindex.collect();
|
||||
let out_first: Vec<TxOutIndex> = indexer.vecs.outputs.first_txoutindex.collect();
|
||||
let first_tx_index: Vec<TxIndex> = indexer.vecs.transactions.first_tx_index.collect();
|
||||
let out_first: Vec<TxOutIndex> = indexer.vecs.outputs.first_txout_index.collect();
|
||||
|
||||
let ref_config = Config::default();
|
||||
|
||||
@@ -200,8 +200,8 @@ fn main() {
|
||||
let mut current_di: Option<usize> = None;
|
||||
|
||||
for h in START_HEIGHT..total_heights {
|
||||
let ft = first_txindex[h];
|
||||
let next_ft = first_txindex
|
||||
let ft = first_tx_index[h];
|
||||
let next_ft = first_tx_index
|
||||
.get(h + 1)
|
||||
.copied()
|
||||
.unwrap_or(TxIndex::from(total_txs));
|
||||
@@ -210,7 +210,7 @@ fn main() {
|
||||
indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txoutindex
|
||||
.first_txout_index
|
||||
.collect_one(ft + 1)
|
||||
.unwrap()
|
||||
.to_usize()
|
||||
@@ -235,7 +235,7 @@ fn main() {
|
||||
let output_types: Vec<OutputType> = indexer
|
||||
.vecs
|
||||
.outputs
|
||||
.outputtype
|
||||
.output_type
|
||||
.collect_range_at(out_start, out_end);
|
||||
|
||||
let mut hist = [0u32; NUM_BINS];
|
||||
|
||||
@@ -166,16 +166,16 @@ fn main() {
|
||||
let total_txs = indexer.vecs.transactions.height.len();
|
||||
let total_outputs = indexer.vecs.outputs.value.len();
|
||||
|
||||
let first_txindex: Vec<TxIndex> = indexer.vecs.transactions.first_txindex.collect();
|
||||
let out_first: Vec<TxOutIndex> = indexer.vecs.outputs.first_txoutindex.collect();
|
||||
let first_tx_index: Vec<TxIndex> = indexer.vecs.transactions.first_tx_index.collect();
|
||||
let out_first: Vec<TxOutIndex> = indexer.vecs.outputs.first_txout_index.collect();
|
||||
|
||||
let ref_config = Config::default();
|
||||
let total_blocks = total_heights - sweep_start;
|
||||
let mut blocks: Vec<BlockData> = Vec::with_capacity(total_blocks);
|
||||
|
||||
for h in START_HEIGHT..total_heights {
|
||||
let ft = first_txindex[h];
|
||||
let next_ft = first_txindex
|
||||
let ft = first_tx_index[h];
|
||||
let next_ft = first_tx_index
|
||||
.get(h + 1)
|
||||
.copied()
|
||||
.unwrap_or(TxIndex::from(total_txs));
|
||||
@@ -184,7 +184,7 @@ fn main() {
|
||||
indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txoutindex
|
||||
.first_txout_index
|
||||
.collect_one(ft + 1)
|
||||
.unwrap()
|
||||
.to_usize()
|
||||
@@ -213,7 +213,7 @@ fn main() {
|
||||
let output_types: Vec<OutputType> = indexer
|
||||
.vecs
|
||||
.outputs
|
||||
.outputtype
|
||||
.output_type
|
||||
.collect_range_at(out_start, out_end);
|
||||
|
||||
let mut full_hist = Box::new([0u32; NUM_BINS]);
|
||||
|
||||
@@ -164,8 +164,8 @@ fn main() {
|
||||
let total_txs = indexer.vecs.transactions.height.len();
|
||||
let total_outputs = indexer.vecs.outputs.value.len();
|
||||
|
||||
let first_txindex: Vec<TxIndex> = indexer.vecs.transactions.first_txindex.collect();
|
||||
let out_first: Vec<TxOutIndex> = indexer.vecs.outputs.first_txoutindex.collect();
|
||||
let first_tx_index: Vec<TxIndex> = indexer.vecs.transactions.first_tx_index.collect();
|
||||
let out_first: Vec<TxOutIndex> = indexer.vecs.outputs.first_txout_index.collect();
|
||||
|
||||
let ref_config = Config::default();
|
||||
let total_blocks = total_heights - sweep_start;
|
||||
@@ -176,8 +176,8 @@ fn main() {
|
||||
let max_tolerance: f64 = 0.05;
|
||||
|
||||
for h in START_HEIGHT..total_heights {
|
||||
let ft = first_txindex[h];
|
||||
let next_ft = first_txindex
|
||||
let ft = first_tx_index[h];
|
||||
let next_ft = first_tx_index
|
||||
.get(h + 1)
|
||||
.copied()
|
||||
.unwrap_or(TxIndex::from(total_txs));
|
||||
@@ -186,7 +186,7 @@ fn main() {
|
||||
indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txoutindex
|
||||
.first_txout_index
|
||||
.collect_one(ft + 1)
|
||||
.unwrap()
|
||||
.to_usize()
|
||||
@@ -215,7 +215,7 @@ fn main() {
|
||||
let output_types: Vec<OutputType> = indexer
|
||||
.vecs
|
||||
.outputs
|
||||
.outputtype
|
||||
.output_type
|
||||
.collect_range_at(out_start, out_end);
|
||||
|
||||
let mut full_hist = Box::new([0u32; NUM_BINS]);
|
||||
|
||||
@@ -152,14 +152,14 @@ fn main() {
|
||||
let total_outputs = indexer.vecs.outputs.value.len();
|
||||
|
||||
// Pre-collect height-indexed vecs (small). Transaction-indexed vecs are too large.
|
||||
let first_txindex: Vec<TxIndex> = indexer.vecs.transactions.first_txindex.collect();
|
||||
let out_first: Vec<TxOutIndex> = indexer.vecs.outputs.first_txoutindex.collect();
|
||||
let first_tx_index: Vec<TxIndex> = indexer.vecs.transactions.first_tx_index.collect();
|
||||
let out_first: Vec<TxOutIndex> = indexer.vecs.outputs.first_txout_index.collect();
|
||||
|
||||
let ref_config = Config::default();
|
||||
|
||||
for h in START_HEIGHT..total_heights {
|
||||
let ft = first_txindex[h];
|
||||
let next_ft = first_txindex
|
||||
let ft = first_tx_index[h];
|
||||
let next_ft = first_tx_index
|
||||
.get(h + 1)
|
||||
.copied()
|
||||
.unwrap_or(TxIndex::from(total_txs));
|
||||
@@ -168,7 +168,7 @@ fn main() {
|
||||
indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txoutindex
|
||||
.first_txout_index
|
||||
.collect_one(ft + 1)
|
||||
.unwrap()
|
||||
.to_usize()
|
||||
@@ -194,7 +194,7 @@ fn main() {
|
||||
let output_types: Vec<OutputType> = indexer
|
||||
.vecs
|
||||
.outputs
|
||||
.outputtype
|
||||
.output_type
|
||||
.collect_range_at(out_start, out_end);
|
||||
|
||||
let mut hist = [0u32; NUM_BINS];
|
||||
|
||||
@@ -48,7 +48,7 @@ pub fn main() -> Result<()> {
|
||||
dbg!(
|
||||
indexer
|
||||
.stores
|
||||
.addresstype_to_addresshash_to_addressindex
|
||||
.address_type_to_address_hash_to_address_index
|
||||
.get_unwrap(OutputType::P2WSH)
|
||||
.approximate_len()
|
||||
);
|
||||
|
||||
@@ -32,16 +32,16 @@ impl Query {
|
||||
return Err(Error::InvalidAddress);
|
||||
};
|
||||
|
||||
let outputtype = OutputType::from(&script);
|
||||
let Ok(bytes) = AddressBytes::try_from((&script, outputtype)) else {
|
||||
let output_type = OutputType::from(&script);
|
||||
let Ok(bytes) = AddressBytes::try_from((&script, output_type)) else {
|
||||
return Err(Error::InvalidAddress);
|
||||
};
|
||||
let addresstype = outputtype;
|
||||
let address_type = output_type;
|
||||
let hash = AddressHash::from(&bytes);
|
||||
|
||||
let Ok(Some(type_index)) = stores
|
||||
.addresstype_to_addresshash_to_addressindex
|
||||
.get_unwrap(addresstype)
|
||||
.address_type_to_address_hash_to_address_index
|
||||
.get_unwrap(address_type)
|
||||
.get(&hash)
|
||||
.map(|opt| opt.map(|cow| cow.into_owned()))
|
||||
else {
|
||||
@@ -51,7 +51,7 @@ impl Query {
|
||||
let any_address_index = computer
|
||||
.distribution
|
||||
.any_address_indexes
|
||||
.get_once(outputtype, type_index)?;
|
||||
.get_once(output_type, type_index)?;
|
||||
|
||||
let address_data = match any_address_index.to_enum() {
|
||||
AnyAddressDataIndexEnum::Funded(index) => computer
|
||||
@@ -99,7 +99,7 @@ impl Query {
|
||||
let txindices = self.address_txindices(&address, after_txid, limit)?;
|
||||
txindices
|
||||
.into_iter()
|
||||
.map(|txindex| self.transaction_by_index(txindex))
|
||||
.map(|tx_index| self.transaction_by_index(tx_index))
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ impl Query {
|
||||
let txid_reader = self.indexer().vecs.transactions.txid.reader();
|
||||
let txids = txindices
|
||||
.into_iter()
|
||||
.map(|txindex| txid_reader.get(txindex.to_usize()))
|
||||
.map(|tx_index| txid_reader.get(tx_index.to_usize()))
|
||||
.collect();
|
||||
Ok(txids)
|
||||
}
|
||||
@@ -127,23 +127,23 @@ impl Query {
|
||||
let indexer = self.indexer();
|
||||
let stores = &indexer.stores;
|
||||
|
||||
let (outputtype, type_index) = self.resolve_address(address)?;
|
||||
let (output_type, type_index) = self.resolve_address(address)?;
|
||||
|
||||
let store = stores
|
||||
.addresstype_to_addressindex_and_txindex
|
||||
.get(outputtype)
|
||||
.address_type_to_address_index_and_tx_index
|
||||
.get(output_type)
|
||||
.unwrap();
|
||||
|
||||
let prefix = u32::from(type_index).to_be_bytes();
|
||||
|
||||
let after_txindex = if let Some(after_txid) = after_txid {
|
||||
let txindex = stores
|
||||
.txidprefix_to_txindex
|
||||
let after_tx_index = if let Some(after_txid) = after_txid {
|
||||
let tx_index = stores
|
||||
.txid_prefix_to_tx_index
|
||||
.get(&after_txid.into())
|
||||
.map_err(|_| Error::UnknownTxid)?
|
||||
.ok_or(Error::UnknownTxid)?
|
||||
.into_owned();
|
||||
Some(txindex)
|
||||
Some(tx_index)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -152,14 +152,14 @@ impl Query {
|
||||
.prefix(prefix)
|
||||
.rev()
|
||||
.filter(|(key, _): &(AddressIndexTxIndex, Unit)| {
|
||||
if let Some(after) = after_txindex {
|
||||
key.txindex() < after
|
||||
if let Some(after) = after_tx_index {
|
||||
key.tx_index() < after
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.take(limit)
|
||||
.map(|(key, _)| key.txindex())
|
||||
.map(|(key, _)| key.tx_index())
|
||||
.collect())
|
||||
}
|
||||
|
||||
@@ -168,37 +168,37 @@ impl Query {
|
||||
let stores = &indexer.stores;
|
||||
let vecs = &indexer.vecs;
|
||||
|
||||
let (outputtype, type_index) = self.resolve_address(&address)?;
|
||||
let (output_type, type_index) = self.resolve_address(&address)?;
|
||||
|
||||
let store = stores
|
||||
.addresstype_to_addressindex_and_unspentoutpoint
|
||||
.get(outputtype)
|
||||
.address_type_to_address_index_and_unspent_outpoint
|
||||
.get(output_type)
|
||||
.unwrap();
|
||||
|
||||
let prefix = u32::from(type_index).to_be_bytes();
|
||||
|
||||
let outpoints: Vec<(TxIndex, Vout)> = store
|
||||
.prefix(prefix)
|
||||
.map(|(key, _): (AddressIndexOutPoint, Unit)| (key.txindex(), key.vout()))
|
||||
.map(|(key, _): (AddressIndexOutPoint, Unit)| (key.tx_index(), key.vout()))
|
||||
.collect();
|
||||
|
||||
let txid_reader = vecs.transactions.txid.reader();
|
||||
let first_txoutindex_reader = vecs.transactions.first_txoutindex.reader();
|
||||
let first_txout_index_reader = vecs.transactions.first_txout_index.reader();
|
||||
let value_reader = vecs.outputs.value.reader();
|
||||
let blockhash_reader = vecs.blocks.blockhash.reader();
|
||||
|
||||
let utxos: Vec<Utxo> = outpoints
|
||||
.into_iter()
|
||||
.map(|(txindex, vout)| {
|
||||
let txid: Txid = txid_reader.get(txindex.to_usize());
|
||||
.map(|(tx_index, vout)| {
|
||||
let txid: Txid = txid_reader.get(tx_index.to_usize());
|
||||
let height = vecs
|
||||
.transactions
|
||||
.height
|
||||
.collect_one_at(txindex.to_usize())
|
||||
.collect_one_at(tx_index.to_usize())
|
||||
.unwrap();
|
||||
let first_txoutindex = first_txoutindex_reader.get(txindex.to_usize());
|
||||
let txoutindex = first_txoutindex + vout;
|
||||
let value: Sats = value_reader.get(usize::from(txoutindex));
|
||||
let first_txout_index = first_txout_index_reader.get(tx_index.to_usize());
|
||||
let txout_index = first_txout_index + vout;
|
||||
let value: Sats = value_reader.get(usize::from(txout_index));
|
||||
let block_hash = blockhash_reader.get(usize::from(height));
|
||||
let block_time = vecs
|
||||
.blocks
|
||||
@@ -252,12 +252,12 @@ impl Query {
|
||||
let stores = &self.indexer().stores;
|
||||
|
||||
let bytes = AddressBytes::from_str(address)?;
|
||||
let outputtype = OutputType::from(&bytes);
|
||||
let output_type = OutputType::from(&bytes);
|
||||
let hash = AddressHash::from(&bytes);
|
||||
|
||||
let Ok(Some(type_index)) = stores
|
||||
.addresstype_to_addresshash_to_addressindex
|
||||
.get(outputtype)
|
||||
.address_type_to_address_hash_to_address_index
|
||||
.get(output_type)
|
||||
.unwrap()
|
||||
.get(&hash)
|
||||
.map(|opt| opt.map(|cow| cow.into_owned()))
|
||||
@@ -265,6 +265,6 @@ impl Query {
|
||||
return Err(Error::UnknownAddress);
|
||||
};
|
||||
|
||||
Ok((outputtype, type_index))
|
||||
Ok((output_type, type_index))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,28 +64,28 @@ impl Query {
|
||||
let sizes = indexer.vecs.blocks.total.collect_range_at(begin, end);
|
||||
let weights = indexer.vecs.blocks.weight.collect_range_at(begin, end);
|
||||
|
||||
// Batch-read first_txindex for tx_count computation (need one extra for next boundary)
|
||||
let txindex_end = if end <= max_height.to_usize() {
|
||||
// Batch-read first_tx_index for tx_count computation (need one extra for next boundary)
|
||||
let tx_index_end = if end <= max_height.to_usize() {
|
||||
end + 1
|
||||
} else {
|
||||
end
|
||||
};
|
||||
let first_txindexes: Vec<TxIndex> = indexer
|
||||
let first_tx_indexes: Vec<TxIndex> = indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txindex
|
||||
.collect_range_at(begin, txindex_end);
|
||||
let total_txs = computer.indexes.txindex.identity.len();
|
||||
.first_tx_index
|
||||
.collect_range_at(begin, tx_index_end);
|
||||
let total_txs = computer.indexes.tx_index.identity.len();
|
||||
|
||||
let mut blocks = Vec::with_capacity(count);
|
||||
for i in (0..count).rev() {
|
||||
let height = Height::from(begin + i);
|
||||
let blockhash = indexer.vecs.blocks.blockhash.read_once(height)?;
|
||||
|
||||
let tx_count = if i + 1 < first_txindexes.len() {
|
||||
first_txindexes[i + 1].to_usize() - first_txindexes[i].to_usize()
|
||||
let tx_count = if i + 1 < first_tx_indexes.len() {
|
||||
first_tx_indexes[i + 1].to_usize() - first_tx_indexes[i].to_usize()
|
||||
} else {
|
||||
total_txs - first_txindexes[i].to_usize()
|
||||
total_txs - first_tx_indexes[i].to_usize()
|
||||
};
|
||||
|
||||
blocks.push(BlockInfo {
|
||||
@@ -111,7 +111,7 @@ impl Query {
|
||||
|
||||
indexer
|
||||
.stores
|
||||
.blockhashprefix_to_height
|
||||
.blockhash_prefix_to_height
|
||||
.get(&prefix)?
|
||||
.map(|h| *h)
|
||||
.ok_or(Error::NotFound("Block not found".into()))
|
||||
@@ -125,23 +125,23 @@ impl Query {
|
||||
let indexer = self.indexer();
|
||||
let computer = self.computer();
|
||||
|
||||
let first_txindex = indexer
|
||||
let first_tx_index = indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txindex
|
||||
.first_tx_index
|
||||
.collect_one(height)
|
||||
.unwrap();
|
||||
let next_first_txindex = if height < max_height {
|
||||
let next_first_tx_index = if height < max_height {
|
||||
indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txindex
|
||||
.first_tx_index
|
||||
.collect_one(height.incremented())
|
||||
.unwrap()
|
||||
} else {
|
||||
TxIndex::from(computer.indexes.txindex.identity.len())
|
||||
TxIndex::from(computer.indexes.tx_index.identity.len())
|
||||
};
|
||||
|
||||
Ok((next_first_txindex.to_usize() - first_txindex.to_usize()) as u32)
|
||||
Ok((next_first_tx_index.to_usize() - first_tx_index.to_usize()) as u32)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,21 +31,21 @@ impl Query {
|
||||
return Err(Error::OutOfRange("Block height out of range".into()));
|
||||
}
|
||||
|
||||
let first_txindex = indexer
|
||||
let first_tx_index = indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txindex
|
||||
.first_tx_index
|
||||
.collect_one(height)
|
||||
.unwrap();
|
||||
let next_first_txindex = indexer
|
||||
let next_first_tx_index = indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txindex
|
||||
.first_tx_index
|
||||
.collect_one(height.incremented())
|
||||
.unwrap_or_else(|| TxIndex::from(indexer.vecs.transactions.txid.len()));
|
||||
|
||||
let first: usize = first_txindex.into();
|
||||
let next: usize = next_first_txindex.into();
|
||||
let first: usize = first_tx_index.into();
|
||||
let next: usize = next_first_tx_index.into();
|
||||
|
||||
let txids: Vec<Txid> = indexer.vecs.transactions.txid.collect_range_at(first, next);
|
||||
|
||||
@@ -60,21 +60,21 @@ impl Query {
|
||||
return Err(Error::OutOfRange("Block height out of range".into()));
|
||||
}
|
||||
|
||||
let first_txindex = indexer
|
||||
let first_tx_index = indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txindex
|
||||
.first_tx_index
|
||||
.collect_one(height)
|
||||
.unwrap();
|
||||
let next_first_txindex = indexer
|
||||
let next_first_tx_index = indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txindex
|
||||
.first_tx_index
|
||||
.collect_one(height.incremented())
|
||||
.unwrap_or_else(|| TxIndex::from(indexer.vecs.transactions.txid.len()));
|
||||
|
||||
let first: usize = first_txindex.into();
|
||||
let next: usize = next_first_txindex.into();
|
||||
let first: usize = first_tx_index.into();
|
||||
let next: usize = next_first_tx_index.into();
|
||||
let tx_count = next - first;
|
||||
|
||||
if start_index >= tx_count {
|
||||
@@ -86,8 +86,8 @@ impl Query {
|
||||
|
||||
let mut txs = Vec::with_capacity(count);
|
||||
for i in start_index..end_index {
|
||||
let txindex = TxIndex::from(first + i);
|
||||
let tx = self.transaction_by_index(txindex)?;
|
||||
let tx_index = TxIndex::from(first + i);
|
||||
let tx = self.transaction_by_index(tx_index)?;
|
||||
txs.push(tx);
|
||||
}
|
||||
|
||||
@@ -102,29 +102,29 @@ impl Query {
|
||||
return Err(Error::OutOfRange("Block height out of range".into()));
|
||||
}
|
||||
|
||||
let first_txindex = indexer
|
||||
let first_tx_index = indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txindex
|
||||
.first_tx_index
|
||||
.collect_one(height)
|
||||
.unwrap();
|
||||
let next_first_txindex = indexer
|
||||
let next_first_tx_index = indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txindex
|
||||
.first_tx_index
|
||||
.collect_one(height.incremented())
|
||||
.unwrap_or_else(|| TxIndex::from(indexer.vecs.transactions.txid.len()));
|
||||
|
||||
let first: usize = first_txindex.into();
|
||||
let next: usize = next_first_txindex.into();
|
||||
let first: usize = first_tx_index.into();
|
||||
let next: usize = next_first_tx_index.into();
|
||||
let tx_count = next - first;
|
||||
|
||||
if index >= tx_count {
|
||||
return Err(Error::OutOfRange("Transaction index out of range".into()));
|
||||
}
|
||||
|
||||
let txindex = first + index;
|
||||
let txid = indexer.vecs.transactions.txid.reader().get(txindex);
|
||||
let tx_index = first + index;
|
||||
let txid = indexer.vecs.transactions.txid.reader().get(tx_index);
|
||||
|
||||
Ok(txid)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// TODO: INCOMPLETE - indexes_to_fee_rate.day1 doesn't have percentile fields
|
||||
// because from_txindex.rs calls remove_percentiles() before creating day1.
|
||||
// because from_tx_index.rs calls remove_percentiles() before creating day1.
|
||||
// Need to either:
|
||||
// 1. Use .height instead and convert height to day1 for iteration
|
||||
// 2. Fix from_txindex.rs to preserve percentiles for day1
|
||||
// 2. Fix from_tx_index.rs to preserve percentiles for day1
|
||||
// 3. Create a separate day1 computation path with percentiles
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
@@ -22,16 +22,16 @@ impl Query {
|
||||
// Look up confirmed transaction by txid prefix
|
||||
let prefix = TxidPrefix::from(&txid);
|
||||
let indexer = self.indexer();
|
||||
let Ok(Some(txindex)) = indexer
|
||||
let Ok(Some(tx_index)) = indexer
|
||||
.stores
|
||||
.txidprefix_to_txindex
|
||||
.txid_prefix_to_tx_index
|
||||
.get(&prefix)
|
||||
.map(|opt| opt.map(|cow| cow.into_owned()))
|
||||
else {
|
||||
return Err(Error::UnknownTxid);
|
||||
};
|
||||
|
||||
self.transaction_by_index(txindex)
|
||||
self.transaction_by_index(tx_index)
|
||||
}
|
||||
|
||||
pub fn transaction_status(&self, TxidParam { txid }: TxidParam) -> Result<TxStatus> {
|
||||
@@ -45,9 +45,9 @@ impl Query {
|
||||
// Look up confirmed transaction by txid prefix
|
||||
let prefix = TxidPrefix::from(&txid);
|
||||
let indexer = self.indexer();
|
||||
let Ok(Some(txindex)) = indexer
|
||||
let Ok(Some(tx_index)) = indexer
|
||||
.stores
|
||||
.txidprefix_to_txindex
|
||||
.txid_prefix_to_tx_index
|
||||
.get(&prefix)
|
||||
.map(|opt| opt.map(|cow| cow.into_owned()))
|
||||
else {
|
||||
@@ -59,7 +59,7 @@ impl Query {
|
||||
.vecs
|
||||
.transactions
|
||||
.height
|
||||
.collect_one(txindex)
|
||||
.collect_one(tx_index)
|
||||
.unwrap();
|
||||
let block_hash = indexer.vecs.blocks.blockhash.read_once(height)?;
|
||||
let block_time = indexer.vecs.blocks.timestamp.collect_one(height).unwrap();
|
||||
@@ -83,16 +83,16 @@ impl Query {
|
||||
// Look up confirmed transaction by txid prefix
|
||||
let prefix = TxidPrefix::from(&txid);
|
||||
let indexer = self.indexer();
|
||||
let Ok(Some(txindex)) = indexer
|
||||
let Ok(Some(tx_index)) = indexer
|
||||
.stores
|
||||
.txidprefix_to_txindex
|
||||
.txid_prefix_to_tx_index
|
||||
.get(&prefix)
|
||||
.map(|opt| opt.map(|cow| cow.into_owned()))
|
||||
else {
|
||||
return Err(Error::UnknownTxid);
|
||||
};
|
||||
|
||||
self.transaction_hex_by_index(txindex)
|
||||
self.transaction_hex_by_index(tx_index)
|
||||
}
|
||||
|
||||
pub fn outspend(&self, TxidParam { txid }: TxidParam, vout: Vout) -> Result<TxOutspend> {
|
||||
@@ -106,32 +106,32 @@ impl Query {
|
||||
// Look up confirmed transaction
|
||||
let prefix = TxidPrefix::from(&txid);
|
||||
let indexer = self.indexer();
|
||||
let Ok(Some(txindex)) = indexer
|
||||
let Ok(Some(tx_index)) = indexer
|
||||
.stores
|
||||
.txidprefix_to_txindex
|
||||
.txid_prefix_to_tx_index
|
||||
.get(&prefix)
|
||||
.map(|opt| opt.map(|cow| cow.into_owned()))
|
||||
else {
|
||||
return Err(Error::UnknownTxid);
|
||||
};
|
||||
|
||||
// Calculate txoutindex
|
||||
let first_txoutindex = indexer
|
||||
// Calculate txout_index
|
||||
let first_txout_index = indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txoutindex
|
||||
.read_once(txindex)?;
|
||||
let txoutindex = first_txoutindex + vout;
|
||||
.first_txout_index
|
||||
.read_once(tx_index)?;
|
||||
let txout_index = first_txout_index + vout;
|
||||
|
||||
// Look up spend status
|
||||
let computer = self.computer();
|
||||
let txinindex = computer.outputs.spent.txinindex.read_once(txoutindex)?;
|
||||
let txin_index = computer.outputs.spent.txin_index.read_once(txout_index)?;
|
||||
|
||||
if txinindex == TxInIndex::UNSPENT {
|
||||
if txin_index == TxInIndex::UNSPENT {
|
||||
return Ok(TxOutspend::UNSPENT);
|
||||
}
|
||||
|
||||
self.outspend_details(txinindex)
|
||||
self.outspend_details(txin_index)
|
||||
}
|
||||
|
||||
pub fn outspends(&self, TxidParam { txid }: TxidParam) -> Result<Vec<TxOutspend>> {
|
||||
@@ -146,9 +146,9 @@ impl Query {
|
||||
// Look up confirmed transaction
|
||||
let prefix = TxidPrefix::from(&txid);
|
||||
let indexer = self.indexer();
|
||||
let Ok(Some(txindex)) = indexer
|
||||
let Ok(Some(tx_index)) = indexer
|
||||
.stores
|
||||
.txidprefix_to_txindex
|
||||
.txid_prefix_to_tx_index
|
||||
.get(&prefix)
|
||||
.map(|opt| opt.map(|cow| cow.into_owned()))
|
||||
else {
|
||||
@@ -156,31 +156,31 @@ impl Query {
|
||||
};
|
||||
|
||||
// Get output range
|
||||
let first_txoutindex = indexer
|
||||
let first_txout_index = indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txoutindex
|
||||
.read_once(txindex)?;
|
||||
let next_first_txoutindex = indexer
|
||||
.first_txout_index
|
||||
.read_once(tx_index)?;
|
||||
let next_first_txout_index = indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txoutindex
|
||||
.read_once(txindex.incremented())?;
|
||||
let output_count = usize::from(next_first_txoutindex) - usize::from(first_txoutindex);
|
||||
.first_txout_index
|
||||
.read_once(tx_index.incremented())?;
|
||||
let output_count = usize::from(next_first_txout_index) - usize::from(first_txout_index);
|
||||
|
||||
// Get spend status for each output
|
||||
let computer = self.computer();
|
||||
let txinindex_reader = computer.outputs.spent.txinindex.reader();
|
||||
let txin_index_reader = computer.outputs.spent.txin_index.reader();
|
||||
|
||||
let mut outspends = Vec::with_capacity(output_count);
|
||||
for i in 0..output_count {
|
||||
let txoutindex = first_txoutindex + Vout::from(i);
|
||||
let txinindex = txinindex_reader.get(usize::from(txoutindex));
|
||||
let txout_index = first_txout_index + Vout::from(i);
|
||||
let txin_index = txin_index_reader.get(usize::from(txout_index));
|
||||
|
||||
if txinindex == TxInIndex::UNSPENT {
|
||||
if txin_index == TxInIndex::UNSPENT {
|
||||
outspends.push(TxOutspend::UNSPENT);
|
||||
} else {
|
||||
outspends.push(self.outspend_details(txinindex)?);
|
||||
outspends.push(self.outspend_details(txin_index)?);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,44 +189,44 @@ impl Query {
|
||||
|
||||
// === Helper methods ===
|
||||
|
||||
pub fn transaction_by_index(&self, txindex: TxIndex) -> Result<Transaction> {
|
||||
pub fn transaction_by_index(&self, tx_index: TxIndex) -> Result<Transaction> {
|
||||
let indexer = self.indexer();
|
||||
let reader = self.reader();
|
||||
let computer = self.computer();
|
||||
|
||||
// Get tx metadata using collect_one for PcoVec, read_once for BytesVec
|
||||
let txid = indexer.vecs.transactions.txid.read_once(txindex)?;
|
||||
let txid = indexer.vecs.transactions.txid.read_once(tx_index)?;
|
||||
let height = indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.height
|
||||
.collect_one(txindex)
|
||||
.collect_one(tx_index)
|
||||
.unwrap();
|
||||
let version = indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.txversion
|
||||
.collect_one(txindex)
|
||||
.tx_version
|
||||
.collect_one(tx_index)
|
||||
.unwrap();
|
||||
let lock_time = indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.rawlocktime
|
||||
.collect_one(txindex)
|
||||
.raw_locktime
|
||||
.collect_one(tx_index)
|
||||
.unwrap();
|
||||
let total_size = indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.total_size
|
||||
.collect_one(txindex)
|
||||
.collect_one(tx_index)
|
||||
.unwrap();
|
||||
let first_txinindex = indexer
|
||||
let first_txin_index = indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txinindex
|
||||
.collect_one(txindex)
|
||||
.first_txin_index
|
||||
.collect_one(tx_index)
|
||||
.unwrap();
|
||||
let position = computer.positions.tx.collect_one(txindex).unwrap();
|
||||
let position = computer.positions.tx.collect_one(tx_index).unwrap();
|
||||
|
||||
// Get block info for status
|
||||
let block_hash = indexer.vecs.blocks.blockhash.read_once(height)?;
|
||||
@@ -240,16 +240,16 @@ impl Query {
|
||||
|
||||
// Create readers for random access lookups
|
||||
let txid_reader = indexer.vecs.transactions.txid.reader();
|
||||
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 outputtype_reader = indexer.vecs.outputs.outputtype.reader();
|
||||
let typeindex_reader = indexer.vecs.outputs.typeindex.reader();
|
||||
let output_type_reader = indexer.vecs.outputs.output_type.reader();
|
||||
let type_index_reader = indexer.vecs.outputs.type_index.reader();
|
||||
let address_readers = indexer.vecs.addresses.address_readers();
|
||||
|
||||
// Batch-read outpoints for all inputs (avoids per-input PcoVec page decompression)
|
||||
let outpoints: Vec<_> = indexer.vecs.inputs.outpoint.collect_range_at(
|
||||
usize::from(first_txinindex),
|
||||
usize::from(first_txinindex) + tx.input.len(),
|
||||
usize::from(first_txin_index),
|
||||
usize::from(first_txin_index) + tx.input.len(),
|
||||
);
|
||||
|
||||
// Build inputs with prevout information
|
||||
@@ -266,21 +266,21 @@ impl Query {
|
||||
let (prev_txid, prev_vout, prevout) = if is_coinbase {
|
||||
(Txid::COINBASE, Vout::MAX, None)
|
||||
} else {
|
||||
let prev_txindex = outpoint.txindex();
|
||||
let prev_tx_index = outpoint.tx_index();
|
||||
let prev_vout = outpoint.vout();
|
||||
let prev_txid = txid_reader.get(prev_txindex.to_usize());
|
||||
let prev_txid = txid_reader.get(prev_tx_index.to_usize());
|
||||
|
||||
// Calculate the txoutindex for the prevout
|
||||
let prev_first_txoutindex =
|
||||
first_txoutindex_reader.get(prev_txindex.to_usize());
|
||||
let prev_txoutindex = prev_first_txoutindex + prev_vout;
|
||||
// Calculate the txout_index for the prevout
|
||||
let prev_first_txout_index =
|
||||
first_txout_index_reader.get(prev_tx_index.to_usize());
|
||||
let prev_txout_index = prev_first_txout_index + prev_vout;
|
||||
|
||||
let prev_value = value_reader.get(usize::from(prev_txoutindex));
|
||||
let prev_outputtype: OutputType =
|
||||
outputtype_reader.get(usize::from(prev_txoutindex));
|
||||
let prev_typeindex = typeindex_reader.get(usize::from(prev_txoutindex));
|
||||
let prev_value = value_reader.get(usize::from(prev_txout_index));
|
||||
let prev_output_type: OutputType =
|
||||
output_type_reader.get(usize::from(prev_txout_index));
|
||||
let prev_type_index = type_index_reader.get(usize::from(prev_txout_index));
|
||||
let script_pubkey =
|
||||
address_readers.script_pubkey(prev_outputtype, prev_typeindex);
|
||||
address_readers.script_pubkey(prev_output_type, prev_type_index);
|
||||
|
||||
let prevout = Some(TxOut::from((script_pubkey, prev_value)));
|
||||
|
||||
@@ -318,7 +318,7 @@ impl Query {
|
||||
};
|
||||
|
||||
let mut transaction = Transaction {
|
||||
index: Some(txindex),
|
||||
index: Some(tx_index),
|
||||
txid,
|
||||
version,
|
||||
lock_time,
|
||||
@@ -337,7 +337,7 @@ impl Query {
|
||||
Ok(transaction)
|
||||
}
|
||||
|
||||
fn transaction_hex_by_index(&self, txindex: TxIndex) -> Result<String> {
|
||||
fn transaction_hex_by_index(&self, tx_index: TxIndex) -> Result<String> {
|
||||
let indexer = self.indexer();
|
||||
let reader = self.reader();
|
||||
let computer = self.computer();
|
||||
@@ -346,37 +346,37 @@ impl Query {
|
||||
.vecs
|
||||
.transactions
|
||||
.total_size
|
||||
.collect_one(txindex)
|
||||
.collect_one(tx_index)
|
||||
.unwrap();
|
||||
let position = computer.positions.tx.collect_one(txindex).unwrap();
|
||||
let position = computer.positions.tx.collect_one(tx_index).unwrap();
|
||||
|
||||
let buffer = reader.read_raw_bytes(position, *total_size as usize)?;
|
||||
|
||||
Ok(buffer.to_lower_hex_string())
|
||||
}
|
||||
|
||||
fn outspend_details(&self, txinindex: TxInIndex) -> Result<TxOutspend> {
|
||||
fn outspend_details(&self, txin_index: TxInIndex) -> Result<TxOutspend> {
|
||||
let indexer = self.indexer();
|
||||
|
||||
// Look up spending txindex directly
|
||||
let spending_txindex = indexer.vecs.inputs.txindex.collect_one(txinindex).unwrap();
|
||||
// Look up spending tx_index directly
|
||||
let spending_tx_index = indexer.vecs.inputs.tx_index.collect_one(txin_index).unwrap();
|
||||
|
||||
// Calculate vin
|
||||
let spending_first_txinindex = indexer
|
||||
let spending_first_txin_index = indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.first_txinindex
|
||||
.collect_one(spending_txindex)
|
||||
.first_txin_index
|
||||
.collect_one(spending_tx_index)
|
||||
.unwrap();
|
||||
let vin = Vin::from(usize::from(txinindex) - usize::from(spending_first_txinindex));
|
||||
let vin = Vin::from(usize::from(txin_index) - usize::from(spending_first_txin_index));
|
||||
|
||||
// Get spending tx details
|
||||
let spending_txid = indexer.vecs.transactions.txid.read_once(spending_txindex)?;
|
||||
let spending_txid = indexer.vecs.transactions.txid.read_once(spending_tx_index)?;
|
||||
let spending_height = indexer
|
||||
.vecs
|
||||
.transactions
|
||||
.height
|
||||
.collect_one(spending_txindex)
|
||||
.collect_one(spending_tx_index)
|
||||
.unwrap();
|
||||
let block_hash = indexer.vecs.blocks.blockhash.read_once(spending_height)?;
|
||||
let block_time = indexer
|
||||
|
||||
@@ -42,14 +42,14 @@ impl TryFrom<&ScriptBuf> for Address {
|
||||
|
||||
impl TryFrom<(&ScriptBuf, OutputType)> for Address {
|
||||
type Error = Error;
|
||||
fn try_from((script, outputtype): (&ScriptBuf, OutputType)) -> Result<Self, Self::Error> {
|
||||
match outputtype {
|
||||
fn try_from((script, output_type): (&ScriptBuf, OutputType)) -> Result<Self, Self::Error> {
|
||||
match output_type {
|
||||
OutputType::P2PK65 | OutputType::P2PK33 => {
|
||||
// P2PK has no standard address encoding, use raw pubkey hex
|
||||
let bytes = AddressBytes::try_from((script, outputtype))?;
|
||||
let bytes = AddressBytes::try_from((script, output_type))?;
|
||||
Ok(Self(bytes_to_hex(bytes.as_slice())))
|
||||
}
|
||||
_ if outputtype.is_address() => {
|
||||
_ if output_type.is_address() => {
|
||||
let addr = bitcoin::Address::from_script(script, bitcoin::Network::Bitcoin)
|
||||
.map_err(|_| Error::InvalidAddress)?;
|
||||
Ok(Self(addr.to_string()))
|
||||
|
||||
@@ -79,9 +79,9 @@ impl TryFrom<&ScriptBuf> for AddressBytes {
|
||||
impl TryFrom<(&ScriptBuf, OutputType)> for AddressBytes {
|
||||
type Error = Error;
|
||||
fn try_from(tuple: (&ScriptBuf, OutputType)) -> Result<Self, Self::Error> {
|
||||
let (script, outputtype) = tuple;
|
||||
let (script, output_type) = tuple;
|
||||
|
||||
match outputtype {
|
||||
match output_type {
|
||||
OutputType::P2PK65 => {
|
||||
let bytes = script.as_bytes();
|
||||
let bytes = match bytes.len() {
|
||||
@@ -219,7 +219,7 @@ impl FromStr for AddressBytes {
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let script = Self::address_to_script(s)?;
|
||||
let outputtype = OutputType::from(&script);
|
||||
Self::try_from((&script, outputtype))
|
||||
let output_type = OutputType::from(&script);
|
||||
Self::try_from((&script, output_type))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,14 +11,14 @@ use super::{OutPoint, TxIndex, TypeIndex};
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Serialize)]
|
||||
#[repr(C)]
|
||||
pub struct AddressIndexOutPoint {
|
||||
addressindextxindex: AddressIndexTxIndex, // u64
|
||||
address_index_tx_index: AddressIndexTxIndex, // u64
|
||||
vout: Vout, // u16
|
||||
}
|
||||
|
||||
impl AddressIndexOutPoint {
|
||||
#[inline]
|
||||
pub fn txindex(&self) -> TxIndex {
|
||||
self.addressindextxindex.txindex()
|
||||
pub fn tx_index(&self) -> TxIndex {
|
||||
self.address_index_tx_index.tx_index()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -30,7 +30,7 @@ impl AddressIndexOutPoint {
|
||||
impl Hash for AddressIndexOutPoint {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
let mut buf = [0u8; 10];
|
||||
buf[0..8].copy_from_slice(&self.addressindextxindex.to_bytes());
|
||||
buf[0..8].copy_from_slice(&self.address_index_tx_index.to_bytes());
|
||||
buf[8..].copy_from_slice(&self.vout.to_bytes());
|
||||
state.write(&buf);
|
||||
}
|
||||
@@ -38,9 +38,9 @@ impl Hash for AddressIndexOutPoint {
|
||||
|
||||
impl From<(TypeIndex, OutPoint)> for AddressIndexOutPoint {
|
||||
#[inline]
|
||||
fn from((addressindex, outpoint): (TypeIndex, OutPoint)) -> Self {
|
||||
fn from((address_index, outpoint): (TypeIndex, OutPoint)) -> Self {
|
||||
Self {
|
||||
addressindextxindex: AddressIndexTxIndex::from((addressindex, outpoint.txindex())),
|
||||
address_index_tx_index: AddressIndexTxIndex::from((address_index, outpoint.tx_index())),
|
||||
vout: outpoint.vout(),
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ impl From<ByteView> for AddressIndexOutPoint {
|
||||
#[inline]
|
||||
fn from(value: ByteView) -> Self {
|
||||
Self {
|
||||
addressindextxindex: AddressIndexTxIndex::from(ByteView::new(&value[..8])),
|
||||
address_index_tx_index: AddressIndexTxIndex::from(ByteView::new(&value[..8])),
|
||||
vout: Vout::from(u16::from_be_bytes([value[8], value[9]])),
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,7 @@ impl From<&AddressIndexOutPoint> for ByteView {
|
||||
fn from(value: &AddressIndexOutPoint) -> Self {
|
||||
ByteView::from(
|
||||
[
|
||||
&ByteView::from(value.addressindextxindex),
|
||||
&ByteView::from(value.address_index_tx_index),
|
||||
value.vout.to_be_bytes().as_slice(),
|
||||
]
|
||||
.concat(),
|
||||
|
||||
@@ -10,27 +10,27 @@ use super::{TxIndex, TypeIndex};
|
||||
pub struct AddressIndexTxIndex(u64);
|
||||
|
||||
impl AddressIndexTxIndex {
|
||||
pub fn addressindex(&self) -> u32 {
|
||||
pub fn address_index(&self) -> u32 {
|
||||
(self.0 >> 32) as u32
|
||||
}
|
||||
|
||||
pub fn txindex(&self) -> TxIndex {
|
||||
pub fn tx_index(&self) -> TxIndex {
|
||||
TxIndex::from(self.0 as u32)
|
||||
}
|
||||
|
||||
pub fn min_for_address(addressindex: TypeIndex) -> Self {
|
||||
Self(u64::from(addressindex) << 32)
|
||||
pub fn min_for_address(address_index: TypeIndex) -> Self {
|
||||
Self(u64::from(address_index) << 32)
|
||||
}
|
||||
|
||||
pub fn max_for_address(addressindex: TypeIndex) -> Self {
|
||||
Self((u64::from(addressindex) << 32) | u64::MAX >> 32)
|
||||
pub fn max_for_address(address_index: TypeIndex) -> Self {
|
||||
Self((u64::from(address_index) << 32) | u64::MAX >> 32)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(TypeIndex, TxIndex)> for AddressIndexTxIndex {
|
||||
#[inline]
|
||||
fn from((addressindex, txindex): (TypeIndex, TxIndex)) -> Self {
|
||||
Self((u64::from(addressindex) << 32) | u64::from(txindex))
|
||||
fn from((address_index, tx_index): (TypeIndex, TxIndex)) -> Self {
|
||||
Self((u64::from(address_index) << 32) | u64::from(tx_index))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,11 +66,11 @@ impl CheckedSub<EmptyAddressIndex> for EmptyAddressIndex {
|
||||
|
||||
impl PrintableIndex for EmptyAddressIndex {
|
||||
fn to_string() -> &'static str {
|
||||
"emptyaddressindex"
|
||||
"empty_address_index"
|
||||
}
|
||||
|
||||
fn to_possible_strings() -> &'static [&'static str] {
|
||||
&["emptyaddr", "emptyaddressindex"]
|
||||
&["emptyaddr", "empty_address_index"]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,11 +63,11 @@ impl CheckedSub<EmptyOutputIndex> for EmptyOutputIndex {
|
||||
|
||||
impl PrintableIndex for EmptyOutputIndex {
|
||||
fn to_string() -> &'static str {
|
||||
"emptyoutputindex"
|
||||
"empty_output_index"
|
||||
}
|
||||
|
||||
fn to_possible_strings() -> &'static [&'static str] {
|
||||
&["emptyout", "emptyoutputindex"]
|
||||
&["emptyout", "empty_output_index"]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,11 +62,11 @@ impl CheckedSub<FundedAddressIndex> for FundedAddressIndex {
|
||||
}
|
||||
impl PrintableIndex for FundedAddressIndex {
|
||||
fn to_string() -> &'static str {
|
||||
"fundedaddressindex"
|
||||
"funded_address_index"
|
||||
}
|
||||
|
||||
fn to_possible_strings() -> &'static [&'static str] {
|
||||
&["fundedaddr", "fundedaddressindex"]
|
||||
&["fundedaddr", "funded_address_index"]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ use super::{
|
||||
};
|
||||
|
||||
/// Aggregation dimension for querying metrics. Includes time-based (date, week, month, year),
|
||||
/// block-based (height, txindex), and address/output type indexes.
|
||||
/// block-based (height, tx_index), and address/output type indexes.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, JsonSchema)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[schemars(example = Index::Day1)]
|
||||
@@ -347,7 +347,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_not_date_based_txindex() {
|
||||
fn test_is_not_date_based_tx_index() {
|
||||
assert!(!Index::TxIndex.is_date_based());
|
||||
}
|
||||
|
||||
@@ -405,7 +405,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_index_to_date_txindex_returns_none() {
|
||||
fn test_index_to_date_tx_index_returns_none() {
|
||||
assert!(Index::TxIndex.index_to_date(100).is_none());
|
||||
}
|
||||
|
||||
|
||||
@@ -9,55 +9,55 @@ use crate::{
|
||||
/// Used by brk_indexer during block processing.
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct Indexes {
|
||||
pub emptyoutputindex: EmptyOutputIndex,
|
||||
pub empty_output_index: EmptyOutputIndex,
|
||||
pub height: Height,
|
||||
pub opreturnindex: OpReturnIndex,
|
||||
pub p2msoutputindex: P2MSOutputIndex,
|
||||
pub p2pk33addressindex: P2PK33AddressIndex,
|
||||
pub p2pk65addressindex: P2PK65AddressIndex,
|
||||
pub p2pkhaddressindex: P2PKHAddressIndex,
|
||||
pub p2shaddressindex: P2SHAddressIndex,
|
||||
pub p2traddressindex: P2TRAddressIndex,
|
||||
pub p2wpkhaddressindex: P2WPKHAddressIndex,
|
||||
pub p2wshaddressindex: P2WSHAddressIndex,
|
||||
pub p2aaddressindex: P2AAddressIndex,
|
||||
pub txindex: TxIndex,
|
||||
pub txinindex: TxInIndex,
|
||||
pub txoutindex: TxOutIndex,
|
||||
pub unknownoutputindex: UnknownOutputIndex,
|
||||
pub op_return_index: OpReturnIndex,
|
||||
pub p2ms_output_index: P2MSOutputIndex,
|
||||
pub p2pk33_address_index: P2PK33AddressIndex,
|
||||
pub p2pk65_address_index: P2PK65AddressIndex,
|
||||
pub p2pkh_address_index: P2PKHAddressIndex,
|
||||
pub p2sh_address_index: P2SHAddressIndex,
|
||||
pub p2tr_address_index: P2TRAddressIndex,
|
||||
pub p2wpkh_address_index: P2WPKHAddressIndex,
|
||||
pub p2wsh_address_index: P2WSHAddressIndex,
|
||||
pub p2a_address_index: P2AAddressIndex,
|
||||
pub tx_index: TxIndex,
|
||||
pub txin_index: TxInIndex,
|
||||
pub txout_index: TxOutIndex,
|
||||
pub unknown_output_index: UnknownOutputIndex,
|
||||
}
|
||||
|
||||
impl Indexes {
|
||||
pub fn to_typeindex(&self, outputtype: OutputType) -> TypeIndex {
|
||||
match outputtype {
|
||||
OutputType::Empty => *self.emptyoutputindex,
|
||||
OutputType::OpReturn => *self.opreturnindex,
|
||||
OutputType::P2A => *self.p2aaddressindex,
|
||||
OutputType::P2MS => *self.p2msoutputindex,
|
||||
OutputType::P2PK33 => *self.p2pk33addressindex,
|
||||
OutputType::P2PK65 => *self.p2pk65addressindex,
|
||||
OutputType::P2PKH => *self.p2pkhaddressindex,
|
||||
OutputType::P2SH => *self.p2shaddressindex,
|
||||
OutputType::P2TR => *self.p2traddressindex,
|
||||
OutputType::P2WPKH => *self.p2wpkhaddressindex,
|
||||
OutputType::P2WSH => *self.p2wshaddressindex,
|
||||
OutputType::Unknown => *self.unknownoutputindex,
|
||||
pub fn to_type_index(&self, output_type: OutputType) -> TypeIndex {
|
||||
match output_type {
|
||||
OutputType::Empty => *self.empty_output_index,
|
||||
OutputType::OpReturn => *self.op_return_index,
|
||||
OutputType::P2A => *self.p2a_address_index,
|
||||
OutputType::P2MS => *self.p2ms_output_index,
|
||||
OutputType::P2PK33 => *self.p2pk33_address_index,
|
||||
OutputType::P2PK65 => *self.p2pk65_address_index,
|
||||
OutputType::P2PKH => *self.p2pkh_address_index,
|
||||
OutputType::P2SH => *self.p2sh_address_index,
|
||||
OutputType::P2TR => *self.p2tr_address_index,
|
||||
OutputType::P2WPKH => *self.p2wpkh_address_index,
|
||||
OutputType::P2WSH => *self.p2wsh_address_index,
|
||||
OutputType::Unknown => *self.unknown_output_index,
|
||||
}
|
||||
}
|
||||
|
||||
/// Increments the address index for the given address type and returns the previous value.
|
||||
/// Only call this for address types (P2PK65, P2PK33, P2PKH, P2SH, P2WPKH, P2WSH, P2TR, P2A).
|
||||
#[inline]
|
||||
pub fn increment_address_index(&mut self, addresstype: OutputType) -> TypeIndex {
|
||||
match addresstype {
|
||||
OutputType::P2PK65 => self.p2pk65addressindex.copy_then_increment(),
|
||||
OutputType::P2PK33 => self.p2pk33addressindex.copy_then_increment(),
|
||||
OutputType::P2PKH => self.p2pkhaddressindex.copy_then_increment(),
|
||||
OutputType::P2SH => self.p2shaddressindex.copy_then_increment(),
|
||||
OutputType::P2WPKH => self.p2wpkhaddressindex.copy_then_increment(),
|
||||
OutputType::P2WSH => self.p2wshaddressindex.copy_then_increment(),
|
||||
OutputType::P2TR => self.p2traddressindex.copy_then_increment(),
|
||||
OutputType::P2A => self.p2aaddressindex.copy_then_increment(),
|
||||
pub fn increment_address_index(&mut self, address_type: OutputType) -> TypeIndex {
|
||||
match address_type {
|
||||
OutputType::P2PK65 => self.p2pk65_address_index.copy_then_increment(),
|
||||
OutputType::P2PK33 => self.p2pk33_address_index.copy_then_increment(),
|
||||
OutputType::P2PKH => self.p2pkh_address_index.copy_then_increment(),
|
||||
OutputType::P2SH => self.p2sh_address_index.copy_then_increment(),
|
||||
OutputType::P2WPKH => self.p2wpkh_address_index.copy_then_increment(),
|
||||
OutputType::P2WSH => self.p2wsh_address_index.copy_then_increment(),
|
||||
OutputType::P2TR => self.p2tr_address_index.copy_then_increment(),
|
||||
OutputType::P2A => self.p2a_address_index.copy_then_increment(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
+216
-216
@@ -3,41 +3,41 @@
|
||||
pub use vecdb::{CheckedSub, Exit, PrintableIndex, Version};
|
||||
|
||||
mod address;
|
||||
mod addressbytes;
|
||||
mod addresschainstats;
|
||||
mod addresshash;
|
||||
mod addressindexoutpoint;
|
||||
mod addressindextxindex;
|
||||
mod addressmempoolstats;
|
||||
mod addressparam;
|
||||
mod addressstats;
|
||||
mod addresstxidsparam;
|
||||
mod addressvalidation;
|
||||
mod address_bytes;
|
||||
mod address_chain_stats;
|
||||
mod address_hash;
|
||||
mod address_index_outpoint;
|
||||
mod address_index_tx_index;
|
||||
mod address_mempool_stats;
|
||||
mod address_param;
|
||||
mod address_stats;
|
||||
mod address_txids_param;
|
||||
mod address_validation;
|
||||
mod age;
|
||||
mod anyaddressindex;
|
||||
mod any_address_index;
|
||||
mod basis_points_16;
|
||||
mod basis_points_32;
|
||||
mod basis_points_signed_16;
|
||||
mod basis_points_signed_32;
|
||||
mod bitcoin;
|
||||
mod blkmetadata;
|
||||
mod blkposition;
|
||||
mod blk_metadata;
|
||||
mod blk_position;
|
||||
mod block;
|
||||
mod blockcountparam;
|
||||
mod blockfeesentry;
|
||||
mod blockferatesentry;
|
||||
mod block_count_param;
|
||||
mod block_fees_entry;
|
||||
mod block_fee_rates_entry;
|
||||
mod blockhash;
|
||||
mod blockhashparam;
|
||||
mod blockhashprefix;
|
||||
mod blockhashstartindex;
|
||||
mod blockhashtxindex;
|
||||
mod blockinfo;
|
||||
mod blockrewardsentry;
|
||||
mod blocksizeentry;
|
||||
mod blocksizesweights;
|
||||
mod blockstatus;
|
||||
mod blocktimestamp;
|
||||
mod blockweightentry;
|
||||
mod blockhash_param;
|
||||
mod blockhash_prefix;
|
||||
mod blockhash_start_index;
|
||||
mod blockhash_tx_index;
|
||||
mod block_info;
|
||||
mod block_rewards_entry;
|
||||
mod block_size_entry;
|
||||
mod block_sizes_weights;
|
||||
mod block_status;
|
||||
mod block_timestamp;
|
||||
mod block_weight_entry;
|
||||
mod bytes;
|
||||
mod cents;
|
||||
mod cents_compact;
|
||||
@@ -48,109 +48,109 @@ mod cost_basis_bucket;
|
||||
mod cost_basis_distribution;
|
||||
mod cost_basis_params;
|
||||
mod cost_basis_value;
|
||||
mod datarange;
|
||||
mod datarangeformat;
|
||||
mod data_range;
|
||||
mod data_range_format;
|
||||
mod date;
|
||||
mod day1;
|
||||
mod day3;
|
||||
mod deser;
|
||||
mod difficultyadjustment;
|
||||
mod difficultyadjustmententry;
|
||||
mod difficultyentry;
|
||||
mod diskusage;
|
||||
mod difficulty_adjustment;
|
||||
mod difficulty_adjustment_entry;
|
||||
mod difficulty_entry;
|
||||
mod disk_usage;
|
||||
mod dollars;
|
||||
mod emptyaddressdata;
|
||||
mod emptyaddressindex;
|
||||
mod emptyoutputindex;
|
||||
mod empty_address_data;
|
||||
mod empty_address_index;
|
||||
mod empty_output_index;
|
||||
mod epoch;
|
||||
mod etag;
|
||||
mod feerate;
|
||||
mod feeratepercentiles;
|
||||
mod feerate_percentiles;
|
||||
mod format;
|
||||
mod formatresponse;
|
||||
mod format_response;
|
||||
mod from_coarser;
|
||||
mod fundedaddressdata;
|
||||
mod fundedaddressindex;
|
||||
mod funded_address_data;
|
||||
mod funded_address_index;
|
||||
mod halving;
|
||||
mod hashrateentry;
|
||||
mod hashratesummary;
|
||||
mod hashrate_entry;
|
||||
mod hashrate_summary;
|
||||
mod health;
|
||||
mod height;
|
||||
mod heightparam;
|
||||
mod height_param;
|
||||
mod hex;
|
||||
mod hour1;
|
||||
mod hour12;
|
||||
mod hour4;
|
||||
mod index;
|
||||
mod indexes;
|
||||
mod indexinfo;
|
||||
mod index_info;
|
||||
mod limit;
|
||||
mod limitparam;
|
||||
mod mempoolblock;
|
||||
mod mempoolentryinfo;
|
||||
mod mempoolinfo;
|
||||
mod limit_param;
|
||||
mod mempool_block;
|
||||
mod mempool_entry_info;
|
||||
mod mempool_info;
|
||||
mod metric;
|
||||
mod metriccount;
|
||||
mod metricdata;
|
||||
mod metricinfo;
|
||||
mod metricoutput;
|
||||
mod metricparam;
|
||||
mod metric_count;
|
||||
mod metric_data;
|
||||
mod metric_info;
|
||||
mod metric_output;
|
||||
mod metric_param;
|
||||
mod metrics;
|
||||
mod metricselection;
|
||||
mod metricselectionlegacy;
|
||||
mod metricspaginated;
|
||||
mod metricwithindex;
|
||||
mod metric_selection;
|
||||
mod metric_selection_legacy;
|
||||
mod metrics_paginated;
|
||||
mod metric_with_index;
|
||||
mod minute10;
|
||||
mod minute30;
|
||||
mod month1;
|
||||
mod month3;
|
||||
mod month6;
|
||||
mod ohlc;
|
||||
mod opreturnindex;
|
||||
mod op_return_index;
|
||||
mod option_ext;
|
||||
mod oracle_bins;
|
||||
mod outpoint;
|
||||
mod output;
|
||||
mod outputtype;
|
||||
mod p2aaddressindex;
|
||||
mod p2abytes;
|
||||
mod p2msoutputindex;
|
||||
mod p2pk33addressindex;
|
||||
mod p2pk33bytes;
|
||||
mod p2pk65addressindex;
|
||||
mod p2pk65bytes;
|
||||
mod p2pkhaddressindex;
|
||||
mod p2pkhbytes;
|
||||
mod p2shaddressindex;
|
||||
mod p2shbytes;
|
||||
mod p2traddressindex;
|
||||
mod p2trbytes;
|
||||
mod p2wpkhaddressindex;
|
||||
mod p2wpkhbytes;
|
||||
mod p2wshaddressindex;
|
||||
mod p2wshbytes;
|
||||
mod output_type;
|
||||
mod p2a_address_index;
|
||||
mod p2a_bytes;
|
||||
mod p2ms_output_index;
|
||||
mod p2pk33_address_index;
|
||||
mod p2pk33_bytes;
|
||||
mod p2pk65_address_index;
|
||||
mod p2pk65_bytes;
|
||||
mod p2pkh_address_index;
|
||||
mod p2pkh_bytes;
|
||||
mod p2sh_address_index;
|
||||
mod p2sh_bytes;
|
||||
mod p2tr_address_index;
|
||||
mod p2tr_bytes;
|
||||
mod p2wpkh_address_index;
|
||||
mod p2wpkh_bytes;
|
||||
mod p2wsh_address_index;
|
||||
mod p2wsh_bytes;
|
||||
mod pagination;
|
||||
mod paginationindex;
|
||||
mod pairoutputindex;
|
||||
mod pagination_index;
|
||||
mod pair_output_index;
|
||||
mod percentile;
|
||||
mod pool;
|
||||
mod pooldetail;
|
||||
mod poolinfo;
|
||||
mod pool_detail;
|
||||
mod pool_info;
|
||||
mod pools;
|
||||
mod poolslug;
|
||||
mod poolslugparam;
|
||||
mod poolssummary;
|
||||
mod poolstats;
|
||||
mod pool_slug;
|
||||
mod pool_slug_param;
|
||||
mod pools_summary;
|
||||
mod pool_stats;
|
||||
mod port;
|
||||
mod range_map;
|
||||
mod rangeindex;
|
||||
mod rawlocktime;
|
||||
mod recommendedfees;
|
||||
mod rewardstats;
|
||||
mod range_index;
|
||||
mod raw_locktime;
|
||||
mod recommended_fees;
|
||||
mod reward_stats;
|
||||
mod sats;
|
||||
mod sats_signed;
|
||||
mod satsfract;
|
||||
mod searchquery;
|
||||
mod sats_fract;
|
||||
mod search_query;
|
||||
mod stored_bool;
|
||||
mod stored_f32;
|
||||
mod stored_f64;
|
||||
@@ -163,32 +163,32 @@ mod stored_u32;
|
||||
mod stored_u64;
|
||||
mod stored_u8;
|
||||
mod supply_state;
|
||||
mod syncstatus;
|
||||
mod sync_status;
|
||||
mod term;
|
||||
mod timeperiod;
|
||||
mod timeperiodparam;
|
||||
mod time_period;
|
||||
mod time_period_param;
|
||||
mod timestamp;
|
||||
mod timestampparam;
|
||||
mod treenode;
|
||||
mod timestamp_param;
|
||||
mod tree_node;
|
||||
mod tx;
|
||||
mod txid;
|
||||
mod txidparam;
|
||||
mod txidprefix;
|
||||
mod txidvout;
|
||||
mod txid_param;
|
||||
mod txid_prefix;
|
||||
mod txid_vout;
|
||||
mod txin;
|
||||
mod txindex;
|
||||
mod txinindex;
|
||||
mod tx_index;
|
||||
mod txin_index;
|
||||
mod txout;
|
||||
mod txoutindex;
|
||||
mod txoutspend;
|
||||
mod txstatus;
|
||||
mod txversion;
|
||||
mod txwithhex;
|
||||
mod typeindex;
|
||||
mod txout_index;
|
||||
mod txout_spend;
|
||||
mod tx_status;
|
||||
mod tx_version;
|
||||
mod tx_with_hex;
|
||||
mod type_index;
|
||||
mod unit;
|
||||
mod unknownoutputindex;
|
||||
mod unknown_output_index;
|
||||
mod utxo;
|
||||
mod validateaddressparam;
|
||||
mod validate_address_param;
|
||||
mod vin;
|
||||
mod vout;
|
||||
mod vsize;
|
||||
@@ -199,41 +199,41 @@ mod year1;
|
||||
mod year10;
|
||||
|
||||
pub use address::*;
|
||||
pub use addressbytes::*;
|
||||
pub use addresschainstats::*;
|
||||
pub use addresshash::*;
|
||||
pub use addressindexoutpoint::*;
|
||||
pub use addressindextxindex::*;
|
||||
pub use addressmempoolstats::*;
|
||||
pub use addressparam::*;
|
||||
pub use addressstats::*;
|
||||
pub use addresstxidsparam::*;
|
||||
pub use addressvalidation::*;
|
||||
pub use address_bytes::*;
|
||||
pub use address_chain_stats::*;
|
||||
pub use address_hash::*;
|
||||
pub use address_index_outpoint::*;
|
||||
pub use address_index_tx_index::*;
|
||||
pub use address_mempool_stats::*;
|
||||
pub use address_param::*;
|
||||
pub use address_stats::*;
|
||||
pub use address_txids_param::*;
|
||||
pub use address_validation::*;
|
||||
pub use age::*;
|
||||
pub use anyaddressindex::*;
|
||||
pub use any_address_index::*;
|
||||
pub use basis_points_16::*;
|
||||
pub use basis_points_32::*;
|
||||
pub use basis_points_signed_16::*;
|
||||
pub use basis_points_signed_32::*;
|
||||
pub use bitcoin::*;
|
||||
pub use blkmetadata::*;
|
||||
pub use blkposition::*;
|
||||
pub use blk_metadata::*;
|
||||
pub use blk_position::*;
|
||||
pub use block::*;
|
||||
pub use blockcountparam::*;
|
||||
pub use blockfeesentry::*;
|
||||
pub use blockferatesentry::*;
|
||||
pub use block_count_param::*;
|
||||
pub use block_fees_entry::*;
|
||||
pub use block_fee_rates_entry::*;
|
||||
pub use blockhash::*;
|
||||
pub use blockhashparam::*;
|
||||
pub use blockhashprefix::*;
|
||||
pub use blockhashstartindex::*;
|
||||
pub use blockhashtxindex::*;
|
||||
pub use blockinfo::*;
|
||||
pub use blockrewardsentry::*;
|
||||
pub use blocksizeentry::*;
|
||||
pub use blocksizesweights::*;
|
||||
pub use blockstatus::*;
|
||||
pub use blocktimestamp::*;
|
||||
pub use blockweightentry::*;
|
||||
pub use blockhash_param::*;
|
||||
pub use blockhash_prefix::*;
|
||||
pub use blockhash_start_index::*;
|
||||
pub use blockhash_tx_index::*;
|
||||
pub use block_info::*;
|
||||
pub use block_rewards_entry::*;
|
||||
pub use block_size_entry::*;
|
||||
pub use block_sizes_weights::*;
|
||||
pub use block_status::*;
|
||||
pub use block_timestamp::*;
|
||||
pub use block_weight_entry::*;
|
||||
pub use bytes::*;
|
||||
pub use cents::*;
|
||||
pub use cents_compact::*;
|
||||
@@ -244,109 +244,109 @@ pub use cost_basis_bucket::*;
|
||||
pub use cost_basis_distribution::*;
|
||||
pub use cost_basis_params::*;
|
||||
pub use cost_basis_value::*;
|
||||
pub use datarange::*;
|
||||
pub use datarangeformat::*;
|
||||
pub use data_range::*;
|
||||
pub use data_range_format::*;
|
||||
pub use date::*;
|
||||
pub use day1::*;
|
||||
pub use day3::*;
|
||||
pub use deser::*;
|
||||
pub use difficultyadjustment::*;
|
||||
pub use difficultyadjustmententry::*;
|
||||
pub use difficultyentry::*;
|
||||
pub use diskusage::*;
|
||||
pub use difficulty_adjustment::*;
|
||||
pub use difficulty_adjustment_entry::*;
|
||||
pub use difficulty_entry::*;
|
||||
pub use disk_usage::*;
|
||||
pub use dollars::*;
|
||||
pub use emptyaddressdata::*;
|
||||
pub use emptyaddressindex::*;
|
||||
pub use emptyoutputindex::*;
|
||||
pub use empty_address_data::*;
|
||||
pub use empty_address_index::*;
|
||||
pub use empty_output_index::*;
|
||||
pub use epoch::*;
|
||||
pub use etag::*;
|
||||
pub use feerate::*;
|
||||
pub use feeratepercentiles::*;
|
||||
pub use feerate_percentiles::*;
|
||||
pub use format::*;
|
||||
pub use formatresponse::*;
|
||||
pub use format_response::*;
|
||||
pub use from_coarser::*;
|
||||
pub use fundedaddressdata::*;
|
||||
pub use fundedaddressindex::*;
|
||||
pub use funded_address_data::*;
|
||||
pub use funded_address_index::*;
|
||||
pub use halving::*;
|
||||
pub use hashrateentry::*;
|
||||
pub use hashratesummary::*;
|
||||
pub use hashrate_entry::*;
|
||||
pub use hashrate_summary::*;
|
||||
pub use health::*;
|
||||
pub use height::*;
|
||||
pub use heightparam::*;
|
||||
pub use height_param::*;
|
||||
pub use hex::*;
|
||||
pub use hour1::*;
|
||||
pub use hour4::*;
|
||||
pub use hour12::*;
|
||||
pub use index::*;
|
||||
pub use indexes::*;
|
||||
pub use indexinfo::*;
|
||||
pub use index_info::*;
|
||||
pub use limit::*;
|
||||
pub use limitparam::*;
|
||||
pub use mempoolblock::*;
|
||||
pub use mempoolentryinfo::*;
|
||||
pub use mempoolinfo::*;
|
||||
pub use limit_param::*;
|
||||
pub use mempool_block::*;
|
||||
pub use mempool_entry_info::*;
|
||||
pub use mempool_info::*;
|
||||
pub use metric::*;
|
||||
pub use metriccount::*;
|
||||
pub use metricdata::*;
|
||||
pub use metricinfo::*;
|
||||
pub use metricoutput::*;
|
||||
pub use metricparam::*;
|
||||
pub use metric_count::*;
|
||||
pub use metric_data::*;
|
||||
pub use metric_info::*;
|
||||
pub use metric_output::*;
|
||||
pub use metric_param::*;
|
||||
pub use metrics::*;
|
||||
pub use metricselection::*;
|
||||
pub use metricselectionlegacy::*;
|
||||
pub use metricspaginated::*;
|
||||
pub use metricwithindex::*;
|
||||
pub use metric_selection::*;
|
||||
pub use metric_selection_legacy::*;
|
||||
pub use metrics_paginated::*;
|
||||
pub use metric_with_index::*;
|
||||
pub use minute10::*;
|
||||
pub use minute30::*;
|
||||
pub use month1::*;
|
||||
pub use month3::*;
|
||||
pub use month6::*;
|
||||
pub use ohlc::*;
|
||||
pub use opreturnindex::*;
|
||||
pub use op_return_index::*;
|
||||
pub use option_ext::*;
|
||||
pub use oracle_bins::*;
|
||||
pub use outpoint::*;
|
||||
pub use output::*;
|
||||
pub use outputtype::*;
|
||||
pub use p2aaddressindex::*;
|
||||
pub use p2abytes::*;
|
||||
pub use p2msoutputindex::*;
|
||||
pub use p2pk33addressindex::*;
|
||||
pub use p2pk33bytes::*;
|
||||
pub use p2pk65addressindex::*;
|
||||
pub use p2pk65bytes::*;
|
||||
pub use p2pkhaddressindex::*;
|
||||
pub use p2pkhbytes::*;
|
||||
pub use p2shaddressindex::*;
|
||||
pub use p2shbytes::*;
|
||||
pub use p2traddressindex::*;
|
||||
pub use p2trbytes::*;
|
||||
pub use p2wpkhaddressindex::*;
|
||||
pub use p2wpkhbytes::*;
|
||||
pub use p2wshaddressindex::*;
|
||||
pub use p2wshbytes::*;
|
||||
pub use output_type::*;
|
||||
pub use p2a_address_index::*;
|
||||
pub use p2a_bytes::*;
|
||||
pub use p2ms_output_index::*;
|
||||
pub use p2pk33_address_index::*;
|
||||
pub use p2pk33_bytes::*;
|
||||
pub use p2pk65_address_index::*;
|
||||
pub use p2pk65_bytes::*;
|
||||
pub use p2pkh_address_index::*;
|
||||
pub use p2pkh_bytes::*;
|
||||
pub use p2sh_address_index::*;
|
||||
pub use p2sh_bytes::*;
|
||||
pub use p2tr_address_index::*;
|
||||
pub use p2tr_bytes::*;
|
||||
pub use p2wpkh_address_index::*;
|
||||
pub use p2wpkh_bytes::*;
|
||||
pub use p2wsh_address_index::*;
|
||||
pub use p2wsh_bytes::*;
|
||||
pub use pagination::*;
|
||||
pub use paginationindex::*;
|
||||
pub use pairoutputindex::*;
|
||||
pub use pagination_index::*;
|
||||
pub use pair_output_index::*;
|
||||
pub use percentile::*;
|
||||
pub use pool::*;
|
||||
pub use pooldetail::*;
|
||||
pub use poolinfo::*;
|
||||
pub use pool_detail::*;
|
||||
pub use pool_info::*;
|
||||
pub use pools::*;
|
||||
pub use poolslug::*;
|
||||
pub use poolslugparam::*;
|
||||
pub use poolssummary::*;
|
||||
pub use poolstats::*;
|
||||
pub use pool_slug::*;
|
||||
pub use pool_slug_param::*;
|
||||
pub use pools_summary::*;
|
||||
pub use pool_stats::*;
|
||||
pub use port::*;
|
||||
pub use range_map::*;
|
||||
pub use rangeindex::*;
|
||||
pub use rawlocktime::*;
|
||||
pub use recommendedfees::*;
|
||||
pub use rewardstats::*;
|
||||
pub use range_index::*;
|
||||
pub use raw_locktime::*;
|
||||
pub use recommended_fees::*;
|
||||
pub use reward_stats::*;
|
||||
pub use sats::*;
|
||||
pub use sats_signed::*;
|
||||
pub use satsfract::*;
|
||||
pub use searchquery::*;
|
||||
pub use sats_fract::*;
|
||||
pub use search_query::*;
|
||||
pub use stored_bool::*;
|
||||
pub use stored_f32::*;
|
||||
pub use stored_f64::*;
|
||||
@@ -359,32 +359,32 @@ pub use stored_u16::*;
|
||||
pub use stored_u32::*;
|
||||
pub use stored_u64::*;
|
||||
pub use supply_state::*;
|
||||
pub use syncstatus::*;
|
||||
pub use sync_status::*;
|
||||
pub use term::*;
|
||||
pub use timeperiod::*;
|
||||
pub use timeperiodparam::*;
|
||||
pub use time_period::*;
|
||||
pub use time_period_param::*;
|
||||
pub use timestamp::*;
|
||||
pub use timestampparam::*;
|
||||
pub use treenode::*;
|
||||
pub use timestamp_param::*;
|
||||
pub use tree_node::*;
|
||||
pub use tx::*;
|
||||
pub use txid::*;
|
||||
pub use txidparam::*;
|
||||
pub use txidprefix::*;
|
||||
pub use txidvout::*;
|
||||
pub use txid_param::*;
|
||||
pub use txid_prefix::*;
|
||||
pub use txid_vout::*;
|
||||
pub use txin::*;
|
||||
pub use txindex::*;
|
||||
pub use txinindex::*;
|
||||
pub use tx_index::*;
|
||||
pub use txin_index::*;
|
||||
pub use txout::*;
|
||||
pub use txoutindex::*;
|
||||
pub use txoutspend::*;
|
||||
pub use txstatus::*;
|
||||
pub use txversion::*;
|
||||
pub use txwithhex::*;
|
||||
pub use typeindex::*;
|
||||
pub use txout_index::*;
|
||||
pub use txout_spend::*;
|
||||
pub use tx_status::*;
|
||||
pub use tx_version::*;
|
||||
pub use tx_with_hex::*;
|
||||
pub use type_index::*;
|
||||
pub use unit::*;
|
||||
pub use unknownoutputindex::*;
|
||||
pub use unknown_output_index::*;
|
||||
pub use utxo::*;
|
||||
pub use validateaddressparam::*;
|
||||
pub use validate_address_param::*;
|
||||
pub use vin::*;
|
||||
pub use vout::*;
|
||||
pub use vsize::*;
|
||||
|
||||
@@ -68,11 +68,11 @@ impl CheckedSub<OpReturnIndex> for OpReturnIndex {
|
||||
|
||||
impl PrintableIndex for OpReturnIndex {
|
||||
fn to_string() -> &'static str {
|
||||
"opreturnindex"
|
||||
"op_return_index"
|
||||
}
|
||||
|
||||
fn to_possible_strings() -> &'static [&'static str] {
|
||||
&["op", "opreturn", "opreturnindex"]
|
||||
&["op", "opreturn", "op_return_index"]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,14 +10,14 @@ pub struct OutPoint(u64);
|
||||
impl OutPoint {
|
||||
pub const COINBASE: Self = Self(u64::MAX);
|
||||
|
||||
pub fn new(txindex: TxIndex, vout: Vout) -> Self {
|
||||
let txindex_bits = u64::from(txindex) << 32;
|
||||
pub fn new(tx_index: TxIndex, vout: Vout) -> Self {
|
||||
let tx_index_bits = u64::from(tx_index) << 32;
|
||||
let vout_bits = u64::from(vout);
|
||||
Self(txindex_bits | vout_bits)
|
||||
Self(tx_index_bits | vout_bits)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn txindex(self) -> TxIndex {
|
||||
pub fn tx_index(self) -> TxIndex {
|
||||
TxIndex::from((self.0 >> 32) as u32)
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ impl OutPoint {
|
||||
|
||||
impl std::fmt::Display for OutPoint {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "txindex: {}, vout: {}", self.txindex(), self.vout())
|
||||
write!(f, "tx_index: {}, vout: {}", self.tx_index(), self.vout())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ impl Serialize for OutPoint {
|
||||
{
|
||||
use serde::ser::SerializeStruct;
|
||||
let mut state = serializer.serialize_struct("OutPoint", 2)?;
|
||||
state.serialize_field("txindex", &self.txindex())?;
|
||||
state.serialize_field("tx_index", &self.tx_index())?;
|
||||
state.serialize_field("vout", &self.vout())?;
|
||||
state.end()
|
||||
}
|
||||
@@ -91,10 +91,10 @@ impl<'de> Deserialize<'de> for OutPoint {
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
struct Helper {
|
||||
txindex: TxIndex,
|
||||
tx_index: TxIndex,
|
||||
vout: Vout,
|
||||
}
|
||||
let h = Helper::deserialize(deserializer)?;
|
||||
Ok(Self::new(h.txindex, h.vout))
|
||||
Ok(Self::new(h.tx_index, h.vout))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,11 +89,11 @@ impl CheckedSub<P2AAddressIndex> for P2AAddressIndex {
|
||||
|
||||
impl PrintableIndex for P2AAddressIndex {
|
||||
fn to_string() -> &'static str {
|
||||
"p2aaddressindex"
|
||||
"p2a_address_index"
|
||||
}
|
||||
|
||||
fn to_possible_strings() -> &'static [&'static str] {
|
||||
&["aaddr", "p2aaddr", "p2aaddressindex"]
|
||||
&["aaddr", "p2aaddr", "p2a_address_index"]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,11 +68,11 @@ impl CheckedSub<P2MSOutputIndex> for P2MSOutputIndex {
|
||||
|
||||
impl PrintableIndex for P2MSOutputIndex {
|
||||
fn to_string() -> &'static str {
|
||||
"p2msoutputindex"
|
||||
"p2ms_output_index"
|
||||
}
|
||||
|
||||
fn to_possible_strings() -> &'static [&'static str] {
|
||||
&["msout", "p2msout", "p2msoutputindex"]
|
||||
&["msout", "p2msout", "p2ms_output_index"]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -89,11 +89,11 @@ impl CheckedSub<P2PK33AddressIndex> for P2PK33AddressIndex {
|
||||
|
||||
impl PrintableIndex for P2PK33AddressIndex {
|
||||
fn to_string() -> &'static str {
|
||||
"p2pk33addressindex"
|
||||
"p2pk33_address_index"
|
||||
}
|
||||
|
||||
fn to_possible_strings() -> &'static [&'static str] {
|
||||
&["pk33addr", "p2pk33addr", "p2pk33addressindex"]
|
||||
&["pk33addr", "p2pk33addr", "p2pk33_address_index"]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -89,10 +89,10 @@ impl CheckedSub<P2PK65AddressIndex> for P2PK65AddressIndex {
|
||||
|
||||
impl PrintableIndex for P2PK65AddressIndex {
|
||||
fn to_string() -> &'static str {
|
||||
"p2pk65addressindex"
|
||||
"p2pk65_address_index"
|
||||
}
|
||||
fn to_possible_strings() -> &'static [&'static str] {
|
||||
&["pk65addr", "p2pk65addr", "p2pk65addressindex"]
|
||||
&["pk65addr", "p2pk65addr", "p2pk65_address_index"]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -89,11 +89,11 @@ impl CheckedSub<P2PKHAddressIndex> for P2PKHAddressIndex {
|
||||
|
||||
impl PrintableIndex for P2PKHAddressIndex {
|
||||
fn to_string() -> &'static str {
|
||||
"p2pkhaddressindex"
|
||||
"p2pkh_address_index"
|
||||
}
|
||||
|
||||
fn to_possible_strings() -> &'static [&'static str] {
|
||||
&["pkhaddr", "p2pkhaddr", "p2pkhaddressindex"]
|
||||
&["pkhaddr", "p2pkhaddr", "p2pkh_address_index"]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -96,11 +96,11 @@ impl CheckedSub<P2SHAddressIndex> for P2SHAddressIndex {
|
||||
|
||||
impl PrintableIndex for P2SHAddressIndex {
|
||||
fn to_string() -> &'static str {
|
||||
"p2shaddressindex"
|
||||
"p2sh_address_index"
|
||||
}
|
||||
|
||||
fn to_possible_strings() -> &'static [&'static str] {
|
||||
&["shaddr", "p2shaddr", "p2shaddressindex"]
|
||||
&["shaddr", "p2shaddr", "p2sh_address_index"]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -89,11 +89,11 @@ impl CheckedSub<P2TRAddressIndex> for P2TRAddressIndex {
|
||||
|
||||
impl PrintableIndex for P2TRAddressIndex {
|
||||
fn to_string() -> &'static str {
|
||||
"p2traddressindex"
|
||||
"p2tr_address_index"
|
||||
}
|
||||
|
||||
fn to_possible_strings() -> &'static [&'static str] {
|
||||
&["traddr", "p2traddr", "p2traddressindex"]
|
||||
&["traddr", "p2traddr", "p2tr_address_index"]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -89,11 +89,11 @@ impl CheckedSub<P2WPKHAddressIndex> for P2WPKHAddressIndex {
|
||||
|
||||
impl PrintableIndex for P2WPKHAddressIndex {
|
||||
fn to_string() -> &'static str {
|
||||
"p2wpkhaddressindex"
|
||||
"p2wpkh_address_index"
|
||||
}
|
||||
|
||||
fn to_possible_strings() -> &'static [&'static str] {
|
||||
&["wpkhaddr", "p2wpkhaddr", "p2wpkhaddressindex"]
|
||||
&["wpkhaddr", "p2wpkhaddr", "p2wpkh_address_index"]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -89,11 +89,11 @@ impl CheckedSub<P2WSHAddressIndex> for P2WSHAddressIndex {
|
||||
|
||||
impl PrintableIndex for P2WSHAddressIndex {
|
||||
fn to_string() -> &'static str {
|
||||
"p2wshaddressindex"
|
||||
"p2wsh_address_index"
|
||||
}
|
||||
|
||||
fn to_possible_strings() -> &'static [&'static str] {
|
||||
&["wshaddr", "p2wshaddr", "p2wshaddressindex"]
|
||||
&["wshaddr", "p2wshaddr", "p2wsh_address_index"]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user