mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-05-17 05:14:49 -07:00
global: utxos part 7
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
use std::ops::{Add, AddAssign, SubAssign};
|
||||
|
||||
use brk_core::{Dollars, Sats, Timestamp};
|
||||
use brk_core::{Dollars, Timestamp};
|
||||
|
||||
use super::{OutputsByType, SupplyState};
|
||||
use super::SupplyState;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BlockState {
|
||||
@@ -30,33 +30,3 @@ impl SubAssign<&BlockState> for BlockState {
|
||||
self.supply -= &rhs.supply;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ReceivedBlockStateData<'a> {
|
||||
pub received: &'a OutputsByType<(SupplyState, Vec<Sats>)>,
|
||||
pub timestamp: Timestamp,
|
||||
pub price: Option<Dollars>,
|
||||
}
|
||||
impl<'a> From<ReceivedBlockStateData<'a>> for BlockState {
|
||||
fn from(
|
||||
ReceivedBlockStateData {
|
||||
received,
|
||||
timestamp,
|
||||
price,
|
||||
}: ReceivedBlockStateData<'a>,
|
||||
) -> Self {
|
||||
let mut block_state = BlockState {
|
||||
supply: SupplyState::default(),
|
||||
price,
|
||||
timestamp,
|
||||
};
|
||||
received
|
||||
.spendable
|
||||
.as_vec()
|
||||
.into_iter()
|
||||
.for_each(|spendable_block_state| {
|
||||
block_state.supply += &spendable_block_state.0;
|
||||
});
|
||||
block_state.supply.utxos += received.unspendable.empty.0.utxos;
|
||||
block_state
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,27 @@
|
||||
use brk_core::{Bitcoin, CheckedSub, Dollars};
|
||||
use brk_core::Dollars;
|
||||
|
||||
use super::SupplyState;
|
||||
use super::{RealizedState, SupplyState};
|
||||
|
||||
// Vecs ? probably
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct CohortState {
|
||||
pub supply: SupplyState,
|
||||
pub realized_cap: Option<Dollars>,
|
||||
pub realized: Option<RealizedState>,
|
||||
// pub price_to_amount: PriceToValue<Amount>, save it not rounded in fjall
|
||||
}
|
||||
|
||||
impl CohortState {
|
||||
pub fn increment(&mut self, supply_state: &SupplyState, price: Option<Dollars>) {
|
||||
self.supply += supply_state;
|
||||
if let Some(realized_cap) = self.realized_cap.as_mut() {
|
||||
*realized_cap += price.unwrap() * Bitcoin::from(supply_state.value);
|
||||
if let Some(realized) = self.realized.as_mut() {
|
||||
realized.increment(supply_state, price.unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decrement(&mut self, supply_state: &SupplyState, price: Option<Dollars>) {
|
||||
if let Some(realized_cap) = self.realized_cap.as_mut() {
|
||||
*realized_cap = realized_cap
|
||||
.checked_sub(price.unwrap() * Bitcoin::from(supply_state.value))
|
||||
.unwrap();
|
||||
}
|
||||
self.supply -= supply_state;
|
||||
if let Some(realized) = self.realized.as_mut() {
|
||||
realized.decrement(supply_state, price.unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
mod block;
|
||||
mod cohort;
|
||||
mod outputs;
|
||||
// mod realized;
|
||||
mod realized;
|
||||
// mod hot;
|
||||
mod supply;
|
||||
mod transacted;
|
||||
|
||||
pub use block::*;
|
||||
pub use cohort::*;
|
||||
pub use outputs::*;
|
||||
// pub use realized::*;
|
||||
pub use realized::*;
|
||||
// pub use hot::*;
|
||||
pub use supply::*;
|
||||
pub use transacted::*;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use brk_core::Sats;
|
||||
|
||||
use super::OutputFilter;
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct OutputsBySize<T> {
|
||||
pub _0sat: T,
|
||||
pub from_1sat_to_10sats: T,
|
||||
pub from_10sats_to_100sats: T,
|
||||
pub from_100sats_to_1_000sats: T,
|
||||
@@ -24,60 +23,79 @@ impl<T> From<OutputsBySize<T>> for OutputsBySize<(OutputFilter, T)> {
|
||||
fn from(value: OutputsBySize<T>) -> Self {
|
||||
#[allow(clippy::inconsistent_digit_grouping)]
|
||||
Self {
|
||||
_0sat: (
|
||||
// OutputFilter::Zero,
|
||||
OutputFilter::Size,
|
||||
value._0sat,
|
||||
),
|
||||
from_1sat_to_10sats: (
|
||||
OutputFilter::Size(Sats::new(1)..Sats::new(10)),
|
||||
// OutputFilter::Size(Sats::new(1)..Sats::new(10)),
|
||||
OutputFilter::Size,
|
||||
value.from_1sat_to_10sats,
|
||||
),
|
||||
from_10sats_to_100sats: (
|
||||
OutputFilter::Size(Sats::new(10)..Sats::new(100)),
|
||||
// OutputFilter::Size(Sats::new(10)..Sats::new(100)),
|
||||
OutputFilter::Size,
|
||||
value.from_10sats_to_100sats,
|
||||
),
|
||||
from_100sats_to_1_000sats: (
|
||||
OutputFilter::Size(Sats::new(100)..Sats::new(1_000)),
|
||||
// OutputFilter::Size(Sats::new(100)..Sats::new(1_000)),
|
||||
OutputFilter::Size,
|
||||
value.from_100sats_to_1_000sats,
|
||||
),
|
||||
from_1_000sats_to_10_000sats: (
|
||||
OutputFilter::Size(Sats::new(1_000)..Sats::new(10_000)),
|
||||
// OutputFilter::Size(Sats::new(1_000)..Sats::new(10_000)),
|
||||
OutputFilter::Size,
|
||||
value.from_1_000sats_to_10_000sats,
|
||||
),
|
||||
from_10_000sats_to_100_000sats: (
|
||||
OutputFilter::Size(Sats::new(10_000)..Sats::new(100_000)),
|
||||
// OutputFilter::Size(Sats::new(10_000)..Sats::new(100_000)),
|
||||
OutputFilter::Size,
|
||||
value.from_10_000sats_to_100_000sats,
|
||||
),
|
||||
from_100_000sats_to_1_000_000sats: (
|
||||
OutputFilter::Size(Sats::new(100_000)..Sats::new(1_000_000)),
|
||||
// OutputFilter::Size(Sats::new(100_000)..Sats::new(1_000_000)),
|
||||
OutputFilter::Size,
|
||||
value.from_100_000sats_to_1_000_000sats,
|
||||
),
|
||||
from_1_000_000sats_to_10_000_000sats: (
|
||||
OutputFilter::Size(Sats::new(1_000_000)..Sats::new(10_000_000)),
|
||||
// OutputFilter::Size(Sats::new(1_000_000)..Sats::new(10_000_000)),
|
||||
OutputFilter::Size,
|
||||
value.from_1_000_000sats_to_10_000_000sats,
|
||||
),
|
||||
from_10_000_000sats_to_1btc: (
|
||||
OutputFilter::Size(Sats::new(10_000_000)..Sats::new(1_00_000_000)),
|
||||
// OutputFilter::Size(Sats::new(10_000_000)..Sats::new(1_00_000_000)),
|
||||
OutputFilter::Size,
|
||||
value.from_10_000_000sats_to_1btc,
|
||||
),
|
||||
from_1btc_to_10btc: (
|
||||
OutputFilter::Size(Sats::new(1_00_000_000)..Sats::new(10_00_000_000)),
|
||||
// OutputFilter::Size(Sats::new(1_00_000_000)..Sats::new(10_00_000_000)),
|
||||
OutputFilter::Size,
|
||||
value.from_1btc_to_10btc,
|
||||
),
|
||||
from_10btc_to_100btc: (
|
||||
OutputFilter::Size(Sats::new(10_00_000_000)..Sats::new(100_00_000_000)),
|
||||
// OutputFilter::Size(Sats::new(10_00_000_000)..Sats::new(100_00_000_000)),
|
||||
OutputFilter::Size,
|
||||
value.from_10btc_to_100btc,
|
||||
),
|
||||
from_100btc_to_1_000btc: (
|
||||
OutputFilter::Size(Sats::new(100_00_000_000)..Sats::new(1_000_00_000_000)),
|
||||
// OutputFilter::Size(Sats::new(100_00_000_000)..Sats::new(1_000_00_000_000)),
|
||||
OutputFilter::Size,
|
||||
value.from_100btc_to_1_000btc,
|
||||
),
|
||||
from_1_000btc_to_10_000btc: (
|
||||
OutputFilter::Size(Sats::new(1_000_00_000_000)..Sats::new(10_000_00_000_000)),
|
||||
// OutputFilter::Size(Sats::new(1_000_00_000_000)..Sats::new(10_000_00_000_000)),
|
||||
OutputFilter::Size,
|
||||
value.from_1_000btc_to_10_000btc,
|
||||
),
|
||||
from_10_000btc_to_100_000btc: (
|
||||
OutputFilter::Size(Sats::new(10_000_00_000_000)..Sats::new(100_000_00_000_000)),
|
||||
// OutputFilter::Size(Sats::new(10_000_00_000_000)..Sats::new(100_000_00_000_000)),
|
||||
OutputFilter::Size,
|
||||
value.from_10_000btc_to_100_000btc,
|
||||
),
|
||||
from_100_000btc: (
|
||||
OutputFilter::Size(Sats::new(100_000_00_000_000)..Sats::MAX),
|
||||
// OutputFilter::Size(Sats::new(100_000_00_000_000)..Sats::MAX),
|
||||
OutputFilter::Size,
|
||||
value.from_100_000btc,
|
||||
),
|
||||
}
|
||||
@@ -85,8 +103,44 @@ impl<T> From<OutputsBySize<T>> for OutputsBySize<(OutputFilter, T)> {
|
||||
}
|
||||
|
||||
impl<T> OutputsBySize<T> {
|
||||
pub fn as_mut_vec(&mut self) -> [&mut T; 14] {
|
||||
#[allow(clippy::inconsistent_digit_grouping)]
|
||||
pub fn get_mut(&mut self, group: usize) -> &mut T {
|
||||
if group == 0 {
|
||||
&mut self._0sat
|
||||
} else if group == 10 {
|
||||
&mut self.from_1sat_to_10sats
|
||||
} else if group == 100 {
|
||||
&mut self.from_10sats_to_100sats
|
||||
} else if group == 1_000 {
|
||||
&mut self.from_100sats_to_1_000sats
|
||||
} else if group == 10_000 {
|
||||
&mut self.from_1_000sats_to_10_000sats
|
||||
} else if group == 100_000 {
|
||||
&mut self.from_10_000sats_to_100_000sats
|
||||
} else if group == 1_000_000 {
|
||||
&mut self.from_100_000sats_to_1_000_000sats
|
||||
} else if group == 10_000_000 {
|
||||
&mut self.from_1_000_000sats_to_10_000_000sats
|
||||
} else if group == 1_00_000_000 {
|
||||
&mut self.from_10_000_000sats_to_1btc
|
||||
} else if group == 10_00_000_000 {
|
||||
&mut self.from_1btc_to_10btc
|
||||
} else if group == 100_00_000_000 {
|
||||
&mut self.from_10btc_to_100btc
|
||||
} else if group == 1_000_00_000_000 {
|
||||
&mut self.from_100btc_to_1_000btc
|
||||
} else if group == 10_000_00_000_000 {
|
||||
&mut self.from_1_000btc_to_10_000btc
|
||||
} else if group == 100_000_00_000_000 {
|
||||
&mut self.from_10_000btc_to_100_000btc
|
||||
} else {
|
||||
&mut self.from_100_000btc
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_mut_vec(&mut self) -> [&mut T; 15] {
|
||||
[
|
||||
&mut self._0sat,
|
||||
&mut self.from_1sat_to_10sats,
|
||||
&mut self.from_10sats_to_100sats,
|
||||
&mut self.from_100sats_to_1_000sats,
|
||||
@@ -106,8 +160,9 @@ impl<T> OutputsBySize<T> {
|
||||
}
|
||||
|
||||
impl<T> OutputsBySize<(OutputFilter, T)> {
|
||||
pub fn vecs(&self) -> [&T; 14] {
|
||||
pub fn vecs(&self) -> [&T; 15] {
|
||||
[
|
||||
&self._0sat.1,
|
||||
&self.from_1sat_to_10sats.1,
|
||||
&self.from_10sats_to_100sats.1,
|
||||
&self.from_100sats_to_1_000sats.1,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_core::{OutputType, Sats};
|
||||
use std::ops::{Add, AddAssign};
|
||||
|
||||
use crate::states::SupplyState;
|
||||
use brk_core::OutputType;
|
||||
|
||||
use super::OutputFilter;
|
||||
|
||||
@@ -16,24 +16,26 @@ pub struct OutputsBySpendableType<T> {
|
||||
pub p2tr: T,
|
||||
pub p2a: T,
|
||||
pub unknown: T,
|
||||
pub empty: T,
|
||||
}
|
||||
|
||||
impl<T> OutputsBySpendableType<T> {
|
||||
pub fn get(&self, output_type: OutputType) -> &T {
|
||||
match output_type {
|
||||
OutputType::P2PK65 => &self.p2pk65,
|
||||
OutputType::P2PK33 => &self.p2pk33,
|
||||
OutputType::P2PKH => &self.p2pkh,
|
||||
OutputType::P2MS => &self.p2ms,
|
||||
OutputType::P2SH => &self.p2sh,
|
||||
OutputType::P2WPKH => &self.p2wpkh,
|
||||
OutputType::P2WSH => &self.p2wsh,
|
||||
OutputType::P2TR => &self.p2tr,
|
||||
OutputType::P2A => &self.p2a,
|
||||
OutputType::Unknown => &self.unknown,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
// pub fn get(&self, output_type: OutputType) -> &T {
|
||||
// match output_type {
|
||||
// OutputType::P2PK65 => &self.p2pk65,
|
||||
// OutputType::P2PK33 => &self.p2pk33,
|
||||
// OutputType::P2PKH => &self.p2pkh,
|
||||
// OutputType::P2MS => &self.p2ms,
|
||||
// OutputType::P2SH => &self.p2sh,
|
||||
// OutputType::P2WPKH => &self.p2wpkh,
|
||||
// OutputType::P2WSH => &self.p2wsh,
|
||||
// OutputType::P2TR => &self.p2tr,
|
||||
// OutputType::P2A => &self.p2a,
|
||||
// OutputType::Unknown => &self.unknown,
|
||||
// OutputType::Empty => &self.empty,
|
||||
// _ => unreachable!(),
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn get_mut(&mut self, output_type: OutputType) -> &mut T {
|
||||
match output_type {
|
||||
@@ -47,26 +49,28 @@ impl<T> OutputsBySpendableType<T> {
|
||||
OutputType::P2TR => &mut self.p2tr,
|
||||
OutputType::P2A => &mut self.p2a,
|
||||
OutputType::Unknown => &mut self.unknown,
|
||||
OutputType::Empty => &mut self.empty,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vec(&self) -> [&T; 10] {
|
||||
[
|
||||
&self.p2pk65,
|
||||
&self.p2pk33,
|
||||
&self.p2pkh,
|
||||
&self.p2ms,
|
||||
&self.p2sh,
|
||||
&self.p2wpkh,
|
||||
&self.p2wsh,
|
||||
&self.p2tr,
|
||||
&self.p2a,
|
||||
&self.unknown,
|
||||
]
|
||||
}
|
||||
// pub fn as_vec(&self) -> [&T; 11] {
|
||||
// [
|
||||
// &self.p2pk65,
|
||||
// &self.p2pk33,
|
||||
// &self.p2pkh,
|
||||
// &self.p2ms,
|
||||
// &self.p2sh,
|
||||
// &self.p2wpkh,
|
||||
// &self.p2wsh,
|
||||
// &self.p2tr,
|
||||
// &self.p2a,
|
||||
// &self.unknown,
|
||||
// &self.empty,
|
||||
// ]
|
||||
// }
|
||||
|
||||
pub fn as_mut_vec(&mut self) -> [&mut T; 10] {
|
||||
pub fn as_mut_vec(&mut self) -> [&mut T; 11] {
|
||||
[
|
||||
&mut self.p2pk65,
|
||||
&mut self.p2pk33,
|
||||
@@ -78,10 +82,11 @@ impl<T> OutputsBySpendableType<T> {
|
||||
&mut self.p2tr,
|
||||
&mut self.p2a,
|
||||
&mut self.unknown,
|
||||
&mut self.empty,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn as_typed_vec(&self) -> [(OutputType, &T); 10] {
|
||||
pub fn as_typed_vec(&self) -> [(OutputType, &T); 11] {
|
||||
[
|
||||
(OutputType::P2PK65, &self.p2pk65),
|
||||
(OutputType::P2PK33, &self.p2pk33),
|
||||
@@ -93,12 +98,13 @@ impl<T> OutputsBySpendableType<T> {
|
||||
(OutputType::P2TR, &self.p2tr),
|
||||
(OutputType::P2A, &self.p2a),
|
||||
(OutputType::Unknown, &self.unknown),
|
||||
(OutputType::Empty, &self.empty),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> OutputsBySpendableType<(OutputFilter, T)> {
|
||||
pub fn vecs(&self) -> [&T; 10] {
|
||||
pub fn vecs(&self) -> [&T; 11] {
|
||||
[
|
||||
&self.p2pk65.1,
|
||||
&self.p2pk33.1,
|
||||
@@ -110,6 +116,7 @@ impl<T> OutputsBySpendableType<(OutputFilter, T)> {
|
||||
&self.p2tr.1,
|
||||
&self.p2a.1,
|
||||
&self.unknown.1,
|
||||
&self.empty.1,
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -127,16 +134,48 @@ impl<T> From<OutputsBySpendableType<T>> for OutputsBySpendableType<(OutputFilter
|
||||
p2tr: (OutputFilter::Type(OutputType::P2TR), value.p2tr),
|
||||
p2a: (OutputFilter::Type(OutputType::P2A), value.p2a),
|
||||
unknown: (OutputFilter::Type(OutputType::Unknown), value.unknown),
|
||||
empty: (OutputFilter::Type(OutputType::Empty), value.empty),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OutputsBySpendableType<(SupplyState, Vec<Sats>)> {
|
||||
pub fn reduce(&self) -> SupplyState {
|
||||
let mut supply_state = SupplyState::default();
|
||||
self.as_vec().iter().for_each(|(supply_state_, _)| {
|
||||
supply_state += supply_state_;
|
||||
});
|
||||
supply_state
|
||||
impl<T> Add for OutputsBySpendableType<T>
|
||||
where
|
||||
T: Add<Output = T>,
|
||||
{
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self {
|
||||
p2pk65: self.p2pk65 + rhs.p2pk65,
|
||||
p2pk33: self.p2pk33 + rhs.p2pk33,
|
||||
p2pkh: self.p2pkh + rhs.p2pkh,
|
||||
p2ms: self.p2ms + rhs.p2ms,
|
||||
p2sh: self.p2sh + rhs.p2sh,
|
||||
p2wpkh: self.p2wpkh + rhs.p2wpkh,
|
||||
p2wsh: self.p2wsh + rhs.p2wsh,
|
||||
p2tr: self.p2tr + rhs.p2tr,
|
||||
p2a: self.p2a + rhs.p2a,
|
||||
unknown: self.unknown + rhs.unknown,
|
||||
empty: self.empty + rhs.empty,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AddAssign for OutputsBySpendableType<T>
|
||||
where
|
||||
T: AddAssign,
|
||||
{
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.p2pk65 += rhs.p2pk65;
|
||||
self.p2pk33 += rhs.p2pk33;
|
||||
self.p2pkh += rhs.p2pkh;
|
||||
self.p2ms += rhs.p2ms;
|
||||
self.p2sh += rhs.p2sh;
|
||||
self.p2wpkh += rhs.p2wpkh;
|
||||
self.p2wsh += rhs.p2wsh;
|
||||
self.p2tr += rhs.p2tr;
|
||||
self.p2a += rhs.p2a;
|
||||
self.unknown += rhs.unknown;
|
||||
self.empty += rhs.empty;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::ops::{Add, AddAssign};
|
||||
|
||||
use brk_core::OutputType;
|
||||
|
||||
use super::{OutputsBySpendableType, OutputsByUnspendableType};
|
||||
@@ -9,22 +11,22 @@ pub struct OutputsByType<T> {
|
||||
}
|
||||
|
||||
impl<T> OutputsByType<T> {
|
||||
// pub fn get(&self, output_type: OutputType) -> &T {
|
||||
// match output_type {
|
||||
// OutputType::P2PK65 => &self.spendable.p2pk65,
|
||||
// OutputType::P2PK33 => &self.spendable.p2pk33,
|
||||
// OutputType::P2PKH => &self.spendable.p2pkh,
|
||||
// OutputType::P2MS => &self.spendable.p2ms,
|
||||
// OutputType::P2SH => &self.spendable.p2sh,
|
||||
// OutputType::P2WPKH => &self.spendable.p2wpkh,
|
||||
// OutputType::P2WSH => &self.spendable.p2wsh,
|
||||
// OutputType::P2TR => &self.spendable.p2tr,
|
||||
// OutputType::P2A => &self.spendable.p2a,
|
||||
// OutputType::OpReturn => &self.unspendable.op_return,
|
||||
// OutputType::Empty => &self.unspendable.empty,
|
||||
// OutputType::Unknown => &self.unspendable.unknown,
|
||||
// }
|
||||
// }
|
||||
pub fn get(&self, output_type: OutputType) -> &T {
|
||||
match output_type {
|
||||
OutputType::P2PK65 => &self.spendable.p2pk65,
|
||||
OutputType::P2PK33 => &self.spendable.p2pk33,
|
||||
OutputType::P2PKH => &self.spendable.p2pkh,
|
||||
OutputType::P2MS => &self.spendable.p2ms,
|
||||
OutputType::P2SH => &self.spendable.p2sh,
|
||||
OutputType::P2WPKH => &self.spendable.p2wpkh,
|
||||
OutputType::P2WSH => &self.spendable.p2wsh,
|
||||
OutputType::P2TR => &self.spendable.p2tr,
|
||||
OutputType::P2A => &self.spendable.p2a,
|
||||
OutputType::Empty => &self.spendable.empty,
|
||||
OutputType::Unknown => &self.spendable.unknown,
|
||||
OutputType::OpReturn => &self.unspendable.op_return,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, output_type: OutputType) -> &mut T {
|
||||
match output_type {
|
||||
@@ -38,18 +40,18 @@ impl<T> OutputsByType<T> {
|
||||
OutputType::P2TR => &mut self.spendable.p2tr,
|
||||
OutputType::P2A => &mut self.spendable.p2a,
|
||||
OutputType::Unknown => &mut self.spendable.unknown,
|
||||
OutputType::Empty => &mut self.spendable.empty,
|
||||
OutputType::OpReturn => &mut self.unspendable.op_return,
|
||||
OutputType::Empty => &mut self.unspendable.empty,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vec(&self) -> Vec<&T> {
|
||||
self.spendable
|
||||
.as_vec()
|
||||
.into_iter()
|
||||
.chain(self.unspendable.as_vec())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
// pub fn as_vec(&self) -> Vec<&T> {
|
||||
// self.spendable
|
||||
// .as_vec()
|
||||
// .into_iter()
|
||||
// .chain(self.unspendable.as_vec())
|
||||
// .collect::<Vec<_>>()
|
||||
// }
|
||||
|
||||
// pub fn as_mut_vec(&mut self) -> Vec<&mut T> {
|
||||
// self.spendable
|
||||
@@ -59,3 +61,26 @@ impl<T> OutputsByType<T> {
|
||||
// .collect::<Vec<_>>()
|
||||
// }
|
||||
}
|
||||
|
||||
impl<T> Add for OutputsByType<T>
|
||||
where
|
||||
T: Add<Output = T>,
|
||||
{
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self {
|
||||
spendable: self.spendable + rhs.spendable,
|
||||
unspendable: self.unspendable + rhs.unspendable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AddAssign for OutputsByType<T>
|
||||
where
|
||||
T: AddAssign,
|
||||
{
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.spendable += rhs.spendable;
|
||||
self.unspendable += rhs.unspendable;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,47 +1,33 @@
|
||||
// use brk_core::OutputType;
|
||||
use std::ops::{Add, AddAssign};
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct OutputsByUnspendableType<T> {
|
||||
pub op_return: T,
|
||||
pub empty: T,
|
||||
// pub unknown: T,
|
||||
}
|
||||
|
||||
impl<T> OutputsByUnspendableType<T> {
|
||||
// pub fn get(&self, output_type: OutputType) -> &T {
|
||||
// match output_type {
|
||||
// OutputType::OpReturn => &self.op_return,
|
||||
// OutputType::Empty => &self.empty,
|
||||
// OutputType::Unknown => &self.unknown,
|
||||
// _ => unreachable!(),
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub fn get_mut(&mut self, output_type: OutputType) -> &mut T {
|
||||
// match output_type {
|
||||
// OutputType::OpReturn => &mut self.op_return,
|
||||
// OutputType::Empty => &mut self.empty,
|
||||
// OutputType::Unknown => &mut self.unknown,
|
||||
// _ => unreachable!(),
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub fn to_unspendable_vec(&self) -> Vec<&T> {
|
||||
// OutputType::as_vec()
|
||||
// .into_iter()
|
||||
// .map(|t| (self.get(t)))
|
||||
// .collect::<Vec<_>>()
|
||||
// }
|
||||
|
||||
pub fn as_vec(&self) -> [&T; 2] {
|
||||
[
|
||||
&self.op_return,
|
||||
&self.empty,
|
||||
// &self.unknown
|
||||
]
|
||||
pub fn as_vec(&self) -> [&T; 1] {
|
||||
[&self.op_return]
|
||||
}
|
||||
}
|
||||
|
||||
// pub fn as_mut_vec(&mut self) -> [&mut T; 3] {
|
||||
// [&mut self.op_return, &mut self.empty, &mut self.unknown]
|
||||
// }
|
||||
impl<T> Add for OutputsByUnspendableType<T>
|
||||
where
|
||||
T: Add<Output = T>,
|
||||
{
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self {
|
||||
op_return: self.op_return + rhs.op_return,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AddAssign for OutputsByUnspendableType<T>
|
||||
where
|
||||
T: AddAssign,
|
||||
{
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.op_return += rhs.op_return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::ops::Range;
|
||||
|
||||
use brk_core::{HalvingEpoch, OutputType, Sats};
|
||||
use brk_core::{HalvingEpoch, OutputType};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum OutputFilter {
|
||||
@@ -8,7 +8,7 @@ pub enum OutputFilter {
|
||||
To(usize),
|
||||
Range(Range<usize>),
|
||||
From(usize),
|
||||
Size(Range<Sats>),
|
||||
Size,
|
||||
Epoch(HalvingEpoch),
|
||||
Type(OutputType),
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use brk_vec::StoredIndex;
|
||||
use rayon::prelude::*;
|
||||
use std::{collections::BTreeMap, ops::ControlFlow};
|
||||
|
||||
use brk_core::{Dollars, HalvingEpoch, Height, Sats, Timestamp};
|
||||
use brk_core::{Dollars, HalvingEpoch, Height, Timestamp};
|
||||
|
||||
mod by_epoch;
|
||||
mod by_from;
|
||||
@@ -30,7 +30,7 @@ pub use filter::*;
|
||||
|
||||
use crate::vecs;
|
||||
|
||||
use super::{BlockState, SupplyState};
|
||||
use super::{BlockState, Transacted};
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct Outputs<T> {
|
||||
@@ -38,12 +38,12 @@ pub struct Outputs<T> {
|
||||
pub by_term: OutputsByTerm<T>,
|
||||
// pub by_up_to: OutputsByUpTo<T>,
|
||||
pub by_from: OutputsByFrom<T>,
|
||||
// pub by_range: OutputsByRange<T>,
|
||||
pub by_range: OutputsByRange<T>,
|
||||
pub by_epoch: OutputsByEpoch<T>,
|
||||
pub by_type: OutputsBySpendableType<T>,
|
||||
pub by_size: OutputsBySize<T>,
|
||||
// // Needs whole UTXO set, TODO later
|
||||
// // pub by_value: OutputsByValue<T>,
|
||||
pub by_spendable_type: OutputsBySpendableType<T>,
|
||||
}
|
||||
|
||||
impl<T> Outputs<T> {
|
||||
@@ -53,11 +53,11 @@ impl<T> Outputs<T> {
|
||||
.chain(self.by_term.as_mut_vec())
|
||||
// .chain(self.by_up_to.as_mut_vec())
|
||||
.chain(self.by_from.as_mut_vec())
|
||||
// .chain(self.by_range.as_mut_vec())
|
||||
.chain(self.by_range.as_mut_vec())
|
||||
.chain(self.by_epoch.as_mut_vec())
|
||||
.chain(self.by_size.as_mut_vec())
|
||||
.chain(self.by_type.as_mut_vec())
|
||||
// // .chain(self.by_value.as_mut_vec())
|
||||
.chain(self.by_spendable_type.as_mut_vec())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ impl Outputs<(OutputFilter, vecs::utxos::cohort::Vecs)> {
|
||||
.into_par_iter()
|
||||
// .chain(self.by_up_to.as_mut_vec())
|
||||
.chain(self.by_from.as_mut_vec())
|
||||
// .chain(self.by_range.as_mut_vec())
|
||||
.chain(self.by_range.as_mut_vec())
|
||||
.for_each(|(filter, v)| {
|
||||
let state = &mut v.state;
|
||||
|
||||
@@ -86,7 +86,7 @@ impl Outputs<(OutputFilter, vecs::utxos::cohort::Vecs)> {
|
||||
OutputFilter::Range(range) => range.contains(&days_old),
|
||||
OutputFilter::All
|
||||
| OutputFilter::Epoch(_)
|
||||
| OutputFilter::Size(_)
|
||||
| OutputFilter::Size
|
||||
| OutputFilter::Type(_) => unreachable!(),
|
||||
}
|
||||
};
|
||||
@@ -98,12 +98,14 @@ impl Outputs<(OutputFilter, vecs::utxos::cohort::Vecs)> {
|
||||
.timestamp
|
||||
.difference_in_days_between(prev_timestamp);
|
||||
let days_old = block_state.timestamp.difference_in_days_between(timestamp);
|
||||
|
||||
if prev_days_old == days_old {
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
let is = check_days_old(days_old);
|
||||
let was = check_days_old(prev_days_old);
|
||||
|
||||
if is && !was {
|
||||
state.increment(&block_state.supply, block_state.price);
|
||||
} else if was && !is {
|
||||
@@ -117,7 +119,7 @@ impl Outputs<(OutputFilter, vecs::utxos::cohort::Vecs)> {
|
||||
|
||||
pub fn send(
|
||||
&mut self,
|
||||
height_to_sent: BTreeMap<Height, OutputsByType<(SupplyState, Vec<Sats>)>>,
|
||||
height_to_sent: BTreeMap<Height, Transacted>,
|
||||
chain_state: &[BlockState],
|
||||
) {
|
||||
let mut time_based_vecs = self
|
||||
@@ -126,58 +128,21 @@ impl Outputs<(OutputFilter, vecs::utxos::cohort::Vecs)> {
|
||||
.into_iter()
|
||||
// .chain(self.by_up_to.as_mut_vec())
|
||||
.chain(self.by_from.as_mut_vec())
|
||||
// .chain(self.by_range.as_mut_vec())
|
||||
.chain(self.by_range.as_mut_vec())
|
||||
.chain(self.by_epoch.as_mut_vec())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let last_timestamp = chain_state.last().unwrap().timestamp;
|
||||
|
||||
height_to_sent.into_iter().for_each(|(height, by_type)| {
|
||||
let by_spendable_type = by_type.spendable;
|
||||
|
||||
height_to_sent.into_iter().for_each(|(height, sent)| {
|
||||
let block_state = chain_state.get(height.unwrap_to_usize()).unwrap();
|
||||
let price = block_state.price;
|
||||
let supply_state = by_spendable_type.reduce();
|
||||
|
||||
let days_old = block_state
|
||||
.timestamp
|
||||
.difference_in_days_between(last_timestamp);
|
||||
|
||||
self.all.1.state.decrement(&supply_state, price);
|
||||
|
||||
by_spendable_type.as_typed_vec().into_iter().for_each(
|
||||
|(output_type, (supply_state, _))| {
|
||||
self.by_spendable_type
|
||||
.get_mut(output_type)
|
||||
.1
|
||||
.state
|
||||
.decrement(supply_state, price)
|
||||
},
|
||||
);
|
||||
|
||||
by_spendable_type
|
||||
.as_vec()
|
||||
.into_iter()
|
||||
.flat_map(|(_, sats_received)| sats_received.iter())
|
||||
.for_each(|sats| {
|
||||
let sats = *sats;
|
||||
self.by_size
|
||||
.as_mut_vec()
|
||||
.iter_mut()
|
||||
.filter(|(filter, _)| match filter {
|
||||
OutputFilter::Size(range) => range.contains(&sats),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.for_each(|(_, vec)| {
|
||||
vec.state.decrement(
|
||||
&SupplyState {
|
||||
utxos: 1,
|
||||
value: sats,
|
||||
},
|
||||
price,
|
||||
);
|
||||
});
|
||||
});
|
||||
self.all.1.state.decrement(&sent.spendable_supply, price);
|
||||
|
||||
time_based_vecs
|
||||
.iter_mut()
|
||||
@@ -189,18 +154,31 @@ impl Outputs<(OutputFilter, vecs::utxos::cohort::Vecs)> {
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.for_each(|(_, vecs)| {
|
||||
vecs.state.decrement(&supply_state, price);
|
||||
vecs.state.decrement(&sent.spendable_supply, price);
|
||||
});
|
||||
|
||||
sent.by_type.spendable.as_typed_vec().into_iter().for_each(
|
||||
|(output_type, supply_state)| {
|
||||
self.by_type
|
||||
.get_mut(output_type)
|
||||
.1
|
||||
.state
|
||||
.decrement(supply_state, price)
|
||||
},
|
||||
);
|
||||
|
||||
sent.by_size.into_iter().for_each(|(group, supply_state)| {
|
||||
self.by_size
|
||||
.get_mut(group)
|
||||
.1
|
||||
.state
|
||||
.decrement(&supply_state, price);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub fn receive(
|
||||
&mut self,
|
||||
received: OutputsByType<(SupplyState, Vec<Sats>)>,
|
||||
height: Height,
|
||||
price: Option<Dollars>,
|
||||
) {
|
||||
let supply_state = received.spendable.reduce();
|
||||
pub fn receive(&mut self, received: Transacted, height: Height, price: Option<Dollars>) {
|
||||
let supply_state = received.spendable_supply;
|
||||
|
||||
[
|
||||
&mut self.all.1,
|
||||
@@ -214,34 +192,7 @@ impl Outputs<(OutputFilter, vecs::utxos::cohort::Vecs)> {
|
||||
v.state.increment(&supply_state, price);
|
||||
});
|
||||
|
||||
let mut by_size = self.by_size.as_mut_vec();
|
||||
|
||||
received
|
||||
.spendable
|
||||
.as_vec()
|
||||
.into_iter()
|
||||
.flat_map(|(_, sats_received)| sats_received.iter())
|
||||
.for_each(|sats| {
|
||||
let sats = *sats;
|
||||
|
||||
by_size
|
||||
.iter_mut()
|
||||
.filter(|(filter, _)| match filter {
|
||||
OutputFilter::Size(range) => range.contains(&sats),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.for_each(|(_, vec)| {
|
||||
vec.state.increment(
|
||||
&SupplyState {
|
||||
utxos: 1,
|
||||
value: sats,
|
||||
},
|
||||
price,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
self.by_spendable_type
|
||||
self.by_type
|
||||
.as_mut_vec()
|
||||
.into_iter()
|
||||
.for_each(|(filter, vecs)| {
|
||||
@@ -250,7 +201,18 @@ impl Outputs<(OutputFilter, vecs::utxos::cohort::Vecs)> {
|
||||
_ => unreachable!(),
|
||||
};
|
||||
vecs.state
|
||||
.increment(&received.spendable.get(output_type).0, price)
|
||||
.increment(received.by_type.get(output_type), price)
|
||||
});
|
||||
|
||||
received
|
||||
.by_size
|
||||
.into_iter()
|
||||
.for_each(|(group, supply_state)| {
|
||||
self.by_size
|
||||
.get_mut(group)
|
||||
.1
|
||||
.state
|
||||
.increment(&supply_state, price);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -262,11 +224,11 @@ impl<T> Outputs<(OutputFilter, T)> {
|
||||
.chain(self.by_term.vecs())
|
||||
// .chain(self.by_up_to.vecs())
|
||||
.chain(self.by_from.vecs())
|
||||
// .chain(self.by_range.vecs())
|
||||
.chain(self.by_range.vecs())
|
||||
.chain(self.by_epoch.vecs())
|
||||
.chain(self.by_size.vecs())
|
||||
// // .chain(self.by_value.vecs())
|
||||
.chain(self.by_spendable_type.vecs())
|
||||
.chain(self.by_type.vecs())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
@@ -278,12 +240,12 @@ impl<T> From<Outputs<T>> for Outputs<(OutputFilter, T)> {
|
||||
by_term: OutputsByTerm::from(value.by_term),
|
||||
// by_up_to: OutputsByUpTo::from(value.by_up_to),
|
||||
by_from: OutputsByFrom::from(value.by_from),
|
||||
// by_range: OutputsByRange::from(value.by_range),
|
||||
by_range: OutputsByRange::from(value.by_range),
|
||||
by_epoch: OutputsByEpoch::from(value.by_epoch),
|
||||
by_size: OutputsBySize::from(value.by_size),
|
||||
// // Needs whole UTXO set, TODO later
|
||||
// // by_value: OutputsByValue<T>,
|
||||
by_spendable_type: OutputsBySpendableType::from(value.by_spendable_type),
|
||||
by_type: OutputsBySpendableType::from(value.by_type),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,61 @@
|
||||
use brk_core::Dollars;
|
||||
use brk_core::{Bitcoin, CheckedSub, Dollars};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
use super::SupplyState;
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct RealizedState {
|
||||
realized_profit: Dollars,
|
||||
realized_loss: Dollars,
|
||||
value_created: Dollars,
|
||||
adjusted_value_created: Dollars,
|
||||
value_destroyed: Dollars,
|
||||
adjusted_value_destroyed: Dollars,
|
||||
pub realized_cap: Dollars,
|
||||
// pub realized_profit: Dollars,
|
||||
// pub realized_loss: Dollars,
|
||||
// pub value_created: Dollars,
|
||||
// pub adjusted_value_created: Dollars,
|
||||
// pub value_destroyed: Dollars,
|
||||
// pub adjusted_value_destroyed: Dollars,
|
||||
}
|
||||
|
||||
impl RealizedState {
|
||||
pub const NAN: Self = Self {
|
||||
realized_cap: Dollars::NAN,
|
||||
// realized_profit: Dollars::NAN,
|
||||
// realized_loss: Dollars::NAN,
|
||||
// value_created: Dollars::NAN,
|
||||
// adjusted_value_created: Dollars::NAN,
|
||||
// value_destroyed: Dollars::NAN,
|
||||
// adjusted_value_destroyed: Dollars::NAN,
|
||||
};
|
||||
|
||||
pub fn increment(&mut self, supply_state: &SupplyState, price: Dollars) {
|
||||
if supply_state.value.is_not_zero() {
|
||||
if self.realized_cap == Dollars::NAN {
|
||||
self.realized_cap = Dollars::ZERO;
|
||||
}
|
||||
self.realized_cap += price * Bitcoin::from(supply_state.value);
|
||||
}
|
||||
|
||||
// if self.realized_profit == Dollars::NAN {
|
||||
// self.realized_profit = Dollars::ZERO;
|
||||
// }
|
||||
// if self.realized_loss == Dollars::NAN {
|
||||
// self.realized_loss = Dollars::ZERO;
|
||||
// }
|
||||
// if self.value_created == Dollars::NAN {
|
||||
// self.value_created = Dollars::ZERO;
|
||||
// }
|
||||
// if self.adjusted_value_created == Dollars::NAN {
|
||||
// self.adjusted_value_created = Dollars::ZERO;
|
||||
// }
|
||||
// if self.value_destroyed == Dollars::NAN {
|
||||
// self.value_destroyed = Dollars::ZERO;
|
||||
// }
|
||||
// if self.adjusted_value_destroyed == Dollars::NAN {
|
||||
// self.adjusted_value_destroyed = Dollars::ZERO;
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn decrement(&mut self, supply_state: &SupplyState, price: Dollars) {
|
||||
self.realized_cap = self
|
||||
.realized_cap
|
||||
.checked_sub(price * Bitcoin::from(supply_state.value))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,12 @@ impl Add<SupplyState> for SupplyState {
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<SupplyState> for SupplyState {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
*self += &rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<&SupplyState> for SupplyState {
|
||||
fn add_assign(&mut self, rhs: &Self) {
|
||||
self.utxos += rhs.utxos;
|
||||
|
||||
100
crates/brk_computer/src/states/transacted.rs
Normal file
100
crates/brk_computer/src/states/transacted.rs
Normal file
@@ -0,0 +1,100 @@
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
mem,
|
||||
ops::{Add, AddAssign},
|
||||
};
|
||||
|
||||
use brk_core::{OutputType, Sats};
|
||||
|
||||
use super::{OutputsByType, SupplyState};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Transacted {
|
||||
pub spendable_supply: SupplyState,
|
||||
pub by_type: OutputsByType<SupplyState>,
|
||||
pub by_size: BTreeMap<usize, SupplyState>,
|
||||
}
|
||||
|
||||
impl Transacted {
|
||||
#[allow(clippy::inconsistent_digit_grouping)]
|
||||
pub fn iterate(&mut self, value: Sats, _type: OutputType) {
|
||||
let supply = SupplyState { utxos: 1, value };
|
||||
|
||||
*self.by_type.get_mut(_type) += &supply;
|
||||
|
||||
if _type.is_unspendable() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.spendable_supply += &supply;
|
||||
|
||||
let _value = usize::from(value);
|
||||
|
||||
// Need to be in sync with by_size !! but plenty fast (I think)
|
||||
if _value == 0 {
|
||||
*self.by_size.entry(0).or_default() += &supply;
|
||||
} else if _value < 10 {
|
||||
*self.by_size.entry(1).or_default() += &supply;
|
||||
} else if _value < 100 {
|
||||
*self.by_size.entry(10).or_default() += &supply;
|
||||
} else if _value < 1_000 {
|
||||
*self.by_size.entry(100).or_default() += &supply;
|
||||
} else if _value < 10_000 {
|
||||
*self.by_size.entry(1_000).or_default() += &supply;
|
||||
} else if _value < 100_000 {
|
||||
*self.by_size.entry(10_000).or_default() += &supply;
|
||||
} else if _value < 1_000_000 {
|
||||
*self.by_size.entry(100_000).or_default() += &supply;
|
||||
} else if _value < 10_000_000 {
|
||||
*self.by_size.entry(1_000_000).or_default() += &supply;
|
||||
} else if _value < 1_00_000_000 {
|
||||
*self.by_size.entry(10_000_000).or_default() += &supply;
|
||||
} else if _value < 10_00_000_000 {
|
||||
*self.by_size.entry(1_00_000_000).or_default() += &supply;
|
||||
} else if _value < 100_00_000_000 {
|
||||
*self.by_size.entry(10_00_000_000).or_default() += &supply;
|
||||
} else if _value < 1_000_00_000_000 {
|
||||
*self.by_size.entry(100_00_000_000).or_default() += &supply;
|
||||
} else if _value < 10_000_00_000_000 {
|
||||
*self.by_size.entry(1_000_00_000_000).or_default() += &supply;
|
||||
} else if _value < 100_000_00_000_000 {
|
||||
*self.by_size.entry(10_000_00_000_000).or_default() += &supply;
|
||||
} else {
|
||||
*self.by_size.entry(100_000_00_000_000).or_default() += &supply;
|
||||
}
|
||||
}
|
||||
|
||||
fn merge_by_size(
|
||||
first: BTreeMap<usize, SupplyState>,
|
||||
second: BTreeMap<usize, SupplyState>,
|
||||
) -> BTreeMap<usize, SupplyState> {
|
||||
let (mut source, to_consume) = if first.len() > second.len() {
|
||||
(first, second)
|
||||
} else {
|
||||
(second, first)
|
||||
};
|
||||
to_consume.into_iter().for_each(|(k, v)| {
|
||||
*source.entry(k).or_default() += &v;
|
||||
});
|
||||
source
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Transacted {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self {
|
||||
spendable_supply: self.spendable_supply + rhs.spendable_supply,
|
||||
by_type: self.by_type + rhs.by_type,
|
||||
by_size: Self::merge_by_size(self.by_size, rhs.by_size),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for Transacted {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.by_size = Self::merge_by_size(mem::take(&mut self.by_size), rhs.by_size);
|
||||
self.spendable_supply += &rhs.spendable_supply;
|
||||
self.by_type += rhs.by_type;
|
||||
}
|
||||
}
|
||||
@@ -405,6 +405,7 @@ impl ComputedVecsFromTxindex<Bitcoin> {
|
||||
}
|
||||
|
||||
impl ComputedVecsFromTxindex<Dollars> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn compute_rest_from_bitcoin(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
|
||||
@@ -8,7 +8,7 @@ use brk_vec::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
states::CohortState,
|
||||
states::{CohortState, RealizedState},
|
||||
vecs::{
|
||||
Indexes, fetched,
|
||||
grouped::{
|
||||
@@ -55,7 +55,7 @@ impl Vecs {
|
||||
|
||||
let mut state = CohortState::default();
|
||||
if compute_dollars {
|
||||
state.realized_cap = Some(Dollars::ZERO);
|
||||
state.realized = Some(RealizedState::NAN);
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
@@ -169,11 +169,9 @@ impl Vecs {
|
||||
.unwrap_get_inner(prev_height);
|
||||
|
||||
if let Some(height_to_realized_cap) = self.height_to_realized_cap.as_mut() {
|
||||
self.state.realized_cap = Some(
|
||||
height_to_realized_cap
|
||||
self.state.realized.as_mut().unwrap().realized_cap = height_to_realized_cap
|
||||
.into_iter()
|
||||
.unwrap_get_inner(prev_height),
|
||||
);
|
||||
.unwrap_get_inner(prev_height);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,10 +213,14 @@ impl Vecs {
|
||||
if let Some(height_to_realized_cap) = self.height_to_realized_cap.as_mut() {
|
||||
height_to_realized_cap.forced_push_at(
|
||||
height,
|
||||
self.state.realized_cap.unwrap_or_else(|| {
|
||||
self.state
|
||||
.realized
|
||||
.as_ref()
|
||||
.unwrap_or_else(|| {
|
||||
dbg!(&self.state);
|
||||
panic!();
|
||||
}),
|
||||
})
|
||||
.realized_cap,
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
use std::{cmp::Ordering, collections::BTreeMap, mem, path::Path, thread};
|
||||
|
||||
use brk_core::{Height, InputIndex, OutputIndex, Sats};
|
||||
use brk_core::{Height, InputIndex, OutputIndex, OutputType, Sats};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{
|
||||
AnyCollectableVec, AnyVec, BaseVecIterator, CollectableVec, Compressed, Computation, EagerVec,
|
||||
GenericStoredVec, StoredIndex, StoredVec, VecIterator, Version,
|
||||
GenericStoredVec, StoredIndex, StoredVec, UnsafeSlice, VecIterator, Version,
|
||||
};
|
||||
use log::info;
|
||||
use rayon::prelude::*;
|
||||
|
||||
use crate::states::{
|
||||
BlockState, OutputFilter, Outputs, OutputsByEpoch, OutputsByFrom, OutputsByRange,
|
||||
OutputsBySize, OutputsBySpendableType, OutputsByTerm, OutputsByType, OutputsByUpTo,
|
||||
ReceivedBlockStateData, SupplyState,
|
||||
OutputsBySize, OutputsBySpendableType, OutputsByTerm, SupplyState, Transacted,
|
||||
};
|
||||
|
||||
use super::{
|
||||
@@ -23,7 +23,7 @@ use super::{
|
||||
|
||||
pub mod cohort;
|
||||
|
||||
const VERSION: Version = Version::new(99);
|
||||
const VERSION: Version = Version::new(999);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vecs {
|
||||
@@ -32,6 +32,8 @@ pub struct Vecs {
|
||||
// cointime,...
|
||||
pub height_to_unspendable_supply: EagerVec<Height, Sats>,
|
||||
pub indexes_to_unspendable_supply: ComputedValueVecsFromHeight,
|
||||
// pub height_to_opreturn_supply: EagerVec<Height, Sats>,
|
||||
// pub indexes_to_opreturn_supply: ComputedValueVecsFromHeight,
|
||||
utxos_vecs: Outputs<(OutputFilter, cohort::Vecs)>,
|
||||
}
|
||||
|
||||
@@ -391,104 +393,104 @@ impl Vecs {
|
||||
fetched,
|
||||
)?,
|
||||
},
|
||||
// by_range: OutputsByRange {
|
||||
// _1d_to_1w: cohort::Vecs::forced_import(
|
||||
// path,
|
||||
// Some("from_1d_to_1w"),
|
||||
// _computation,
|
||||
// compressed,
|
||||
// VERSION + Version::ZERO,
|
||||
// fetched,
|
||||
// )?,
|
||||
// _1w_to_1m: cohort::Vecs::forced_import(
|
||||
// path,
|
||||
// Some("from_1w_to_1m"),
|
||||
// _computation,
|
||||
// compressed,
|
||||
// VERSION + Version::ZERO,
|
||||
// fetched,
|
||||
// )?,
|
||||
// _1m_to_3m: cohort::Vecs::forced_import(
|
||||
// path,
|
||||
// Some("from_1m_to_3m"),
|
||||
// _computation,
|
||||
// compressed,
|
||||
// VERSION + Version::ZERO,
|
||||
// fetched,
|
||||
// )?,
|
||||
// _3m_to_6m: cohort::Vecs::forced_import(
|
||||
// path,
|
||||
// Some("from_3m_to_6m"),
|
||||
// _computation,
|
||||
// compressed,
|
||||
// VERSION + Version::ZERO,
|
||||
// fetched,
|
||||
// )?,
|
||||
// _6m_to_1y: cohort::Vecs::forced_import(
|
||||
// path,
|
||||
// Some("from_6m_to_1y"),
|
||||
// _computation,
|
||||
// compressed,
|
||||
// VERSION + Version::ZERO,
|
||||
// fetched,
|
||||
// )?,
|
||||
// _1y_to_2y: cohort::Vecs::forced_import(
|
||||
// path,
|
||||
// Some("from_1y_to_2y"),
|
||||
// _computation,
|
||||
// compressed,
|
||||
// VERSION + Version::ZERO,
|
||||
// fetched,
|
||||
// )?,
|
||||
// _2y_to_3y: cohort::Vecs::forced_import(
|
||||
// path,
|
||||
// Some("from_2y_to_3y"),
|
||||
// _computation,
|
||||
// compressed,
|
||||
// VERSION + Version::ZERO,
|
||||
// fetched,
|
||||
// )?,
|
||||
// _3y_to_4y: cohort::Vecs::forced_import(
|
||||
// path,
|
||||
// Some("from_3y_to_4y"),
|
||||
// _computation,
|
||||
// compressed,
|
||||
// VERSION + Version::ZERO,
|
||||
// fetched,
|
||||
// )?,
|
||||
// _4y_to_5y: cohort::Vecs::forced_import(
|
||||
// path,
|
||||
// Some("from_4y_to_5y"),
|
||||
// _computation,
|
||||
// compressed,
|
||||
// VERSION + Version::ZERO,
|
||||
// fetched,
|
||||
// )?,
|
||||
// _5y_to_7y: cohort::Vecs::forced_import(
|
||||
// path,
|
||||
// Some("from_5y_to_7y"),
|
||||
// _computation,
|
||||
// compressed,
|
||||
// VERSION + Version::ZERO,
|
||||
// fetched,
|
||||
// )?,
|
||||
// _7y_to_10y: cohort::Vecs::forced_import(
|
||||
// path,
|
||||
// Some("from_7y_to_10y"),
|
||||
// _computation,
|
||||
// compressed,
|
||||
// VERSION + Version::ZERO,
|
||||
// fetched,
|
||||
// )?,
|
||||
// _10y_to_15y: cohort::Vecs::forced_import(
|
||||
// path,
|
||||
// Some("from_10y_to_15y"),
|
||||
// _computation,
|
||||
// compressed,
|
||||
// VERSION + Version::ZERO,
|
||||
// fetched,
|
||||
// )?,
|
||||
// },
|
||||
by_range: OutputsByRange {
|
||||
_1d_to_1w: cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("from_1d_to_1w"),
|
||||
_computation,
|
||||
compressed,
|
||||
VERSION + Version::ZERO,
|
||||
fetched,
|
||||
)?,
|
||||
_1w_to_1m: cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("from_1w_to_1m"),
|
||||
_computation,
|
||||
compressed,
|
||||
VERSION + Version::ZERO,
|
||||
fetched,
|
||||
)?,
|
||||
_1m_to_3m: cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("from_1m_to_3m"),
|
||||
_computation,
|
||||
compressed,
|
||||
VERSION + Version::ZERO,
|
||||
fetched,
|
||||
)?,
|
||||
_3m_to_6m: cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("from_3m_to_6m"),
|
||||
_computation,
|
||||
compressed,
|
||||
VERSION + Version::ZERO,
|
||||
fetched,
|
||||
)?,
|
||||
_6m_to_1y: cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("from_6m_to_1y"),
|
||||
_computation,
|
||||
compressed,
|
||||
VERSION + Version::ZERO,
|
||||
fetched,
|
||||
)?,
|
||||
_1y_to_2y: cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("from_1y_to_2y"),
|
||||
_computation,
|
||||
compressed,
|
||||
VERSION + Version::ZERO,
|
||||
fetched,
|
||||
)?,
|
||||
_2y_to_3y: cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("from_2y_to_3y"),
|
||||
_computation,
|
||||
compressed,
|
||||
VERSION + Version::ZERO,
|
||||
fetched,
|
||||
)?,
|
||||
_3y_to_4y: cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("from_3y_to_4y"),
|
||||
_computation,
|
||||
compressed,
|
||||
VERSION + Version::ZERO,
|
||||
fetched,
|
||||
)?,
|
||||
_4y_to_5y: cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("from_4y_to_5y"),
|
||||
_computation,
|
||||
compressed,
|
||||
VERSION + Version::ZERO,
|
||||
fetched,
|
||||
)?,
|
||||
_5y_to_7y: cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("from_5y_to_7y"),
|
||||
_computation,
|
||||
compressed,
|
||||
VERSION + Version::ZERO,
|
||||
fetched,
|
||||
)?,
|
||||
_7y_to_10y: cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("from_7y_to_10y"),
|
||||
_computation,
|
||||
compressed,
|
||||
VERSION + Version::ZERO,
|
||||
fetched,
|
||||
)?,
|
||||
_10y_to_15y: cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("from_10y_to_15y"),
|
||||
_computation,
|
||||
compressed,
|
||||
VERSION + Version::ZERO,
|
||||
fetched,
|
||||
)?,
|
||||
},
|
||||
by_epoch: OutputsByEpoch {
|
||||
_0: cohort::Vecs::forced_import(
|
||||
path,
|
||||
@@ -532,6 +534,14 @@ impl Vecs {
|
||||
)?,
|
||||
},
|
||||
by_size: OutputsBySize {
|
||||
_0sat: cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("0sat"),
|
||||
_computation,
|
||||
compressed,
|
||||
VERSION + Version::ZERO,
|
||||
fetched,
|
||||
)?,
|
||||
from_1sat_to_10sats: cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("from_1sat_to_10sats"),
|
||||
@@ -738,7 +748,7 @@ impl Vecs {
|
||||
// fetched,
|
||||
// )?,
|
||||
// },
|
||||
by_spendable_type: OutputsBySpendableType {
|
||||
by_type: OutputsBySpendableType {
|
||||
p2pk65: cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("p2pk65"),
|
||||
@@ -819,14 +829,14 @@ impl Vecs {
|
||||
VERSION + Version::ZERO,
|
||||
fetched,
|
||||
)?,
|
||||
// empty: cohort::Vecs::forced_import(
|
||||
// path,
|
||||
// Some("empty"),
|
||||
// _computation,
|
||||
// compressed,
|
||||
// VERSION + Version::ZERO,
|
||||
// fetched,
|
||||
// )?,
|
||||
empty: cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("empty"),
|
||||
_computation,
|
||||
compressed,
|
||||
VERSION + Version::ZERO,
|
||||
fetched,
|
||||
)?,
|
||||
unknown: cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("unknown"),
|
||||
@@ -873,18 +883,19 @@ impl Vecs {
|
||||
.as_ref()
|
||||
.map(|fetched| &fetched.chainindexes_to_close.height);
|
||||
|
||||
let inputindex_to_outputindex_mmap = inputindex_to_outputindex.mmap().load();
|
||||
let outputindex_to_value_mmap = outputindex_to_value.mmap().load();
|
||||
let outputindex_to_outputtype_mmap = outputindex_to_outputtype.mmap().load();
|
||||
let outputindex_to_txindex_mmap = outputindex_to_txindex.mmap().load();
|
||||
let txindex_to_height_mmap = txindex_to_height.mmap().load();
|
||||
|
||||
let mut height_to_first_outputindex_iter = height_to_first_outputindex.into_iter();
|
||||
let mut height_to_first_inputindex_iter = height_to_first_inputindex.into_iter();
|
||||
let mut height_to_output_count_iter = height_to_output_count.into_iter();
|
||||
let mut height_to_input_count_iter = height_to_input_count.into_iter();
|
||||
let mut inputindex_to_outputindex_iter = inputindex_to_outputindex.into_iter();
|
||||
let mut outputindex_to_value_iter = outputindex_to_value.into_iter();
|
||||
let mut outputindex_to_value_iter_2 = outputindex_to_value.into_iter();
|
||||
let mut txindex_to_height_iter = txindex_to_height.into_iter();
|
||||
let mut outputindex_to_txindex_iter = outputindex_to_txindex.into_iter();
|
||||
// let mut outputindex_to_value_iter_2 = outputindex_to_value.into_iter();
|
||||
let mut height_to_close_iter = height_to_close.as_ref().map(|v| v.into_iter());
|
||||
let mut outputindex_to_outputtype_iter = outputindex_to_outputtype.into_iter();
|
||||
let mut outputindex_to_outputtype_iter_2 = outputindex_to_outputtype.into_iter();
|
||||
// let mut outputindex_to_outputtype_iter_2 = outputindex_to_outputtype.into_iter();
|
||||
let mut height_to_unclaimed_rewards_iter = height_to_unclaimed_rewards.into_iter();
|
||||
let mut height_to_timestamp_fixed_iter = height_to_timestamp_fixed.into_iter();
|
||||
|
||||
@@ -1012,104 +1023,134 @@ impl Vecs {
|
||||
}
|
||||
|
||||
let sent_handle = s.spawn(|| {
|
||||
let mut txindex_to_height = BTreeMap::new();
|
||||
let mut height_to_sent: BTreeMap<
|
||||
Height,
|
||||
OutputsByType<(SupplyState, Vec<Sats>)>,
|
||||
> = BTreeMap::new();
|
||||
|
||||
// Skip coinbase
|
||||
(first_inputindex + 1..first_inputindex + *input_count)
|
||||
.into_par_iter()
|
||||
.map(InputIndex::from)
|
||||
.for_each(|inputindex| {
|
||||
let outputindex =
|
||||
inputindex_to_outputindex_iter.unwrap_get_inner(inputindex);
|
||||
.map(|inputindex| {
|
||||
let outputindex = inputindex_to_outputindex
|
||||
.get_or_read(inputindex, &inputindex_to_outputindex_mmap)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let value = outputindex_to_value_iter.unwrap_get_inner(outputindex);
|
||||
let value = outputindex_to_value
|
||||
.get_or_read(outputindex, &outputindex_to_value_mmap)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let input_type =
|
||||
outputindex_to_outputtype_iter.unwrap_get_inner(outputindex);
|
||||
let input_type = outputindex_to_outputtype
|
||||
.get_or_read(outputindex, &outputindex_to_outputtype_mmap)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let input_txindex =
|
||||
outputindex_to_txindex_iter.unwrap_get_inner(outputindex);
|
||||
if input_type.is_unspendable() {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
let input_height =
|
||||
*txindex_to_height.entry(input_txindex).or_insert_with(|| {
|
||||
txindex_to_height_iter.unwrap_get_inner(input_txindex)
|
||||
let input_txindex = outputindex_to_txindex
|
||||
.get_or_read(outputindex, &outputindex_to_txindex_mmap)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
// let input_height = *cached_txindex_to_height
|
||||
// .entry(input_txindex)
|
||||
// .or_insert_with(|| {
|
||||
let height = txindex_to_height
|
||||
.get_or_read(input_txindex, &txindex_to_height_mmap)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
// });
|
||||
|
||||
(height, value, input_type)
|
||||
})
|
||||
.fold(
|
||||
BTreeMap::<Height, Transacted>::default,
|
||||
|mut tree, (height, value, input_type)| {
|
||||
tree.entry(height).or_default().iterate(value, input_type);
|
||||
tree
|
||||
},
|
||||
)
|
||||
.reduce(BTreeMap::<Height, Transacted>::default, |first, second| {
|
||||
let (mut source, to_consume) = if first.len() > second.len() {
|
||||
(first, second)
|
||||
} else {
|
||||
(second, first)
|
||||
};
|
||||
to_consume.into_iter().for_each(|(k, v)| {
|
||||
*source.entry(k).or_default() += v;
|
||||
});
|
||||
|
||||
let input_data = height_to_sent.entry(input_height).or_default();
|
||||
|
||||
let (sent_supply, sats_vec) = input_data.get_mut(input_type);
|
||||
|
||||
sent_supply.utxos += 1;
|
||||
sent_supply.value += value;
|
||||
sats_vec.push(value);
|
||||
});
|
||||
|
||||
height_to_sent
|
||||
source
|
||||
})
|
||||
});
|
||||
|
||||
let received_handle = s.spawn(|| {
|
||||
let mut by_type: OutputsByType<(SupplyState, Vec<Sats>)> =
|
||||
OutputsByType::default();
|
||||
|
||||
(first_outputindex..first_outputindex + *output_count)
|
||||
.into_par_iter()
|
||||
.map(OutputIndex::from)
|
||||
.for_each(|outputindex| {
|
||||
let value =
|
||||
outputindex_to_value_iter_2.unwrap_get_inner(outputindex);
|
||||
.map(|outputindex| {
|
||||
let value = outputindex_to_value
|
||||
.get_or_read(outputindex, &outputindex_to_value_mmap)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let output_type =
|
||||
outputindex_to_outputtype_iter_2.unwrap_get_inner(outputindex);
|
||||
let output_type = outputindex_to_outputtype
|
||||
.get_or_read(outputindex, &outputindex_to_outputtype_mmap)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let (received_supply, sats_vec) = by_type.get_mut(output_type);
|
||||
|
||||
received_supply.value += value;
|
||||
received_supply.utxos += 1;
|
||||
sats_vec.push(value);
|
||||
});
|
||||
|
||||
by_type
|
||||
(value, output_type)
|
||||
})
|
||||
.fold(
|
||||
Transacted::default,
|
||||
|mut transacted, (value, output_type)| {
|
||||
transacted.iterate(value, output_type);
|
||||
transacted
|
||||
},
|
||||
)
|
||||
.reduce(Transacted::default, |acc, transacted| acc + transacted)
|
||||
});
|
||||
|
||||
(sent_handle.join().unwrap(), received_handle.join().unwrap())
|
||||
});
|
||||
|
||||
unspendable_supply += received
|
||||
.by_type
|
||||
.unspendable
|
||||
.as_vec()
|
||||
.into_iter()
|
||||
.map(|state| state.0.value)
|
||||
.map(|state| state.value)
|
||||
.sum::<Sats>()
|
||||
+ height_to_unclaimed_rewards_iter.unwrap_get_inner(height);
|
||||
|
||||
if height == Height::new(0) {
|
||||
received.spendable.p2pk65.1.remove(0);
|
||||
received.spendable.p2pk65.0.utxos -= 1;
|
||||
received.spendable.p2pk65.0.value -= Sats::FIFTY_BTC;
|
||||
received = Transacted::default();
|
||||
unspendable_supply += Sats::FIFTY_BTC;
|
||||
} else if height == Height::new(91_842) || height == Height::new(91_880) {
|
||||
// Need to destroy invalid coinbases due to duplicate txids
|
||||
let entry = if height == Height::new(91_842) {
|
||||
if height == Height::new(91_842) {
|
||||
height_to_sent.entry(Height::new(91_812)).or_default()
|
||||
} else {
|
||||
height_to_sent.entry(Height::new(91_722)).or_default()
|
||||
};
|
||||
entry.spendable.p2pk65.0.value += Sats::FIFTY_BTC;
|
||||
entry.spendable.p2pk65.0.utxos += 1;
|
||||
entry.spendable.p2pk65.1.push(Sats::FIFTY_BTC);
|
||||
}
|
||||
.iterate(Sats::FIFTY_BTC, OutputType::P2PK65);
|
||||
};
|
||||
|
||||
if chain_state_starting_height <= height {
|
||||
// RECEIVE
|
||||
|
||||
// Push current block state before processing sends and receives
|
||||
chain_state.push(BlockState::from(ReceivedBlockStateData {
|
||||
received: &received,
|
||||
chain_state.push(BlockState {
|
||||
supply: received.spendable_supply.clone(),
|
||||
price,
|
||||
timestamp,
|
||||
}));
|
||||
});
|
||||
|
||||
self.utxos_vecs.receive(received, height, price);
|
||||
|
||||
@@ -1117,16 +1158,11 @@ impl Vecs {
|
||||
|
||||
// SEND
|
||||
|
||||
height_to_sent
|
||||
.iter()
|
||||
.for_each(|(height, sent_data_by_type)| {
|
||||
let block_state =
|
||||
chain_state.get_mut(height.unwrap_to_usize()).unwrap();
|
||||
let unsafe_chain_state = UnsafeSlice::new(&mut chain_state);
|
||||
|
||||
sent_data_by_type
|
||||
.as_vec()
|
||||
.into_iter()
|
||||
.for_each(|(supply, _)| block_state.supply -= supply);
|
||||
height_to_sent.par_iter().for_each(|(height, sent)| unsafe {
|
||||
(*unsafe_chain_state.get(height.unwrap_to_usize())).supply -=
|
||||
&sent.spendable_supply;
|
||||
});
|
||||
|
||||
self.utxos_vecs.send(height_to_sent, chain_state.as_slice());
|
||||
@@ -1151,6 +1187,8 @@ impl Vecs {
|
||||
|
||||
exit.block();
|
||||
|
||||
info!("Computing utxo set datasets...");
|
||||
|
||||
let mut flat_vecs_ = self.utxos_vecs.as_mut_vec();
|
||||
|
||||
// Flush rest of values
|
||||
|
||||
@@ -29,6 +29,7 @@ pub struct Dollars(f64);
|
||||
|
||||
impl Dollars {
|
||||
pub const ZERO: Self = Self(0.0);
|
||||
pub const NAN: Self = Self(f64::NAN);
|
||||
|
||||
pub const fn mint(dollars: f64) -> Self {
|
||||
Self(dollars)
|
||||
|
||||
@@ -45,8 +45,8 @@ impl OutputType {
|
||||
Self::P2WSH => true,
|
||||
Self::P2TR => true,
|
||||
Self::P2A => true,
|
||||
Self::Empty => false,
|
||||
Self::Unknown => false,
|
||||
Self::Empty => true,
|
||||
Self::Unknown => true,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,10 @@ impl Sats {
|
||||
pub fn is_zero(&self) -> bool {
|
||||
*self == Self::ZERO
|
||||
}
|
||||
|
||||
pub fn is_not_zero(&self) -> bool {
|
||||
*self != Self::ZERO
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Sats {
|
||||
@@ -140,6 +144,12 @@ impl From<Sats> for f64 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Sats> for usize {
|
||||
fn from(value: Sats) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Amount> for Sats {
|
||||
fn from(value: Amount) -> Self {
|
||||
Self(value.to_sat())
|
||||
|
||||
@@ -35,7 +35,7 @@ impl Fetcher {
|
||||
pub fn get_date(&mut self, date: Date) -> color_eyre::Result<OHLCCents> {
|
||||
self.kraken
|
||||
.get_from_1d(&date)
|
||||
.or_else(|e| {
|
||||
.or_else(|_| {
|
||||
// eprintln!("{e}");
|
||||
self.binance.get_from_1d(&date)
|
||||
})
|
||||
|
||||
@@ -44,7 +44,7 @@ impl<'a> VecTrees<'a> {
|
||||
.id_to_index_to_vec
|
||||
.entry(key.clone())
|
||||
.or_default()
|
||||
.insert(index.clone(), vec);
|
||||
.insert(index, vec);
|
||||
if prev.is_some() {
|
||||
dbg!(&key, str, name);
|
||||
panic!()
|
||||
|
||||
@@ -19,6 +19,11 @@ impl<'a, T> UnsafeSlice<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// SAFETY: It is UB
|
||||
pub fn get(&self, i: usize) -> *mut T {
|
||||
self.0[i].get()
|
||||
}
|
||||
|
||||
pub fn copy_slice(&self, start: usize, slice: &[T])
|
||||
where
|
||||
T: Copy,
|
||||
|
||||
@@ -8,11 +8,13 @@ use std::{
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use arc_swap::ArcSwap;
|
||||
use brk_core::{
|
||||
Bitcoin, CheckedSub, Close, Date, DateIndex, Dollars, Height, Sats, StoredUsize, TxIndex,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use log::info;
|
||||
use memmap2::Mmap;
|
||||
|
||||
use crate::{
|
||||
AnyCollectableVec, AnyIterableVec, AnyVec, BoxedVecIterator, CollectableVec, Compressed, Error,
|
||||
@@ -97,6 +99,14 @@ where
|
||||
self.inner.path()
|
||||
}
|
||||
|
||||
pub fn get_or_read(&self, index: I, mmap: &Mmap) -> Result<Option<Value<T>>> {
|
||||
self.inner.get_or_read(index, mmap)
|
||||
}
|
||||
|
||||
pub fn mmap(&self) -> &ArcSwap<Mmap> {
|
||||
self.inner.mmap()
|
||||
}
|
||||
|
||||
pub fn inner_version(&self) -> Version {
|
||||
self.inner.version()
|
||||
}
|
||||
|
||||
@@ -352,18 +352,19 @@ function createPartialOptions(colors) {
|
||||
*
|
||||
* @param {Object} args
|
||||
* @param {string} args.name
|
||||
* @param {string} args.legend
|
||||
* @param {string} args.title
|
||||
* @param {VecIdRatioCapBase} args.key
|
||||
* @param {Color} [args.color]
|
||||
*/
|
||||
function createPriceWithRatio({ name, title, key, color }) {
|
||||
function createPriceWithRatio({ name, title, legend, key, color }) {
|
||||
return {
|
||||
name,
|
||||
title,
|
||||
top: [
|
||||
createBaseSeries({
|
||||
key,
|
||||
name: "Average",
|
||||
name: legend,
|
||||
color,
|
||||
}),
|
||||
createBaseSeries({
|
||||
@@ -633,6 +634,7 @@ function createPartialOptions(colors) {
|
||||
createPriceWithRatio({
|
||||
key: `${key}realized-price`,
|
||||
name: "realized price",
|
||||
legend: "realized",
|
||||
title: `${title} Realized Price`,
|
||||
}),
|
||||
],
|
||||
@@ -747,6 +749,7 @@ function createPartialOptions(colors) {
|
||||
key: `${key}-sma`,
|
||||
name,
|
||||
title: `${name} Market Price Moving Average`,
|
||||
legend: "average",
|
||||
color: colors[`_${key}`],
|
||||
}),
|
||||
),
|
||||
@@ -785,6 +788,11 @@ function createPartialOptions(colors) {
|
||||
],
|
||||
})),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Investing",
|
||||
tree: [
|
||||
{
|
||||
name: "DCA vs Lump sum",
|
||||
tree: [
|
||||
@@ -1581,6 +1589,71 @@ function createPartialOptions(colors) {
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Range",
|
||||
tree: [
|
||||
createUTXOGroupFolder({
|
||||
key: "from-1d-to-1w",
|
||||
name: "1d..1w",
|
||||
title: "Between 1 Day and 1 Week",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-1w-to-1m",
|
||||
name: "1w..1m",
|
||||
title: "Between 1 Week and 1 Month",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-1m-to-3m",
|
||||
name: "1m..3m",
|
||||
title: "Between 1 Month and 3 Months",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-3m-to-6m",
|
||||
name: "3m..6m",
|
||||
title: "Between 3 Month and 6 Months",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-6m-to-1y",
|
||||
name: "6m..1y",
|
||||
title: "Between 6 Months and 1 Year",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-1y-to-2y",
|
||||
name: "1y..2y",
|
||||
title: "Between 1 Year and 2 Years",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-2y-to-3y",
|
||||
name: "2y..3y",
|
||||
title: "Between 2 Years and 3 Years",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-3y-to-4y",
|
||||
name: "3y..4y",
|
||||
title: "Between 3 Years and 4 Years",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-4y-to-5y",
|
||||
name: "4y..5y",
|
||||
title: "Between 4 Years and 5 Years",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-5y-to-7y",
|
||||
name: "5y..7y",
|
||||
title: "Between 5 Years and 7 Years",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-7y-to-10y",
|
||||
name: "7y..10y",
|
||||
title: "Between 7 Years and 10 Years",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-10y-to-15y",
|
||||
name: "10y..15y",
|
||||
title: "Between 10 Years and 15 Years",
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Epoch",
|
||||
tree: [
|
||||
@@ -1615,74 +1688,79 @@ function createPartialOptions(colors) {
|
||||
name: "size",
|
||||
tree: [
|
||||
createUTXOGroupFolder({
|
||||
key: "from-1sat-10sats",
|
||||
key: "0sat",
|
||||
name: "0sat",
|
||||
title: "0 sat",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-1sat-to-10sats",
|
||||
name: "1sat..10sats",
|
||||
title: "UTXOs from 1 sat to 10 sats",
|
||||
title: "From 1 sat to 10 sats",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-10sats-100sats",
|
||||
key: "from-10sats-to-100sats",
|
||||
name: "10sat..100sats",
|
||||
title: "UTXOs from 10 sats to 100 sats",
|
||||
title: "From 10 sats to 100 sats",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-100sats-1-000sats",
|
||||
key: "from-100sats-to-1-000sats",
|
||||
name: "100sat..1_000sats",
|
||||
title: "UTXOs from 100 sats to 1,000 sats",
|
||||
title: "From 100 sats to 1,000 sats",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-1-000sats-10-000sats",
|
||||
key: "from-1-000sats-to-10-000sats",
|
||||
name: "1_000sat..10_000sats",
|
||||
title: "UTXOs from 1,000 sats to 10,000 sats",
|
||||
title: "From 1,000 sats to 10,000 sats",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-10-000sats-100-000sats",
|
||||
key: "from-10-000sats-to-100-000sats",
|
||||
name: "10_000sat..100_000sats",
|
||||
title: "UTXOs from 10,000 sats to 100,000 sats",
|
||||
title: "From 10,000 sats to 100,000 sats",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-100-000sats-1-000-000sats",
|
||||
key: "from-100-000sats-to-1-000-000sats",
|
||||
name: "100_000sat..1_000_000sats",
|
||||
title: "UTXOs from 100,000 sats to 1,000,000 sats",
|
||||
title: "From 100,000 sats to 1,000,000 sats",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-1-000-000sats-10-000-000sats",
|
||||
key: "from-1-000-000sats-to-10-000-000sats",
|
||||
name: "1_000_000sat..10_000_000sats",
|
||||
title: "UTXOs from 1,000,000 sats to 10,000,000 sats",
|
||||
title: "From 1,000,000 sats to 10,000,000 sats",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-10-000-000sats-1btc",
|
||||
key: "from-10-000-000sats-to-1btc",
|
||||
name: "10_000_000sat..1btc",
|
||||
title: "UTXOs from 10,000,000 sats to 1 BTC",
|
||||
title: "From 10,000,000 sats to 1 BTC",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-1btc-10btc",
|
||||
key: "from-1btc-to-10btc",
|
||||
name: "1btc..10btc",
|
||||
title: "UTXOs from 1 BTC to 10 BTC",
|
||||
title: "From 1 BTC to 10 BTC",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-10btc-100btc",
|
||||
key: "from-10btc-to-100btc",
|
||||
name: "10btc..100btc",
|
||||
title: "UTXOs from 10 BTC to 100 BTC",
|
||||
title: "From 10 BTC to 100 BTC",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-100btc-1-000btc",
|
||||
key: "from-100btc-to-1-000btc",
|
||||
name: "100btc..1_000btc",
|
||||
title: "UTXOs from 100 BTC to 1,000 BTC",
|
||||
title: "From 100 BTC to 1,000 BTC",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-1-000btc-10-000btc",
|
||||
key: "from-1-000btc-to-10-000btc",
|
||||
name: "1_000btc..10_000btc",
|
||||
title: "UTXOs from 1,000 BTC to 10,000 BTC",
|
||||
title: "From 1,000 BTC to 10,000 BTC",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-10-000btc-100-000btc",
|
||||
key: "from-10-000btc-to-100-000btc",
|
||||
name: "10_000btc..100_000btc",
|
||||
title: "UTXOs from 10,000 BTC to 100,000 BTC",
|
||||
title: "From 10,000 BTC to 100,000 BTC",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "from-100-000btc",
|
||||
name: "100_000btc..inf",
|
||||
title: "UTXOs from 100,000 BTC",
|
||||
name: "100_000btc+",
|
||||
title: "From 100,000 BTC",
|
||||
}),
|
||||
],
|
||||
},
|
||||
@@ -1739,6 +1817,11 @@ function createPartialOptions(colors) {
|
||||
name: "unknown",
|
||||
title: "Pay To Unknown",
|
||||
}),
|
||||
createUTXOGroupFolder({
|
||||
key: "empty",
|
||||
name: "empty",
|
||||
title: "Pay To Empty",
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user