mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-05-27 01:54:47 -07:00
computer: snapshot
This commit is contained in:
@@ -5,6 +5,7 @@ mod from_dateindex;
|
||||
mod from_height;
|
||||
mod from_height_strict;
|
||||
mod from_txindex;
|
||||
mod price_percentiles;
|
||||
mod ratio_from_dateindex;
|
||||
mod sd_from_dateindex;
|
||||
mod source;
|
||||
@@ -20,6 +21,7 @@ pub use from_dateindex::*;
|
||||
pub use from_height::*;
|
||||
pub use from_height_strict::*;
|
||||
pub use from_txindex::*;
|
||||
pub use price_percentiles::*;
|
||||
pub use ratio_from_dateindex::*;
|
||||
pub use sd_from_dateindex::*;
|
||||
pub use source::*;
|
||||
|
||||
94
crates/brk_computer/src/grouped/price_percentiles.rs
Normal file
94
crates/brk_computer/src/grouped/price_percentiles.rs
Normal file
@@ -0,0 +1,94 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::{Traversable, TreeNode};
|
||||
use brk_types::{Dollars, Height, Version};
|
||||
use vecdb::{AnyExportableVec, Database, EagerVec, Exit, PcoVec};
|
||||
|
||||
use crate::{indexes, Indexes};
|
||||
|
||||
use super::{ComputedVecsFromHeight, Source, VecBuilderOptions};
|
||||
|
||||
pub const PERCENTILES: [u8; 21] = [
|
||||
0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100,
|
||||
];
|
||||
pub const PERCENTILES_LEN: usize = PERCENTILES.len();
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PricePercentiles {
|
||||
pub vecs: [Option<ComputedVecsFromHeight<Dollars>>; PERCENTILES_LEN],
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl PricePercentiles {
|
||||
pub fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
compute: bool,
|
||||
) -> Result<Self> {
|
||||
let vecs = PERCENTILES.map(|p| {
|
||||
compute.then(|| {
|
||||
ComputedVecsFromHeight::forced_import(
|
||||
db,
|
||||
&format!("{name}_price_pct{p:02}"),
|
||||
Source::Compute,
|
||||
version + VERSION,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)
|
||||
.unwrap()
|
||||
})
|
||||
});
|
||||
|
||||
Ok(Self { vecs })
|
||||
}
|
||||
|
||||
pub fn truncate_push(
|
||||
&mut self,
|
||||
height: Height,
|
||||
percentile_prices: &[Dollars; PERCENTILES_LEN],
|
||||
) -> Result<()> {
|
||||
for (i, vec) in self.vecs.iter_mut().enumerate() {
|
||||
if let Some(v) = vec {
|
||||
v.height.as_mut().unwrap().truncate_push(height, percentile_prices[i])?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
for vec in self.vecs.iter_mut().flatten() {
|
||||
vec.compute_rest(indexes, starting_indexes, exit, None::<&EagerVec<PcoVec<Height, Dollars>>>)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get(&self, percentile: u8) -> Option<&ComputedVecsFromHeight<Dollars>> {
|
||||
PERCENTILES
|
||||
.iter()
|
||||
.position(|&p| p == percentile)
|
||||
.and_then(|i| self.vecs[i].as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl Traversable for PricePercentiles {
|
||||
fn to_tree_node(&self) -> TreeNode {
|
||||
TreeNode::Branch(
|
||||
PERCENTILES
|
||||
.iter()
|
||||
.zip(self.vecs.iter())
|
||||
.filter_map(|(p, v)| v.as_ref().map(|v| (format!("pct{p:02}"), v.to_tree_node())))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
fn iter_any_exportable(&self) -> impl Iterator<Item = &dyn AnyExportableVec> {
|
||||
self.vecs.iter().flatten().flat_map(|p| p.iter_any_exportable())
|
||||
}
|
||||
}
|
||||
@@ -229,8 +229,6 @@ impl Computer {
|
||||
)?;
|
||||
info!("Computed pools in {:?}", i.elapsed());
|
||||
|
||||
return Ok(());
|
||||
|
||||
info!("Computing stateful...");
|
||||
self.stateful.compute(
|
||||
indexer,
|
||||
@@ -241,6 +239,8 @@ impl Computer {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
return Ok(());
|
||||
|
||||
info!("Computing cointime...");
|
||||
self.cointime.compute(
|
||||
&self.indexes,
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use std::mem;
|
||||
use std::{collections::hash_map::Entry, mem};
|
||||
|
||||
use brk_grouper::ByAddressType;
|
||||
use brk_types::{OutputType, TypeIndex};
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use rustc_hash::FxHashMap;
|
||||
use smallvec::{Array, SmallVec};
|
||||
|
||||
#[derive(Debug, Deref, DerefMut)]
|
||||
pub struct AddressTypeToTypeIndexMap<T>(ByAddressType<FxHashMap<TypeIndex, T>>);
|
||||
@@ -44,12 +45,17 @@ impl<T> AddressTypeToTypeIndexMap<T> {
|
||||
}
|
||||
|
||||
pub fn into_sorted_iter(self) -> impl Iterator<Item = (OutputType, Vec<(TypeIndex, T)>)> {
|
||||
self.0.into_iter_typed().map(|(output_type, map)| {
|
||||
self.0.into_iter().map(|(output_type, map)| {
|
||||
let mut sorted: Vec<_> = map.into_iter().collect();
|
||||
sorted.sort_unstable_by_key(|(typeindex, _)| *typeindex);
|
||||
(output_type, sorted)
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(clippy::should_implement_trait)]
|
||||
pub fn into_iter(self) -> impl Iterator<Item = (OutputType, FxHashMap<TypeIndex, T>)> {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for AddressTypeToTypeIndexMap<T> {
|
||||
@@ -67,23 +73,26 @@ impl<T> Default for AddressTypeToTypeIndexMap<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AddressTypeToTypeIndexMap<Vec<T>>
|
||||
impl<T> AddressTypeToTypeIndexMap<SmallVec<T>>
|
||||
where
|
||||
T: Copy,
|
||||
T: Array,
|
||||
{
|
||||
pub fn merge_vec(mut self, other: Self) -> Self {
|
||||
for (address_type, other_map) in other.0.into_iter_typed() {
|
||||
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 {
|
||||
self_map
|
||||
.entry(typeindex)
|
||||
.and_modify(|self_vec| {
|
||||
match self_map.entry(typeindex) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
let self_vec = entry.get_mut();
|
||||
if other_vec.len() > self_vec.len() {
|
||||
mem::swap(self_vec, &mut other_vec);
|
||||
}
|
||||
self_vec.extend(other_vec.iter().copied());
|
||||
})
|
||||
.or_insert(other_vec);
|
||||
self_vec.extend(other_vec);
|
||||
}
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(other_vec);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self
|
||||
|
||||
@@ -12,7 +12,8 @@ use crate::{
|
||||
Indexes,
|
||||
grouped::{
|
||||
ComputedHeightValueVecs, ComputedRatioVecsFromDateIndex, ComputedValueVecsFromDateIndex,
|
||||
ComputedVecsFromDateIndex, ComputedVecsFromHeight, Source, VecBuilderOptions,
|
||||
ComputedValueVecsFromHeight, ComputedVecsFromDateIndex, ComputedVecsFromHeight,
|
||||
PricePercentiles, Source, VecBuilderOptions,
|
||||
},
|
||||
indexes, price,
|
||||
states::CohortState,
|
||||
@@ -41,9 +42,11 @@ pub struct Vecs {
|
||||
pub height_to_unrealized_profit: Option<EagerVec<PcoVec<Height, Dollars>>>,
|
||||
pub height_to_value_created: Option<EagerVec<PcoVec<Height, Dollars>>>,
|
||||
pub height_to_value_destroyed: Option<EagerVec<PcoVec<Height, Dollars>>>,
|
||||
pub height_to_sent: EagerVec<PcoVec<Height, Sats>>,
|
||||
pub height_to_satblocks_destroyed: EagerVec<PcoVec<Height, Sats>>,
|
||||
pub height_to_satdays_destroyed: EagerVec<PcoVec<Height, Sats>>,
|
||||
|
||||
pub indexes_to_sent: ComputedValueVecsFromHeight,
|
||||
pub indexes_to_coinblocks_destroyed: ComputedVecsFromHeight<StoredF64>,
|
||||
pub indexes_to_coindays_destroyed: ComputedVecsFromHeight<StoredF64>,
|
||||
pub dateindex_to_sopr: Option<EagerVec<PcoVec<DateIndex, StoredF64>>>,
|
||||
@@ -79,6 +82,7 @@ pub struct Vecs {
|
||||
pub indexes_to_total_realized_pnl: Option<ComputedVecsFromDateIndex<Dollars>>,
|
||||
pub indexes_to_min_price_paid: Option<ComputedVecsFromHeight<Dollars>>,
|
||||
pub indexes_to_max_price_paid: Option<ComputedVecsFromHeight<Dollars>>,
|
||||
pub price_percentiles: Option<PricePercentiles>,
|
||||
pub height_to_supply_half_value: ComputedHeightValueVecs,
|
||||
pub indexes_to_supply_half: ComputedValueVecsFromDateIndex,
|
||||
pub height_to_neg_unrealized_loss: Option<EagerVec<PcoVec<Height, Dollars>>>,
|
||||
@@ -356,6 +360,16 @@ impl Vecs {
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
price_percentiles: (compute_dollars && extended).then(|| {
|
||||
PricePercentiles::forced_import(
|
||||
db,
|
||||
&suffix(""),
|
||||
version + Version::ZERO,
|
||||
indexes,
|
||||
true,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
height_to_supply: EagerVec::forced_import(
|
||||
db,
|
||||
&suffix("supply"),
|
||||
@@ -1075,6 +1089,11 @@ impl Vecs {
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
height_to_sent: EagerVec::forced_import(
|
||||
db,
|
||||
&suffix("sent"),
|
||||
version + Version::ZERO,
|
||||
)?,
|
||||
height_to_satblocks_destroyed: EagerVec::forced_import(
|
||||
db,
|
||||
&suffix("satblocks_destroyed"),
|
||||
@@ -1085,6 +1104,15 @@ impl Vecs {
|
||||
&suffix("satdays_destroyed"),
|
||||
version + Version::ZERO,
|
||||
)?,
|
||||
indexes_to_sent: ComputedValueVecsFromHeight::forced_import(
|
||||
db,
|
||||
&suffix("sent"),
|
||||
Source::Compute,
|
||||
version + Version::ZERO,
|
||||
VecBuilderOptions::default().add_sum(),
|
||||
compute_dollars,
|
||||
indexes,
|
||||
)?,
|
||||
indexes_to_coinblocks_destroyed: ComputedVecsFromHeight::forced_import(
|
||||
db,
|
||||
&suffix("coinblocks_destroyed"),
|
||||
@@ -1190,6 +1218,7 @@ impl Vecs {
|
||||
self.height_to_max_price_paid
|
||||
.as_ref()
|
||||
.map_or(usize::MAX, |v| v.len()),
|
||||
self.height_to_sent.len(),
|
||||
self.height_to_satdays_destroyed.len(),
|
||||
self.height_to_satblocks_destroyed.len(),
|
||||
]
|
||||
@@ -1235,6 +1264,11 @@ impl Vecs {
|
||||
base_version + self.height_to_utxo_count.inner_version(),
|
||||
)?;
|
||||
|
||||
self.height_to_sent
|
||||
.validate_computed_version_or_reset(
|
||||
base_version + self.height_to_sent.inner_version(),
|
||||
)?;
|
||||
|
||||
self.height_to_satblocks_destroyed
|
||||
.validate_computed_version_or_reset(
|
||||
base_version + self.height_to_satblocks_destroyed.inner_version(),
|
||||
@@ -1441,6 +1475,8 @@ impl Vecs {
|
||||
self.height_to_utxo_count
|
||||
.truncate_push(height, StoredU64::from(state.supply.utxo_count))?;
|
||||
|
||||
self.height_to_sent.truncate_push(height, state.sent)?;
|
||||
|
||||
self.height_to_satblocks_destroyed
|
||||
.truncate_push(height, state.satblocks_destroyed)?;
|
||||
|
||||
@@ -1569,6 +1605,7 @@ impl Vecs {
|
||||
) -> Result<()> {
|
||||
self.height_to_supply.safe_flush(exit)?;
|
||||
self.height_to_utxo_count.safe_flush(exit)?;
|
||||
self.height_to_sent.safe_flush(exit)?;
|
||||
self.height_to_satdays_destroyed.safe_flush(exit)?;
|
||||
self.height_to_satblocks_destroyed.safe_flush(exit)?;
|
||||
|
||||
@@ -1672,6 +1709,15 @@ impl Vecs {
|
||||
.as_slice(),
|
||||
exit,
|
||||
)?;
|
||||
self.height_to_sent.compute_sum_of_others(
|
||||
starting_indexes.height,
|
||||
others
|
||||
.iter()
|
||||
.map(|v| &v.height_to_sent)
|
||||
.collect::<Vec<_>>()
|
||||
.as_slice(),
|
||||
exit,
|
||||
)?;
|
||||
self.height_to_satblocks_destroyed.compute_sum_of_others(
|
||||
starting_indexes.height,
|
||||
others
|
||||
@@ -1999,6 +2045,9 @@ impl Vecs {
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.indexes_to_sent
|
||||
.compute_rest(indexes, price, starting_indexes, exit, Some(&self.height_to_sent))?;
|
||||
|
||||
self.indexes_to_coinblocks_destroyed
|
||||
.compute_all(indexes, starting_indexes, exit, |v| {
|
||||
v.compute_transform(
|
||||
|
||||
@@ -778,7 +778,6 @@ impl Vecs {
|
||||
let mut height_to_first_p2wshaddressindex_iter =
|
||||
height_to_first_p2wshaddressindex.into_iter();
|
||||
let mut height_to_first_txindex_iter = height_to_first_txindex.into_iter();
|
||||
let mut height_to_txindex_count_iter = height_to_txindex_count.into_iter();
|
||||
let mut height_to_first_txinindex_iter = height_to_first_txinindex.into_iter();
|
||||
let mut height_to_first_txoutindex_iter = height_to_first_txoutindex.into_iter();
|
||||
let mut height_to_input_count_iter = height_to_input_count.into_iter();
|
||||
@@ -908,17 +907,21 @@ impl Vecs {
|
||||
mut height_to_sent,
|
||||
addresstype_to_typedindex_to_sent_data,
|
||||
mut stored_or_new_addresstype_to_typeindex_to_addressdatawithsource,
|
||||
mut combined_txindex_vecs,
|
||||
) = thread::scope(|scope| {
|
||||
scope.spawn(|| {
|
||||
self.utxo_cohorts
|
||||
.tick_tock_next_block(&chain_state, timestamp);
|
||||
});
|
||||
|
||||
let (transacted, addresstype_to_typedindex_to_received_data, receiving_addresstype_to_typeindex_to_addressdatawithsource) = (first_txoutindex..first_txoutindex + usize::from(output_count))
|
||||
let (transacted, addresstype_to_typedindex_to_received_data, receiving_addresstype_to_typeindex_to_addressdatawithsource, output_txindex_vecs) = (first_txoutindex..first_txoutindex + usize::from(output_count))
|
||||
.into_par_iter()
|
||||
.map(|i| {
|
||||
let txoutindex = TxOutIndex::from(i);
|
||||
|
||||
let local_idx = i - first_txoutindex;
|
||||
let txindex = txoutindex_to_txindex[local_idx];
|
||||
|
||||
let value = txoutindex_to_value
|
||||
.read_unwrap(txoutindex, &ir.txoutindex_to_value);
|
||||
|
||||
@@ -926,7 +929,7 @@ impl Vecs {
|
||||
.read_unwrap(txoutindex, &ir.txoutindex_to_outputtype);
|
||||
|
||||
if output_type.is_not_address() {
|
||||
return (value, output_type, None);
|
||||
return (txindex, value, output_type, None);
|
||||
}
|
||||
|
||||
let typeindex = txoutindex_to_typeindex
|
||||
@@ -943,17 +946,19 @@ impl Vecs {
|
||||
&self.addresses_data,
|
||||
);
|
||||
|
||||
(value, output_type, Some((typeindex, addressdata_opt)))
|
||||
(txindex, value, output_type, Some(( typeindex, addressdata_opt)))
|
||||
}).fold(
|
||||
|| {
|
||||
(
|
||||
Transacted::default(),
|
||||
AddressTypeToVec::<(TypeIndex, Sats)>::default(),
|
||||
AddressTypeToTypeIndexMap::default()
|
||||
AddressTypeToTypeIndexMap::default(),
|
||||
AddressTypeToTypeIndexMap::<TxIndexVec>::default(),
|
||||
)
|
||||
},
|
||||
|(mut transacted, mut addresstype_to_typedindex_to_data, mut addresstype_to_typeindex_to_addressdatawithsource),
|
||||
|(mut transacted, mut addresstype_to_typedindex_to_data, mut addresstype_to_typeindex_to_addressdatawithsource, mut txindex_vecs),
|
||||
(
|
||||
txindex,
|
||||
value,
|
||||
output_type,
|
||||
typeindex_with_addressdata_opt,
|
||||
@@ -967,23 +972,33 @@ impl Vecs {
|
||||
.insert_for_type(output_type, typeindex, addressdata);
|
||||
}
|
||||
|
||||
let addr_type = output_type;
|
||||
|
||||
addresstype_to_typedindex_to_data
|
||||
.get_mut(output_type)
|
||||
.get_mut(addr_type)
|
||||
.unwrap()
|
||||
.push((typeindex, value));
|
||||
|
||||
txindex_vecs
|
||||
.get_mut(addr_type)
|
||||
.unwrap()
|
||||
.entry(typeindex)
|
||||
.or_insert_with(TxIndexVec::new)
|
||||
.push(txindex);
|
||||
}
|
||||
|
||||
(transacted, addresstype_to_typedindex_to_data, addresstype_to_typeindex_to_addressdatawithsource)
|
||||
(transacted, addresstype_to_typedindex_to_data, addresstype_to_typeindex_to_addressdatawithsource, txindex_vecs)
|
||||
}).reduce(
|
||||
|| {
|
||||
(
|
||||
Transacted::default(),
|
||||
AddressTypeToVec::<(TypeIndex, Sats)>::default(),
|
||||
AddressTypeToTypeIndexMap::default()
|
||||
AddressTypeToTypeIndexMap::default(),
|
||||
AddressTypeToTypeIndexMap::<TxIndexVec>::default(),
|
||||
)
|
||||
},
|
||||
|(transacted, addresstype_to_typedindex_to_data, addresstype_to_typeindex_to_addressdatawithsource), (transacted2, addresstype_to_typedindex_to_data2, addresstype_to_typeindex_to_addressdatawithsource2)| {
|
||||
(transacted + transacted2, addresstype_to_typedindex_to_data.merge(addresstype_to_typedindex_to_data2), addresstype_to_typeindex_to_addressdatawithsource.merge(addresstype_to_typeindex_to_addressdatawithsource2))
|
||||
|(transacted, addresstype_to_typedindex_to_data, addresstype_to_typeindex_to_addressdatawithsource, txindex_vecs), (transacted2, addresstype_to_typedindex_to_data2, addresstype_to_typeindex_to_addressdatawithsource2, txindex_vecs2)| {
|
||||
(transacted + transacted2, addresstype_to_typedindex_to_data.merge(addresstype_to_typedindex_to_data2), addresstype_to_typeindex_to_addressdatawithsource.merge(addresstype_to_typeindex_to_addressdatawithsource2), txindex_vecs.merge_vec(txindex_vecs2))
|
||||
},
|
||||
);
|
||||
|
||||
@@ -992,185 +1007,230 @@ impl Vecs {
|
||||
height_to_sent,
|
||||
addresstype_to_typedindex_to_sent_data,
|
||||
sending_addresstype_to_typeindex_to_addressdatawithsource,
|
||||
) =
|
||||
(first_txinindex + 1..first_txinindex + usize::from(input_count))
|
||||
.into_par_iter()
|
||||
.map(|i| {
|
||||
let txinindex = TxInIndex::from(i);
|
||||
input_txindex_vecs,
|
||||
) = (first_txinindex + 1..first_txinindex + usize::from(input_count))
|
||||
.into_par_iter()
|
||||
.map(|i| {
|
||||
let txinindex = TxInIndex::from(i);
|
||||
|
||||
let outpoint = txinindex_to_outpoint
|
||||
.read_unwrap(txinindex, &ir.txinindex_to_outpoint);
|
||||
let local_idx = i - first_txinindex;
|
||||
let txindex = txinindex_to_txindex[local_idx];
|
||||
|
||||
let txoutindex = txindex_to_first_txoutindex.read_unwrap(
|
||||
outpoint.txindex(),
|
||||
&ir.txindex_to_first_txoutindex,
|
||||
) + outpoint.vout();
|
||||
let outpoint = txinindex_to_outpoint
|
||||
.read_unwrap(txinindex, &ir.txinindex_to_outpoint);
|
||||
|
||||
let value = txoutindex_to_value
|
||||
.read_unwrap(txoutindex, &ir.txoutindex_to_value);
|
||||
let txoutindex = txindex_to_first_txoutindex
|
||||
.read_unwrap(outpoint.txindex(), &ir.txindex_to_first_txoutindex)
|
||||
+ outpoint.vout();
|
||||
|
||||
let input_type = txoutindex_to_outputtype
|
||||
.read_unwrap(txoutindex, &ir.txoutindex_to_outputtype);
|
||||
let value = txoutindex_to_value
|
||||
.read_unwrap(txoutindex, &ir.txoutindex_to_value);
|
||||
|
||||
let prev_height =
|
||||
*txoutindex_range_to_height.get(txoutindex).unwrap();
|
||||
let input_type = txoutindex_to_outputtype
|
||||
.read_unwrap(txoutindex, &ir.txoutindex_to_outputtype);
|
||||
|
||||
if input_type.is_not_address() {
|
||||
return (prev_height, value, input_type, None);
|
||||
}
|
||||
let prev_height = *txoutindex_range_to_height.get(txoutindex).unwrap();
|
||||
|
||||
let typeindex = txoutindex_to_typeindex
|
||||
.read_unwrap(txoutindex, &ir.txoutindex_to_typeindex);
|
||||
if input_type.is_not_address() {
|
||||
return (txindex, prev_height, value, input_type, None);
|
||||
}
|
||||
|
||||
let addressdata_opt = Self::get_addressdatawithsource(
|
||||
input_type,
|
||||
typeindex,
|
||||
&first_addressindexes,
|
||||
&addresstype_to_typeindex_to_loadedaddressdata,
|
||||
&addresstype_to_typeindex_to_emptyaddressdata,
|
||||
&vr,
|
||||
&self.any_address_indexes,
|
||||
&self.addresses_data,
|
||||
);
|
||||
let typeindex = txoutindex_to_typeindex
|
||||
.read_unwrap(txoutindex, &ir.txoutindex_to_typeindex);
|
||||
|
||||
let addressdata_opt = Self::get_addressdatawithsource(
|
||||
input_type,
|
||||
typeindex,
|
||||
&first_addressindexes,
|
||||
&addresstype_to_typeindex_to_loadedaddressdata,
|
||||
&addresstype_to_typeindex_to_emptyaddressdata,
|
||||
&vr,
|
||||
&self.any_address_indexes,
|
||||
&self.addresses_data,
|
||||
);
|
||||
|
||||
(
|
||||
txindex,
|
||||
prev_height,
|
||||
value,
|
||||
input_type,
|
||||
Some((typeindex, addressdata_opt)),
|
||||
)
|
||||
})
|
||||
.fold(
|
||||
|| {
|
||||
(
|
||||
prev_height,
|
||||
value,
|
||||
input_type,
|
||||
Some((typeindex, addressdata_opt)),
|
||||
FxHashMap::<Height, Transacted>::default(),
|
||||
HeightToAddressTypeToVec::<(TypeIndex, Sats)>::default(),
|
||||
AddressTypeToTypeIndexMap::default(),
|
||||
AddressTypeToTypeIndexMap::<TxIndexVec>::default(),
|
||||
)
|
||||
})
|
||||
.fold(
|
||||
|| {
|
||||
(
|
||||
FxHashMap::<Height, Transacted>::default(),
|
||||
HeightToAddressTypeToVec::<(TypeIndex, Sats)>::default(),
|
||||
AddressTypeToTypeIndexMap::default(),
|
||||
)
|
||||
},
|
||||
|(
|
||||
mut height_to_transacted,
|
||||
mut height_to_addresstype_to_typedindex_to_data,
|
||||
mut addresstype_to_typeindex_to_addressdatawithsource,
|
||||
),
|
||||
(
|
||||
prev_height,
|
||||
value,
|
||||
output_type,
|
||||
typeindex_with_addressdata_opt,
|
||||
)| {
|
||||
height_to_transacted
|
||||
.entry(prev_height)
|
||||
.or_default()
|
||||
.iterate(value, output_type);
|
||||
},
|
||||
|(
|
||||
mut height_to_transacted,
|
||||
mut height_to_addresstype_to_typedindex_to_data,
|
||||
mut addresstype_to_typeindex_to_addressdatawithsource,
|
||||
mut txindex_vecs,
|
||||
),
|
||||
(
|
||||
txindex,
|
||||
prev_height,
|
||||
value,
|
||||
output_type,
|
||||
typeindex_with_addressdata_opt,
|
||||
)| {
|
||||
height_to_transacted
|
||||
.entry(prev_height)
|
||||
.or_default()
|
||||
.iterate(value, output_type);
|
||||
|
||||
if let Some((typeindex, addressdata_opt)) =
|
||||
typeindex_with_addressdata_opt
|
||||
{
|
||||
if let Some(addressdata) = addressdata_opt {
|
||||
addresstype_to_typeindex_to_addressdatawithsource
|
||||
.insert_for_type(
|
||||
output_type,
|
||||
typeindex,
|
||||
addressdata,
|
||||
);
|
||||
}
|
||||
|
||||
height_to_addresstype_to_typedindex_to_data
|
||||
.entry(prev_height)
|
||||
.or_default()
|
||||
.get_mut(output_type)
|
||||
.unwrap()
|
||||
.push((typeindex, value));
|
||||
if let Some((typeindex, addressdata_opt)) =
|
||||
typeindex_with_addressdata_opt
|
||||
{
|
||||
if let Some(addressdata) = addressdata_opt {
|
||||
addresstype_to_typeindex_to_addressdatawithsource
|
||||
.insert_for_type(output_type, typeindex, addressdata);
|
||||
}
|
||||
|
||||
let addr_type = output_type;
|
||||
|
||||
height_to_addresstype_to_typedindex_to_data
|
||||
.entry(prev_height)
|
||||
.or_default()
|
||||
.get_mut(addr_type)
|
||||
.unwrap()
|
||||
.push((typeindex, value));
|
||||
|
||||
txindex_vecs
|
||||
.get_mut(addr_type)
|
||||
.unwrap()
|
||||
.entry(typeindex)
|
||||
.or_insert_with(TxIndexVec::new)
|
||||
.push(txindex);
|
||||
}
|
||||
|
||||
(
|
||||
height_to_transacted,
|
||||
height_to_addresstype_to_typedindex_to_data,
|
||||
addresstype_to_typeindex_to_addressdatawithsource,
|
||||
txindex_vecs,
|
||||
)
|
||||
},
|
||||
)
|
||||
.reduce(
|
||||
|| {
|
||||
(
|
||||
FxHashMap::<Height, Transacted>::default(),
|
||||
HeightToAddressTypeToVec::<(TypeIndex, Sats)>::default(),
|
||||
AddressTypeToTypeIndexMap::default(),
|
||||
AddressTypeToTypeIndexMap::<TxIndexVec>::default(),
|
||||
)
|
||||
},
|
||||
|(
|
||||
height_to_transacted,
|
||||
addresstype_to_typedindex_to_data,
|
||||
addresstype_to_typeindex_to_addressdatawithsource,
|
||||
txindex_vecs,
|
||||
),
|
||||
(
|
||||
height_to_transacted2,
|
||||
addresstype_to_typedindex_to_data2,
|
||||
addresstype_to_typeindex_to_addressdatawithsource2,
|
||||
txindex_vecs2,
|
||||
)| {
|
||||
let (mut height_to_transacted, height_to_transacted_consumed) =
|
||||
if height_to_transacted.len() > height_to_transacted2.len() {
|
||||
(height_to_transacted, height_to_transacted2)
|
||||
} else {
|
||||
(height_to_transacted2, height_to_transacted)
|
||||
};
|
||||
height_to_transacted_consumed
|
||||
.into_iter()
|
||||
.for_each(|(k, v)| {
|
||||
*height_to_transacted.entry(k).or_default() += v;
|
||||
});
|
||||
|
||||
let (
|
||||
mut addresstype_to_typedindex_to_data,
|
||||
addresstype_to_typedindex_to_data_consumed,
|
||||
) = if addresstype_to_typedindex_to_data.len()
|
||||
> addresstype_to_typedindex_to_data2.len()
|
||||
{
|
||||
(
|
||||
height_to_transacted,
|
||||
height_to_addresstype_to_typedindex_to_data,
|
||||
addresstype_to_typeindex_to_addressdatawithsource,
|
||||
addresstype_to_typedindex_to_data,
|
||||
addresstype_to_typedindex_to_data2,
|
||||
)
|
||||
},
|
||||
)
|
||||
.reduce(
|
||||
|| {
|
||||
} else {
|
||||
(
|
||||
FxHashMap::<Height, Transacted>::default(),
|
||||
HeightToAddressTypeToVec::<(TypeIndex, Sats)>::default(),
|
||||
AddressTypeToTypeIndexMap::default(),
|
||||
addresstype_to_typedindex_to_data2,
|
||||
addresstype_to_typedindex_to_data,
|
||||
)
|
||||
},
|
||||
|(
|
||||
};
|
||||
addresstype_to_typedindex_to_data_consumed
|
||||
.0
|
||||
.into_iter()
|
||||
.for_each(|(k, v)| {
|
||||
addresstype_to_typedindex_to_data
|
||||
.entry(k)
|
||||
.or_default()
|
||||
.merge_mut(v);
|
||||
});
|
||||
|
||||
(
|
||||
height_to_transacted,
|
||||
addresstype_to_typedindex_to_data,
|
||||
addresstype_to_typeindex_to_addressdatawithsource,
|
||||
),
|
||||
(
|
||||
height_to_transacted2,
|
||||
addresstype_to_typedindex_to_data2,
|
||||
addresstype_to_typeindex_to_addressdatawithsource2,
|
||||
)| {
|
||||
let (mut height_to_transacted, height_to_transacted_consumed) =
|
||||
if height_to_transacted.len() > height_to_transacted2.len()
|
||||
{
|
||||
(height_to_transacted, height_to_transacted2)
|
||||
} else {
|
||||
(height_to_transacted2, height_to_transacted)
|
||||
};
|
||||
height_to_transacted_consumed
|
||||
.into_iter()
|
||||
.for_each(|(k, v)| {
|
||||
*height_to_transacted.entry(k).or_default() += v;
|
||||
});
|
||||
|
||||
let (
|
||||
mut addresstype_to_typedindex_to_data,
|
||||
addresstype_to_typedindex_to_data_consumed,
|
||||
) = if addresstype_to_typedindex_to_data.len()
|
||||
> addresstype_to_typedindex_to_data2.len()
|
||||
{
|
||||
(
|
||||
addresstype_to_typedindex_to_data,
|
||||
addresstype_to_typedindex_to_data2,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
addresstype_to_typedindex_to_data2,
|
||||
addresstype_to_typedindex_to_data,
|
||||
)
|
||||
};
|
||||
addresstype_to_typedindex_to_data_consumed
|
||||
.0
|
||||
.into_iter()
|
||||
.for_each(|(k, v)| {
|
||||
addresstype_to_typedindex_to_data
|
||||
.entry(k)
|
||||
.or_default()
|
||||
.merge_mut(v);
|
||||
});
|
||||
|
||||
(
|
||||
height_to_transacted,
|
||||
addresstype_to_typedindex_to_data,
|
||||
addresstype_to_typeindex_to_addressdatawithsource.merge(
|
||||
addresstype_to_typeindex_to_addressdatawithsource2,
|
||||
),
|
||||
)
|
||||
},
|
||||
);
|
||||
addresstype_to_typeindex_to_addressdatawithsource
|
||||
.merge(addresstype_to_typeindex_to_addressdatawithsource2),
|
||||
txindex_vecs.merge_vec(txindex_vecs2),
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
let addresstype_to_typeindex_to_addressdatawithsource =
|
||||
receiving_addresstype_to_typeindex_to_addressdatawithsource
|
||||
.merge(sending_addresstype_to_typeindex_to_addressdatawithsource);
|
||||
|
||||
let combined_txindex_vecs = output_txindex_vecs.merge_vec(input_txindex_vecs);
|
||||
|
||||
(
|
||||
transacted,
|
||||
addresstype_to_typedindex_to_received_data,
|
||||
height_to_sent,
|
||||
addresstype_to_typedindex_to_sent_data,
|
||||
addresstype_to_typeindex_to_addressdatawithsource,
|
||||
combined_txindex_vecs,
|
||||
)
|
||||
});
|
||||
|
||||
combined_txindex_vecs
|
||||
.par_values_mut()
|
||||
.flat_map(|typeindex_to_txindexes| typeindex_to_txindexes.par_iter_mut())
|
||||
.map(|(_, v)| v)
|
||||
.filter(|txindex_vec| txindex_vec.len() > 1)
|
||||
.for_each(|txindex_vec| {
|
||||
txindex_vec.sort_unstable();
|
||||
txindex_vec.dedup();
|
||||
});
|
||||
|
||||
for (address_type, typeindex, txindex_vec) in combined_txindex_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;
|
||||
|
||||
if let Some(addressdata) = addresstype_to_typeindex_to_loadedaddressdata
|
||||
.get_mut_unwrap(address_type)
|
||||
.get_mut(&typeindex)
|
||||
{
|
||||
addressdata.deref_mut().tx_count += tx_count;
|
||||
} else if let Some(addressdata) = addresstype_to_typeindex_to_emptyaddressdata
|
||||
.get_mut_unwrap(address_type)
|
||||
.get_mut(&typeindex)
|
||||
{
|
||||
addressdata.deref_mut().tx_count += tx_count;
|
||||
}
|
||||
}
|
||||
|
||||
thread::scope(|scope| {
|
||||
scope.spawn(|| {
|
||||
addresstype_to_typedindex_to_received_data.process_received(
|
||||
@@ -1331,7 +1391,7 @@ impl Vecs {
|
||||
starting_indexes.height,
|
||||
&self
|
||||
.addresstype_to_height_to_addr_count
|
||||
.iter_typed()
|
||||
.iter()
|
||||
.map(|(_, v)| v)
|
||||
.collect::<Vec<_>>(),
|
||||
exit,
|
||||
@@ -1345,7 +1405,7 @@ impl Vecs {
|
||||
starting_indexes.height,
|
||||
&self
|
||||
.addresstype_to_height_to_empty_addr_count
|
||||
.iter_typed()
|
||||
.iter()
|
||||
.map(|(_, v)| v)
|
||||
.collect::<Vec<_>>(),
|
||||
exit,
|
||||
@@ -1562,10 +1622,10 @@ impl Vecs {
|
||||
self.height_to_unspendable_supply.safe_flush(exit)?;
|
||||
self.height_to_opreturn_supply.safe_flush(exit)?;
|
||||
self.addresstype_to_height_to_addr_count
|
||||
.iter_mut()
|
||||
.values_mut()
|
||||
.try_for_each(|v| v.safe_flush(exit))?;
|
||||
self.addresstype_to_height_to_empty_addr_count
|
||||
.iter_mut()
|
||||
.values_mut()
|
||||
.try_for_each(|v| v.safe_flush(exit))?;
|
||||
|
||||
let mut addresstype_to_typeindex_to_new_or_updated_anyaddressindex =
|
||||
@@ -1713,7 +1773,7 @@ impl AddressTypeToVec<(TypeIndex, Sats)> {
|
||||
WithAddressDataSource<LoadedAddressData>,
|
||||
>,
|
||||
) {
|
||||
self.unwrap().into_iter_typed().for_each(|(_type, vec)| {
|
||||
self.unwrap().into_iter().for_each(|(_type, vec)| {
|
||||
vec.into_iter().for_each(|(type_index, value)| {
|
||||
let mut is_new = false;
|
||||
let mut from_any_empty = false;
|
||||
@@ -1832,7 +1892,7 @@ impl HeightToAddressTypeToVec<(TypeIndex, Sats)> {
|
||||
.unwrap()
|
||||
.is_more_than_hour();
|
||||
|
||||
v.unwrap().into_iter_typed().try_for_each(|(_type, vec)| {
|
||||
v.unwrap().into_iter().try_for_each(|(_type, vec)| {
|
||||
vec.into_iter().try_for_each(|(type_index, value)| {
|
||||
let typeindex_to_loadedaddressdata =
|
||||
addresstype_to_typeindex_to_loadedaddressdata.get_mut_unwrap(_type);
|
||||
|
||||
@@ -3,13 +3,17 @@ use std::{cmp::Ordering, path::Path};
|
||||
use brk_error::Result;
|
||||
use brk_types::{CheckedSub, Dollars, Height, Sats};
|
||||
|
||||
use crate::{PriceToAmount, RealizedState, SupplyState, UnrealizedState};
|
||||
use crate::{
|
||||
grouped::{PERCENTILES, PERCENTILES_LEN},
|
||||
PriceToAmount, RealizedState, SupplyState, UnrealizedState,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CohortState {
|
||||
pub supply: SupplyState,
|
||||
|
||||
pub realized: Option<RealizedState>,
|
||||
pub sent: Sats,
|
||||
pub satblocks_destroyed: Sats,
|
||||
pub satdays_destroyed: Sats,
|
||||
|
||||
@@ -21,6 +25,7 @@ impl CohortState {
|
||||
Self {
|
||||
supply: SupplyState::default(),
|
||||
realized: compute_dollars.then_some(RealizedState::NAN),
|
||||
sent: Sats::ZERO,
|
||||
satblocks_destroyed: Sats::ZERO,
|
||||
satdays_destroyed: Sats::ZERO,
|
||||
price_to_amount: compute_dollars.then_some(PriceToAmount::create(path, name)),
|
||||
@@ -52,6 +57,7 @@ impl CohortState {
|
||||
}
|
||||
|
||||
pub fn reset_single_iteration_values(&mut self) {
|
||||
self.sent = Sats::ZERO;
|
||||
self.satdays_destroyed = Sats::ZERO;
|
||||
self.satblocks_destroyed = Sats::ZERO;
|
||||
if let Some(realized) = self.realized.as_mut() {
|
||||
@@ -211,8 +217,8 @@ impl CohortState {
|
||||
self.supply -= supply_state;
|
||||
|
||||
if supply_state.value > Sats::ZERO {
|
||||
self.sent += supply_state.value;
|
||||
self.satblocks_destroyed += supply_state.value * blocks_old;
|
||||
|
||||
self.satdays_destroyed +=
|
||||
Sats::from((u64::from(supply_state.value) as f64 * days_old).floor() as u64);
|
||||
|
||||
@@ -240,6 +246,42 @@ impl CohortState {
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes prices at PERCENTILES in a single pass.
|
||||
/// Returns an array of prices corresponding to each percentile.
|
||||
pub fn compute_percentile_prices(&self) -> [Dollars; PERCENTILES_LEN] {
|
||||
let mut result = [Dollars::NAN; PERCENTILES_LEN];
|
||||
|
||||
let price_to_amount = match self.price_to_amount.as_ref() {
|
||||
Some(p) => p,
|
||||
None => return result,
|
||||
};
|
||||
|
||||
if price_to_amount.is_empty() || self.supply.value == Sats::ZERO {
|
||||
return result;
|
||||
}
|
||||
|
||||
let total = u64::from(self.supply.value);
|
||||
let targets = PERCENTILES.map(|p| total * u64::from(p) / 100);
|
||||
|
||||
let mut accumulated = 0u64;
|
||||
let mut pct_idx = 0;
|
||||
|
||||
for (&price, &sats) in price_to_amount.iter() {
|
||||
accumulated += u64::from(sats);
|
||||
|
||||
while pct_idx < PERCENTILES_LEN && accumulated >= targets[pct_idx] {
|
||||
result[pct_idx] = price;
|
||||
pct_idx += 1;
|
||||
}
|
||||
|
||||
if pct_idx >= PERCENTILES_LEN {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn compute_unrealized_states(
|
||||
&self,
|
||||
height_price: Dollars,
|
||||
|
||||
@@ -103,7 +103,7 @@ impl<T> ByAddressType<T> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn iter(&self) -> impl Iterator<Item = &T> {
|
||||
pub fn values(&self) -> impl Iterator<Item = &T> {
|
||||
[
|
||||
&self.p2pk65,
|
||||
&self.p2pk33,
|
||||
@@ -118,7 +118,7 @@ impl<T> ByAddressType<T> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
|
||||
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut T> {
|
||||
[
|
||||
&mut self.p2pk65,
|
||||
&mut self.p2pk33,
|
||||
@@ -133,7 +133,7 @@ impl<T> ByAddressType<T> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn par_iter(&mut self) -> impl ParallelIterator<Item = &T>
|
||||
pub fn par_values(&mut self) -> impl ParallelIterator<Item = &T>
|
||||
where
|
||||
T: Send + Sync,
|
||||
{
|
||||
@@ -151,7 +151,7 @@ impl<T> ByAddressType<T> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn par_iter_mut(&mut self) -> impl ParallelIterator<Item = &mut T>
|
||||
pub fn par_values_mut(&mut self) -> impl ParallelIterator<Item = &mut T>
|
||||
where
|
||||
T: Send + Sync,
|
||||
{
|
||||
@@ -169,7 +169,7 @@ impl<T> ByAddressType<T> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn iter_typed(&self) -> impl Iterator<Item = (OutputType, &T)> {
|
||||
pub fn iter(&self) -> impl Iterator<Item = (OutputType, &T)> {
|
||||
[
|
||||
(OutputType::P2PK65, &self.p2pk65),
|
||||
(OutputType::P2PK33, &self.p2pk33),
|
||||
@@ -184,7 +184,8 @@ impl<T> ByAddressType<T> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn into_iter_typed(self) -> impl Iterator<Item = (OutputType, T)> {
|
||||
#[allow(clippy::should_implement_trait)]
|
||||
pub fn into_iter(self) -> impl Iterator<Item = (OutputType, T)> {
|
||||
[
|
||||
(OutputType::P2PK65, self.p2pk65),
|
||||
(OutputType::P2PK33, self.p2pk33),
|
||||
@@ -199,7 +200,7 @@ impl<T> ByAddressType<T> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn iter_typed_mut(&mut self) -> impl Iterator<Item = (OutputType, &mut T)> {
|
||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = (OutputType, &mut T)> {
|
||||
[
|
||||
(OutputType::P2PK65, &mut self.p2pk65),
|
||||
(OutputType::P2PK33, &mut self.p2pk33),
|
||||
@@ -283,7 +284,7 @@ where
|
||||
|
||||
impl<T> ByAddressType<Option<T>> {
|
||||
pub fn take(&mut self) {
|
||||
self.iter_mut().for_each(|opt| {
|
||||
self.values_mut().for_each(|opt| {
|
||||
opt.take();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -127,17 +127,17 @@ impl Stores {
|
||||
.into_iter()
|
||||
.chain(
|
||||
self.addresstype_to_addresshash_to_addressindex
|
||||
.iter()
|
||||
.values()
|
||||
.map(|s| s as &dyn AnyStore),
|
||||
)
|
||||
.chain(
|
||||
self.addresstype_to_addressindex_and_txindex
|
||||
.iter()
|
||||
.values()
|
||||
.map(|s| s as &dyn AnyStore),
|
||||
)
|
||||
.chain(
|
||||
self.addresstype_to_addressindex_and_unspentoutpoint
|
||||
.iter()
|
||||
.values()
|
||||
.map(|s| s as &dyn AnyStore),
|
||||
)
|
||||
.map(|store| {
|
||||
@@ -158,17 +158,17 @@ impl Stores {
|
||||
.into_par_iter()
|
||||
.chain(
|
||||
self.addresstype_to_addresshash_to_addressindex
|
||||
.par_iter_mut()
|
||||
.par_values_mut()
|
||||
.map(|s| s as &mut dyn AnyStore),
|
||||
)
|
||||
.chain(
|
||||
self.addresstype_to_addressindex_and_txindex
|
||||
.par_iter_mut()
|
||||
.par_values_mut()
|
||||
.map(|s| s as &mut dyn AnyStore),
|
||||
)
|
||||
.chain(
|
||||
self.addresstype_to_addressindex_and_unspentoutpoint
|
||||
.par_iter_mut()
|
||||
.par_values_mut()
|
||||
.map(|s| s as &mut dyn AnyStore),
|
||||
) // Changed from par_iter_mut()
|
||||
.map(|store| {
|
||||
@@ -195,15 +195,15 @@ impl Stores {
|
||||
&& self.height_to_coinbase_tag.is_empty()?
|
||||
&& self
|
||||
.addresstype_to_addresshash_to_addressindex
|
||||
.iter()
|
||||
.values()
|
||||
.try_fold(true, |acc, s| s.is_empty().map(|empty| acc && empty))?
|
||||
&& self
|
||||
.addresstype_to_addressindex_and_txindex
|
||||
.iter()
|
||||
.values()
|
||||
.try_fold(true, |acc, s| s.is_empty().map(|empty| acc && empty))?
|
||||
&& self
|
||||
.addresstype_to_addressindex_and_unspentoutpoint
|
||||
.iter()
|
||||
.values()
|
||||
.try_fold(true, |acc, s| s.is_empty().map(|empty| acc && empty))?
|
||||
{
|
||||
return Ok(());
|
||||
|
||||
@@ -32,4 +32,4 @@ serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
tower-http = { version = "0.6.7", features = ["compression-full", "trace"] }
|
||||
tracing = "0.1.41"
|
||||
tracing = "0.1.43"
|
||||
|
||||
Reference in New Issue
Block a user