computer: store part 4

This commit is contained in:
nym21
2025-07-01 13:57:48 +02:00
parent 6e996797b8
commit a0a13eb2a8
10 changed files with 455 additions and 60 deletions

View File

@@ -1,18 +1,19 @@
use std::{path::Path, thread}; use std::{path::Path, thread};
use brk_core::{ use brk_core::{
AddressData, AddressIndexToTypeIndedToOutputIndex, EmptyAddressData, GroupedByAddressType, AddressData, EmptyAddressData, GroupedByAddressType, Height, OutputIndex, OutputType,
Height, P2AAddressIndex, P2AAddressIndexOutputindex, P2PK33AddressIndex, P2AAddressIndex, P2AAddressIndexOutputindex, P2PK33AddressIndex, P2PK33AddressIndexOutputindex,
P2PK33AddressIndexOutputindex, P2PK65AddressIndex, P2PK65AddressIndexOutputindex, P2PK65AddressIndex, P2PK65AddressIndexOutputindex, P2PKHAddressIndex,
P2PKHAddressIndex, P2PKHAddressIndexOutputindex, P2SHAddressIndex, P2SHAddressIndexOutputindex, P2PKHAddressIndexOutputindex, P2SHAddressIndex, P2SHAddressIndexOutputindex, P2TRAddressIndex,
P2TRAddressIndex, P2TRAddressIndexOutputindex, P2WPKHAddressIndex, P2TRAddressIndexOutputindex, P2WPKHAddressIndex, P2WPKHAddressIndexOutputindex,
P2WPKHAddressIndexOutputindex, P2WSHAddressIndex, P2WSHAddressIndexOutputindex, Result, Unit, P2WSHAddressIndex, P2WSHAddressIndexOutputindex, Result, TypeIndex, Unit, Version,
Version,
}; };
use brk_store::{AnyStore, Store}; use brk_store::{AnyStore, Store};
use fjall::{PersistMode, TransactionalKeyspace}; use fjall::{PersistMode, TransactionalKeyspace};
use rayon::prelude::*; use rayon::prelude::*;
use crate::vecs::stateful::AddressTypeToTypeIndexVec;
const VERSION: Version = Version::ZERO; const VERSION: Version = Version::ZERO;
#[derive(Clone)] #[derive(Clone)]
@@ -487,11 +488,109 @@ impl Stores {
.map_err(|e| e.into()) .map_err(|e| e.into())
} }
pub fn get_addressdata(
&self,
address_type: OutputType,
type_index: TypeIndex,
) -> Result<Option<AddressData>> {
Ok(match address_type {
OutputType::P2A => self
.p2aaddressindex_to_addressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2PK33 => self
.p2pk33addressindex_to_addressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2PK65 => self
.p2pk65addressindex_to_addressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2PKH => self
.p2pkhaddressindex_to_addressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2SH => self
.p2shaddressindex_to_addressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2TR => self
.p2traddressindex_to_addressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2WPKH => self
.p2wpkhaddressindex_to_addressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2WSH => self
.p2wshaddressindex_to_addressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
_ => unreachable!(),
})
}
pub fn get_emptyaddressdata(
&self,
address_type: OutputType,
type_index: TypeIndex,
) -> Result<Option<EmptyAddressData>> {
Ok(match address_type {
OutputType::P2A => self
.p2aaddressindex_to_emptyaddressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2PK33 => self
.p2pk33addressindex_to_emptyaddressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2PK65 => self
.p2pk65addressindex_to_emptyaddressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2PKH => self
.p2pkhaddressindex_to_emptyaddressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2SH => self
.p2shaddressindex_to_emptyaddressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2TR => self
.p2traddressindex_to_emptyaddressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2WPKH => self
.p2wpkhaddressindex_to_emptyaddressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2WSH => self
.p2wshaddressindex_to_emptyaddressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
_ => unreachable!(),
})
}
// pub fn emptyaddressdata_store_increase_replaced(&mut self, address_type: OutputType) {
// match address_type {
// OutputType::P2A => self.p2aaddressindex_to_addressdata.increase_replaced(),
// OutputType::P2PK33 => self.p2pk33addressindex_to_addressdata.increase_replaced(),
// OutputType::P2PK65 => self.p2pk65addressindex_to_addressdata.increase_replaced(),
// OutputType::P2PKH => self.p2pkhaddressindex_to_addressdata.increase_replaced(),
// OutputType::P2SH => self.p2shaddressindex_to_addressdata.increase_replaced(),
// OutputType::P2TR => self.p2traddressindex_to_addressdata.increase_replaced(),
// OutputType::P2WPKH => self.p2wpkhaddressindex_to_addressdata.increase_replaced(),
// OutputType::P2WSH => self.p2wshaddressindex_to_addressdata.increase_replaced(),
// _ => unreachable!(),
// }
// }
pub fn commit( pub fn commit(
&mut self, &mut self,
height: Height, height: Height,
sent: AddressIndexToTypeIndedToOutputIndex, sent: AddressTypeToTypeIndexVec<OutputIndex>,
received: AddressIndexToTypeIndedToOutputIndex, received: AddressTypeToTypeIndexVec<OutputIndex>,
) -> Result<()> { ) -> Result<()> {
// &mut self.p2aaddressindex_to_addressdata, // &mut self.p2aaddressindex_to_addressdata,
// &mut self.p2pk33addressindex_to_addressdata, // &mut self.p2pk33addressindex_to_addressdata,
@@ -521,7 +620,7 @@ impl Stores {
p2wsh, p2wsh,
p2tr, p2tr,
p2a, p2a,
} = received.inner(); } = received.unwrap();
s.spawn(|| { s.spawn(|| {
self.p2aaddressindex_to_outputs_received.commit_( self.p2aaddressindex_to_outputs_received.commit_(
@@ -612,7 +711,7 @@ impl Stores {
p2wsh, p2wsh,
p2tr, p2tr,
p2a, p2a,
} = sent.inner(); } = sent.unwrap();
s.spawn(|| { s.spawn(|| {
self.p2aaddressindex_to_outputs_sent.commit_( self.p2aaddressindex_to_outputs_sent.commit_(

View File

@@ -0,0 +1,50 @@
use std::{collections::BTreeMap, mem};
use brk_core::TypeIndex;
use derive_deref::{Deref, DerefMut};
use super::GroupedByAddressType;
#[derive(Debug, Deref, DerefMut)]
pub struct AddressTypeToTypeIndexTree<T>(GroupedByAddressType<BTreeMap<TypeIndex, T>>);
impl<T> AddressTypeToTypeIndexTree<T> {
pub fn merge(&mut self, mut other: Self) {
Self::merge_(&mut self.p2pk65, &mut other.p2pk65);
Self::merge_(&mut self.p2pk33, &mut other.p2pk33);
Self::merge_(&mut self.p2pkh, &mut other.p2pkh);
Self::merge_(&mut self.p2sh, &mut other.p2sh);
Self::merge_(&mut self.p2wpkh, &mut other.p2wpkh);
Self::merge_(&mut self.p2wsh, &mut other.p2wsh);
Self::merge_(&mut self.p2tr, &mut other.p2tr);
Self::merge_(&mut self.p2a, &mut other.p2a);
}
fn merge_(own: &mut BTreeMap<TypeIndex, T>, other: &mut BTreeMap<TypeIndex, T>) {
if own.len() >= other.len() {
own.append(other);
} else {
other.append(own);
mem::swap(own, other);
}
}
pub fn inner(self) -> GroupedByAddressType<BTreeMap<TypeIndex, T>> {
self.0
}
}
impl<T> Default for AddressTypeToTypeIndexTree<T> {
fn default() -> Self {
Self(GroupedByAddressType {
p2pk65: BTreeMap::default(),
p2pk33: BTreeMap::default(),
p2pkh: BTreeMap::default(),
p2sh: BTreeMap::default(),
p2wpkh: BTreeMap::default(),
p2wsh: BTreeMap::default(),
p2tr: BTreeMap::default(),
p2a: BTreeMap::default(),
})
}
}

View File

@@ -1,17 +1,14 @@
use std::mem; use std::mem;
use brk_core::TypeIndex;
use derive_deref::{Deref, DerefMut}; use derive_deref::{Deref, DerefMut};
use crate::{OutputIndex, TypeIndex};
use super::GroupedByAddressType; use super::GroupedByAddressType;
#[derive(Debug, Default, Deref, DerefMut)] #[derive(Debug, Default, Deref, DerefMut)]
pub struct AddressIndexToTypeIndedToOutputIndex( pub struct AddressTypeToTypeIndexVec<T>(GroupedByAddressType<Vec<(TypeIndex, T)>>);
GroupedByAddressType<Vec<(TypeIndex, OutputIndex)>>,
);
impl AddressIndexToTypeIndedToOutputIndex { impl<T> AddressTypeToTypeIndexVec<T> {
pub fn merge(&mut self, mut other: Self) { pub fn merge(&mut self, mut other: Self) {
Self::merge_(&mut self.p2pk65, &mut other.p2pk65); Self::merge_(&mut self.p2pk65, &mut other.p2pk65);
Self::merge_(&mut self.p2pk33, &mut other.p2pk33); Self::merge_(&mut self.p2pk33, &mut other.p2pk33);
@@ -23,7 +20,7 @@ impl AddressIndexToTypeIndedToOutputIndex {
Self::merge_(&mut self.p2a, &mut other.p2a); Self::merge_(&mut self.p2a, &mut other.p2a);
} }
fn merge_(own: &mut Vec<(TypeIndex, OutputIndex)>, other: &mut Vec<(TypeIndex, OutputIndex)>) { fn merge_(own: &mut Vec<(TypeIndex, T)>, other: &mut Vec<(TypeIndex, T)>) {
if own.len() >= other.len() { if own.len() >= other.len() {
own.append(other); own.append(other);
} else { } else {
@@ -32,7 +29,7 @@ impl AddressIndexToTypeIndedToOutputIndex {
} }
} }
pub fn inner(self) -> GroupedByAddressType<Vec<(TypeIndex, OutputIndex)>> { pub fn unwrap(self) -> GroupedByAddressType<Vec<(TypeIndex, T)>> {
self.0 self.0
} }
} }

View File

@@ -0,0 +1,19 @@
use brk_core::{AddressData, EmptyAddressData};
#[derive(Debug)]
pub enum AnyAddressData {
AddressData(AddressData),
EmptyAddressData(EmptyAddressData),
}
impl From<AddressData> for AnyAddressData {
fn from(value: AddressData) -> Self {
Self::AddressData(value)
}
}
impl From<EmptyAddressData> for AnyAddressData {
fn from(value: EmptyAddressData) -> Self {
Self::EmptyAddressData(value)
}
}

View File

@@ -1,7 +1,7 @@
use std::{cmp::Ordering, collections::BTreeMap, mem, path::Path, thread}; use std::{cmp::Ordering, collections::BTreeMap, mem, path::Path, thread};
use brk_core::{ use brk_core::{
AddressIndexToTypeIndedToOutputIndex, DateIndex, GroupedByAddressType, Height, InputIndex, AddressData, DateIndex, Dollars, EmptyAddressData, GroupedByAddressType, Height, InputIndex,
OutputIndex, OutputType, Result, Sats, StoredUsize, Version, OutputIndex, OutputType, Result, Sats, StoredUsize, Version,
}; };
use brk_exit::Exit; use brk_exit::Exit;
@@ -15,10 +15,7 @@ use rayon::prelude::*;
use brk_state::{BlockState, CohortStateTrait, SupplyState, Transacted}; use brk_state::{BlockState, CohortStateTrait, SupplyState, Transacted};
use crate::{ use crate::{stores::Stores, vecs::market};
stores::Stores,
vecs::{market, stateful::r#trait::CohortVecs},
};
use super::{ use super::{
Indexes, fetched, Indexes, fetched,
@@ -28,10 +25,19 @@ use super::{
mod address_cohort; mod address_cohort;
mod address_cohorts; mod address_cohorts;
mod addresstype_to_typeindex_tree;
mod addresstype_to_typeindex_vec;
mod anyaddressdata;
mod common; mod common;
mod r#trait; mod r#trait;
mod utxo_cohort; mod utxo_cohort;
mod utxo_cohorts; mod utxo_cohorts;
mod withaddressdatasource;
use addresstype_to_typeindex_tree::*;
pub use addresstype_to_typeindex_vec::*;
use r#trait::CohortVecs;
use withaddressdatasource::WithAddressDataSource;
const VERSION: Version = Version::new(5); const VERSION: Version = Version::new(5);
@@ -353,10 +359,14 @@ impl Vecs {
let mut height = starting_height; let mut height = starting_height;
let mut addressindex_to_typedindex_to_sent_outputindex = let mut addresstype_to_typeindex_to_sent_outputindex =
AddressIndexToTypeIndedToOutputIndex::default(); AddressTypeToTypeIndexVec::<OutputIndex>::default();
let mut addressindex_to_typedindex_to_received_outputindex = let mut addresstype_to_typeindex_to_received_outputindex =
AddressIndexToTypeIndedToOutputIndex::default(); AddressTypeToTypeIndexVec::<OutputIndex>::default();
let mut addresstype_to_typeindex_to_addressdata =
AddressTypeToTypeIndexTree::<WithAddressDataSource<AddressData>>::default();
let mut addresstype_to_typeindex_to_emptyaddressdata =
AddressTypeToTypeIndexTree::<WithAddressDataSource<EmptyAddressData>>::default();
(height.unwrap_to_usize()..height_to_date_fixed.len()) (height.unwrap_to_usize()..height_to_date_fixed.len())
.map(Height::from) .map(Height::from)
@@ -383,7 +393,7 @@ impl Vecs {
let output_count = height_to_output_count_iter.unwrap_get_inner(height); let output_count = height_to_output_count_iter.unwrap_get_inner(height);
let input_count = height_to_input_count_iter.unwrap_get_inner(height); let input_count = height_to_input_count_iter.unwrap_get_inner(height);
let ((mut height_to_sent, new_addressindex_to_typedindex_to_sent_outputindex), (mut received, new_addressindex_to_typedindex_to_received_outputindex)) = thread::scope(|s| { let ((mut height_to_sent, new_addresstype_to_typedindex_to_sent_outputindex, addresstype_to_typedindex_to_sent_sats_and_addressdata_opt), (mut received, new_addresstype_to_typedindex_to_received_outputindex, addresstype_to_typedindex_to_received_sats_and_addressdata_opt)) = thread::scope(|s| {
if chain_state_starting_height <= height { if chain_state_starting_height <= height {
s.spawn(|| { s.spawn(|| {
self.utxos_vecs self.utxos_vecs
@@ -425,7 +435,11 @@ impl Vecs {
unreachable!() unreachable!()
} }
// stores. let addressdata_opt = if input_type.is_address() && !addresstype_to_typeindex_to_addressdata.get(input_type).unwrap().contains_key(&typeindex) {
Some(WithAddressDataSource::FromAddressDataStore( stores.get_addressdata(input_type, typeindex).unwrap().unwrap()))
} else {
None
};
let input_txindex = outputindex_to_txindex let input_txindex = outputindex_to_txindex
.get_or_read(outputindex, &outputindex_to_txindex_mmap) .get_or_read(outputindex, &outputindex_to_txindex_mmap)
@@ -439,29 +453,34 @@ impl Vecs {
.unwrap() .unwrap()
.into_owned(); .into_owned();
(height, value, input_type, typeindex, outputindex) (height, value, input_type, typeindex, outputindex, addressdata_opt)
}) })
.fold( .fold(
|| { || {
( (
BTreeMap::<Height, Transacted>::default(), BTreeMap::<Height, Transacted>::default(),
AddressIndexToTypeIndedToOutputIndex::default(), AddressTypeToTypeIndexVec::<OutputIndex>::default(),
AddressTypeToTypeIndexVec::<(Sats, Option<WithAddressDataSource<AddressData>>)>::default(),
) )
}, },
|(mut tree, mut vecs), (height, value, input_type, typeindex, outputindex)| { |(mut tree, mut vecs, mut vecs2), (height, value, input_type, typeindex, outputindex, addressdata_opt)| {
tree.entry(height).or_default().iterate(value, input_type); tree.entry(height).or_default().iterate(value, input_type);
if let Some( vec) = vecs.get_mut(input_type) { if let Some(vec) = vecs.get_mut(input_type) {
vec.push((typeindex, outputindex)); vec.push((typeindex, outputindex));
} }
(tree, vecs) if let Some(vec) = vecs2.get_mut(input_type) {
vec.push((typeindex, (value, addressdata_opt)));
}
(tree, vecs, vecs2)
}, },
) )
.reduce( || { .reduce( || {
( (
BTreeMap::<Height, Transacted>::default(), BTreeMap::<Height, Transacted>::default(),
AddressIndexToTypeIndedToOutputIndex::default(), AddressTypeToTypeIndexVec::<OutputIndex>::default(),
AddressTypeToTypeIndexVec::<(Sats, Option<WithAddressDataSource<AddressData>>)>::default(),
) )
}, |(first_tree, mut source_vecs), (second_tree, other_vecs)| { }, |(first_tree, mut source_vecs,mut source_vecs2), (second_tree, other_vecs, other_vecs2)| {
let (mut tree_source, tree_to_consume) = if first_tree.len() > second_tree.len() { let (mut tree_source, tree_to_consume) = if first_tree.len() > second_tree.len() {
(first_tree, second_tree) (first_tree, second_tree)
} else { } else {
@@ -471,7 +490,8 @@ impl Vecs {
*tree_source.entry(k).or_default() += v; *tree_source.entry(k).or_default() += v;
}); });
source_vecs.merge(other_vecs); source_vecs.merge(other_vecs);
(tree_source, source_vecs) source_vecs2.merge(other_vecs2);
(tree_source, source_vecs, source_vecs2)
}) })
}); });
@@ -498,29 +518,56 @@ impl Vecs {
.unwrap() .unwrap()
.into_owned(); .into_owned();
(value, output_type, typeindex, outputindex) let addressdata_opt = if output_type.is_address() && !addresstype_to_typeindex_to_addressdata.get(output_type).unwrap().contains_key(&typeindex) && !addresstype_to_typeindex_to_emptyaddressdata.get(output_type).unwrap().contains_key(&typeindex) {
Some(if let Some(addressdata) = stores.get_addressdata(output_type, typeindex).unwrap() {
WithAddressDataSource::FromAddressDataStore(addressdata)
} else if let Some(emptyaddressdata) = stores.get_emptyaddressdata(output_type, typeindex).unwrap() {
WithAddressDataSource::FromEmptyAddressDataStore(emptyaddressdata.into())
} else {
WithAddressDataSource::New(AddressData::default())
})
} else {
None
};
(value, output_type, typeindex, outputindex, addressdata_opt)
}) })
.fold( .fold(
|| (Transacted::default(), AddressIndexToTypeIndedToOutputIndex::default()), || (Transacted::default(), AddressTypeToTypeIndexVec::<OutputIndex>::default(),
|(mut transacted, mut vecs), (value, output_type, typeindex, outputindex)| { AddressTypeToTypeIndexVec::<(Sats, Option<WithAddressDataSource<AddressData>>)>::default(),
),
|(mut transacted, mut vecs, mut vecs2), (value, output_type, typeindex, outputindex, addressdata_opt)| {
transacted.iterate(value, output_type); transacted.iterate(value, output_type);
if let Some(vec) = vecs.get_mut(output_type) { if let Some(vec) = vecs.get_mut(output_type) {
vec.push((typeindex, outputindex)); vec.push((typeindex, outputindex));
} }
(transacted, vecs) if let Some(vec) = vecs2.get_mut(output_type) {
vec.push((typeindex, (value, addressdata_opt)));
}
(transacted, vecs, vecs2)
}, },
) )
.reduce(|| (Transacted::default(), AddressIndexToTypeIndedToOutputIndex::default()), |(transacted, mut vecs), (other_transacted, other_vecs)| { .reduce(|| (Transacted::default(), AddressTypeToTypeIndexVec::<OutputIndex>::default(),
AddressTypeToTypeIndexVec::<(Sats, Option<WithAddressDataSource<AddressData>>)>::default(),
), |(transacted, mut vecs, mut vecs2), (other_transacted, other_vecs, other_vecs2)| {
vecs.merge(other_vecs); vecs.merge(other_vecs);
(transacted + other_transacted, vecs) vecs2.merge(other_vecs2);
(transacted + other_transacted, vecs, vecs2)
}) })
}); });
(sent_handle.join().unwrap(), received_handle.join().unwrap()) (sent_handle.join().unwrap(), received_handle.join().unwrap())
}); });
addressindex_to_typedindex_to_sent_outputindex.merge(new_addressindex_to_typedindex_to_sent_outputindex); addresstype_to_typeindex_to_sent_outputindex.merge(new_addresstype_to_typedindex_to_sent_outputindex);
addressindex_to_typedindex_to_received_outputindex.merge(new_addressindex_to_typedindex_to_received_outputindex); addresstype_to_typeindex_to_received_outputindex.merge(new_addresstype_to_typedindex_to_received_outputindex);
addresstype_to_typedindex_to_received_sats_and_addressdata_opt.process_received(&mut addresstype_to_typeindex_to_addressdata, &mut addresstype_to_typeindex_to_emptyaddressdata, price);
// addresstype_to_typedindex_to_sent_sats_and_addressdata_opt;
// take from addressdata store
// apply
// update vecs states if cohort changes
unspendable_supply += received unspendable_supply += received
.by_type .by_type
@@ -617,8 +664,8 @@ impl Vecs {
)?; )?;
stores.commit( stores.commit(
height, height,
mem::take(&mut addressindex_to_typedindex_to_sent_outputindex), mem::take(&mut addresstype_to_typeindex_to_sent_outputindex),
mem::take( &mut addressindex_to_typedindex_to_received_outputindex) mem::take( &mut addresstype_to_typeindex_to_received_outputindex)
)?; )?;
exit.release(); exit.release();
} }
@@ -633,8 +680,8 @@ impl Vecs {
self.flush_states(height, &chain_state, exit)?; self.flush_states(height, &chain_state, exit)?;
stores.commit( stores.commit(
height, height,
mem::take(&mut addressindex_to_typedindex_to_sent_outputindex), mem::take(&mut addresstype_to_typeindex_to_sent_outputindex),
mem::take(&mut addressindex_to_typedindex_to_received_outputindex), mem::take(&mut addresstype_to_typeindex_to_received_outputindex),
)?; )?;
} else { } else {
exit.block(); exit.block();
@@ -756,3 +803,67 @@ impl Vecs {
.collect::<Vec<_>>() .collect::<Vec<_>>()
} }
} }
impl AddressTypeToTypeIndexVec<(Sats, Option<WithAddressDataSource<AddressData>>)> {
fn process_received(
mut self,
addresstype_to_typeindex_to_addressdata: &mut AddressTypeToTypeIndexTree<
WithAddressDataSource<AddressData>,
>,
addresstype_to_typeindex_to_emptyaddressdata: &mut AddressTypeToTypeIndexTree<
WithAddressDataSource<EmptyAddressData>,
>,
price: Option<Dollars>,
) {
self.into_typed_vec().into_iter().for_each(|(_type, vec)| {
vec.into_iter()
.for_each(|(type_index, (value, addressdata_opt))| {
addresstype_to_typeindex_to_addressdata
.get_mut(_type)
.unwrap()
.entry(type_index)
.or_insert_with(|| {
addressdata_opt.unwrap_or_else(|| {
addresstype_to_typeindex_to_emptyaddressdata
.get_mut(_type)
.unwrap()
.remove(&type_index)
.unwrap()
.into()
})
})
.deref_mut()
.receive(value, price);
// update vecs states if cohort changes
});
});
}
fn process_sent(
mut self,
addresstype_to_typeindex_to_addressdata: &mut AddressTypeToTypeIndexTree<
WithAddressDataSource<AddressData>,
>,
price: Option<Dollars>,
) -> Result<()> {
self.into_typed_vec()
.into_iter()
.try_for_each(|(_type, vec)| {
vec.into_iter()
.try_for_each(|(type_index, (value, addressdata_opt))| {
addresstype_to_typeindex_to_addressdata
.get_mut(_type)
.unwrap()
.entry(type_index)
.or_insert(addressdata_opt.unwrap())
.deref_mut()
.send(value, price)?;
Ok(())
// update vecs states if cohort changes
})
})
}
}

View File

@@ -0,0 +1,54 @@
use brk_core::{AddressData, EmptyAddressData};
#[derive(Debug)]
pub enum WithAddressDataSource<T> {
New(T),
FromAddressDataStore(T),
FromEmptyAddressDataStore(T),
}
impl<T> WithAddressDataSource<T> {
pub fn is_new(&self) -> bool {
matches!(self, Self::New(_))
}
pub fn deref(&self) -> &T {
match self {
Self::New(v) => v,
Self::FromAddressDataStore(v) => v,
Self::FromEmptyAddressDataStore(v) => v,
}
}
pub fn deref_mut(&mut self) -> &mut T {
match self {
Self::New(v) => v,
Self::FromAddressDataStore(v) => v,
Self::FromEmptyAddressDataStore(v) => v,
}
}
}
impl From<WithAddressDataSource<EmptyAddressData>> for WithAddressDataSource<AddressData> {
fn from(value: WithAddressDataSource<EmptyAddressData>) -> Self {
match value {
WithAddressDataSource::New(v) => Self::New(v.into()),
WithAddressDataSource::FromAddressDataStore(v) => Self::FromAddressDataStore(v.into()),
WithAddressDataSource::FromEmptyAddressDataStore(v) => {
Self::FromEmptyAddressDataStore(v.into())
}
}
}
}
impl From<WithAddressDataSource<AddressData>> for WithAddressDataSource<EmptyAddressData> {
fn from(value: WithAddressDataSource<AddressData>) -> Self {
match value {
WithAddressDataSource::New(v) => Self::New(v.into()),
WithAddressDataSource::FromAddressDataStore(v) => Self::FromAddressDataStore(v.into()),
WithAddressDataSource::FromEmptyAddressDataStore(v) => {
Self::FromEmptyAddressDataStore(v.into())
}
}
}
}

View File

@@ -1,4 +1,7 @@
use std::ops::{Add, AddAssign}; use std::{
mem,
ops::{Add, AddAssign},
};
use crate::OutputType; use crate::OutputType;
@@ -17,6 +20,20 @@ pub struct GroupedByAddressType<T> {
} }
impl<T> GroupedByAddressType<T> { impl<T> GroupedByAddressType<T> {
pub fn get(&self, address_type: OutputType) -> Option<&T> {
match address_type {
OutputType::P2PK65 => Some(&self.p2pk65),
OutputType::P2PK33 => Some(&self.p2pk33),
OutputType::P2PKH => Some(&self.p2pkh),
OutputType::P2SH => Some(&self.p2sh),
OutputType::P2WPKH => Some(&self.p2wpkh),
OutputType::P2WSH => Some(&self.p2wsh),
OutputType::P2TR => Some(&self.p2tr),
OutputType::P2A => Some(&self.p2a),
_ => None,
}
}
pub fn get_mut(&mut self, address_type: OutputType) -> Option<&mut T> { pub fn get_mut(&mut self, address_type: OutputType) -> Option<&mut T> {
match address_type { match address_type {
OutputType::P2PK65 => Some(&mut self.p2pk65), OutputType::P2PK65 => Some(&mut self.p2pk65),
@@ -56,6 +73,35 @@ impl<T> GroupedByAddressType<T> {
(OutputType::P2A, &self.p2a), (OutputType::P2A, &self.p2a),
] ]
} }
pub fn as_mut_typed_vec(&mut self) -> [(OutputType, &mut T); 8] {
[
(OutputType::P2PK65, &mut self.p2pk65),
(OutputType::P2PK33, &mut self.p2pk33),
(OutputType::P2PKH, &mut self.p2pkh),
(OutputType::P2SH, &mut self.p2sh),
(OutputType::P2WPKH, &mut self.p2wpkh),
(OutputType::P2WSH, &mut self.p2wsh),
(OutputType::P2TR, &mut self.p2tr),
(OutputType::P2A, &mut self.p2a),
]
}
pub fn into_typed_vec(&mut self) -> [(OutputType, T); 8]
where
T: Default,
{
[
(OutputType::P2PK65, mem::take(&mut self.p2pk65)),
(OutputType::P2PK33, mem::take(&mut self.p2pk33)),
(OutputType::P2PKH, mem::take(&mut self.p2pkh)),
(OutputType::P2SH, mem::take(&mut self.p2sh)),
(OutputType::P2WPKH, mem::take(&mut self.p2wpkh)),
(OutputType::P2WSH, mem::take(&mut self.p2wsh)),
(OutputType::P2TR, mem::take(&mut self.p2tr)),
(OutputType::P2A, mem::take(&mut self.p2a)),
]
}
} }
impl<T> GroupedByAddressType<(GroupFilter, T)> { impl<T> GroupedByAddressType<(GroupFilter, T)> {

View File

@@ -1,5 +1,4 @@
mod address; mod address;
mod addressindex_to_typeindex_to_outputindex;
mod by_address_type; mod by_address_type;
mod by_date_range; mod by_date_range;
mod by_epoch; mod by_epoch;
@@ -16,7 +15,6 @@ mod filter;
mod utxo; mod utxo;
pub use address::*; pub use address::*;
pub use addressindex_to_typeindex_to_outputindex::*;
pub use by_address_type::*; pub use by_address_type::*;
pub use by_date_range::*; pub use by_date_range::*;
pub use by_epoch::*; pub use by_epoch::*;

View File

@@ -31,22 +31,26 @@ impl AddressData {
} }
} }
pub fn receive(&mut self, amount: Sats, price: Dollars) { pub fn receive(&mut self, amount: Sats, price: Option<Dollars>) {
self.received += amount; self.received += amount;
self.outputs_len += 1; self.outputs_len += 1;
self.realized_cap += price * amount; if let Some(price) = price {
self.realized_cap += price * amount;
}
} }
pub fn send(&mut self, amount: Sats, previous_price: Dollars) -> Result<()> { pub fn send(&mut self, amount: Sats, previous_price: Option<Dollars>) -> Result<()> {
if self.amount() < amount { if self.amount() < amount {
return Err(Error::String("Previous_amount smaller than sent amount")); return Err(Error::String("Previous_amount smaller than sent amount"));
} }
self.sent += amount; self.sent += amount;
self.outputs_len -= 1; self.outputs_len -= 1;
self.realized_cap = self if let Some(previous_price) = previous_price {
.realized_cap self.realized_cap = self
.checked_sub(previous_price * amount) .realized_cap
.unwrap(); .checked_sub(previous_price * amount)
.unwrap();
}
Ok(()) Ok(())
} }
} }

View File

@@ -50,6 +50,23 @@ impl OutputType {
} }
} }
pub fn is_address(&self) -> bool {
match self {
Self::P2PK65 => true,
Self::P2PK33 => true,
Self::P2PKH => true,
Self::P2MS => false,
Self::P2SH => true,
Self::OpReturn => false,
Self::P2WPKH => true,
Self::P2WSH => true,
Self::P2TR => true,
Self::P2A => true,
Self::Empty => false,
Self::Unknown => false,
}
}
pub fn is_unspendable(&self) -> bool { pub fn is_unspendable(&self) -> bool {
!self.is_spendable() !self.is_spendable()
} }