mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-05-14 13:08:36 -07:00
computer: store part 4
This commit is contained in:
@@ -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_(
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
19
crates/brk_computer/src/vecs/stateful/anyaddressdata.rs
Normal file
19
crates/brk_computer/src/vecs/stateful/anyaddressdata.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)> {
|
||||||
|
|||||||
@@ -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::*;
|
||||||
|
|||||||
@@ -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(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user