diff --git a/Cargo.lock b/Cargo.lock index 28d29a5e5..dbe0f71d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -202,6 +202,12 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.5.0" @@ -650,9 +656,9 @@ dependencies = [ [[package]] name = "brk_rmcp" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34e99c51043db05e5d77c381124c1705c9a360f9a88bef0af44397134929d730" +checksum = "5788307976c7fbc3b549b56c70fd6b1893d609e08e82d470d6938b748742cf54" dependencies = [ "base64 0.22.1", "brk_rmcp-macros", @@ -680,9 +686,9 @@ dependencies = [ [[package]] name = "brk_rmcp-macros" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19a9e21ea5789ad190ce5c572bdbba50e589f9dd01acd19600b86442b56f02d" +checksum = "8b49ac541e14b18e43696144176faeabc547ce198cb10d575c13fcc6245d337c" dependencies = [ "darling 0.21.2", "proc-macro2", @@ -2047,19 +2053,21 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" dependencies = [ + "atomic-waker", "bytes", "futures-channel", - "futures-util", + "futures-core", "http", "http-body", "httparse", "httpdate", "itoa", "pin-project-lite", + "pin-utils", "smallvec", "tokio", ] @@ -3065,9 +3073,9 @@ dependencies = [ [[package]] name = "oxc_sourcemap" -version = "4.0.5" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6057a9bbd4a84bb4146539123642ee66e0f5ac700b0fcddd193cabcb2e0460" +checksum = "d5e78344e5a6cdd74250bc9bb144a4c3215b6107fe4fd47973f4bd175372ccb2" dependencies = [ "base64-simd", "rustc-hash", @@ -3863,7 +3871,9 @@ checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" [[package]] name = "seqdb" -version = "0.2.0" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567d567faf0a305d66eb0419fc50ba8faec58a3baa8624d7a1fd1c798395044c" dependencies = [ "libc", "log", @@ -4688,7 +4698,9 @@ checksum = "8f54a172d0620933a27a4360d3db3e2ae0dd6cceae9730751a036bbf182c4b23" [[package]] name = "vecdb" -version = "0.2.0" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "236493fb96b34fe7900a3bf62cbb1bd1c5991bc9db563dbbe7ce5cc8c3037cb1" dependencies = [ "ctrlc", "log", @@ -4706,7 +4718,9 @@ dependencies = [ [[package]] name = "vecdb_derive" -version = "0.2.0" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d117eb4f82c996a7de2dd5bca1f53da20fa39ae97646405af29eccde67be041" dependencies = [ "quote", "syn 2.0.106", diff --git a/Cargo.toml b/Cargo.toml index dabe0883e..98845f42d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,8 +52,8 @@ serde_bytes = "0.11.17" serde_derive = "1.0.219" serde_json = { version = "1.0.142", features = ["float_roundtrip"] } tokio = { version = "1.47.1", features = ["rt-multi-thread"] } -vecdb = { path = "../seqdb/crates/vecdb", features = ["derive"]} -# vecdb = { version = "0.1.2", features = ["derive"]} +# vecdb = { path = "../seqdb/crates/vecdb", features = ["derive"]} +vecdb = { version = "0.2.4", features = ["derive"]} zerocopy = "0.8.26" zerocopy-derive = "0.8.26" diff --git a/crates/brk_computer/examples/price_to_amount.rs b/crates/brk_computer/examples/price_to_amount.rs new file mode 100644 index 000000000..2e6ed376b --- /dev/null +++ b/crates/brk_computer/examples/price_to_amount.rs @@ -0,0 +1,15 @@ +use std::path::Path; + +use brk_computer::PriceToAmount; +use brk_error::Result; +use brk_structs::Height; + +pub fn main() -> Result<()> { + let path = Path::new(&std::env::var("HOME").unwrap()) + .join(".brk") + .join("computed/stateful/states"); + let mut price_to_amount = PriceToAmount::create(&path, "addrs_above_1btc_under_10btc"); + dbg!(price_to_amount.import_at_or_before(Height::new(890000))?); + dbg!(price_to_amount); + Ok(()) +} diff --git a/crates/brk_computer/src/lib.rs b/crates/brk_computer/src/lib.rs index c609f9839..d694000d8 100644 --- a/crates/brk_computer/src/lib.rs +++ b/crates/brk_computer/src/lib.rs @@ -26,6 +26,7 @@ mod utils; use indexes::Indexes; +pub use states::PriceToAmount; use states::*; #[derive(Clone)] @@ -79,7 +80,6 @@ impl Computer { Format::Compressed, &indexes, price.as_ref(), - &computed_path.join("states"), )?, transactions: transactions::Vecs::forced_import( &computed_path, diff --git a/crates/brk_computer/src/stateful/address_cohort.rs b/crates/brk_computer/src/stateful/address_cohort.rs index 412877b7e..be0a6e77f 100644 --- a/crates/brk_computer/src/stateful/address_cohort.rs +++ b/crates/brk_computer/src/stateful/address_cohort.rs @@ -88,26 +88,26 @@ impl Vecs { } impl DynCohortVecs for Vecs { - fn starting_height(&self) -> Height { + fn min_height_vecs_len(&self) -> usize { [ - self.height_to_address_count.len().into(), - self.inner.starting_height(), + self.height_to_address_count.len(), + self.inner.min_height_vecs_len(), ] .into_iter() .min() .unwrap() } - fn set_starting_height(&mut self, starting_height: Height) { - self.starting_height = Some(starting_height); + fn reset_state_starting_height(&mut self) { + self.starting_height = Some(Height::ZERO); } - fn import_state_at(&mut self, starting_height: Height) -> Result<()> { - if starting_height > self.starting_height() { - unreachable!() - } + fn import_state(&mut self, starting_height: Height) -> Result { + let starting_height = self + .inner + .import_state(starting_height, &mut self.state.as_mut().unwrap().inner)?; - self.set_starting_height(starting_height); + self.starting_height = Some(starting_height); if let Some(prev_height) = starting_height.decremented() { self.state.as_mut().unwrap().address_count = *self @@ -116,10 +116,7 @@ impl DynCohortVecs for Vecs { .unwrap_get_inner(prev_height); } - self.inner.import_state_at( - self.starting_height.unwrap(), - &mut self.state.as_mut().unwrap().inner, - ) + Ok(starting_height) } fn validate_computed_versions(&mut self, base_version: Version) -> Result<()> { diff --git a/crates/brk_computer/src/stateful/common.rs b/crates/brk_computer/src/stateful/common.rs index 07ab8f8b7..a6147aeed 100644 --- a/crates/brk_computer/src/stateful/common.rs +++ b/crates/brk_computer/src/stateful/common.rs @@ -973,7 +973,7 @@ impl Vecs { }) } - pub fn starting_height(&self) -> Height { + pub fn min_height_vecs_len(&self) -> usize { [ self.height_to_supply.len(), self.height_to_utxo_count.len(), @@ -1023,17 +1023,20 @@ impl Vecs { self.height_to_satblocks_destroyed.len(), ] .into_iter() - .map(Height::from) .min() .unwrap() } - pub fn import_state_at( + pub fn import_state( &mut self, starting_height: Height, state: &mut CohortState, - ) -> Result<()> { - if let Some(prev_height) = starting_height.decremented() { + ) -> Result { + if let Some(mut prev_height) = starting_height.decremented() { + if self.height_to_realized_cap.as_mut().is_some() { + prev_height = state.import_at_or_before(prev_height)?; + } + state.supply.value = self .height_to_supply .into_iter() @@ -1047,10 +1050,9 @@ impl Vecs { state.realized.as_mut().unwrap().cap = height_to_realized_cap .into_iter() .unwrap_get_inner(prev_height); - - state.import_at(prev_height)?; } - Ok(()) + + Ok(prev_height.incremented()) } else { Err(Error::Str("Unset")) } diff --git a/crates/brk_computer/src/stateful/mod.rs b/crates/brk_computer/src/stateful/mod.rs index 6e6fc93d6..968bacc7a 100644 --- a/crates/brk_computer/src/stateful/mod.rs +++ b/crates/brk_computer/src/stateful/mod.rs @@ -1,4 +1,10 @@ -use std::{cmp::Ordering, collections::BTreeMap, mem, path::Path, thread}; +use std::{ + cmp::Ordering, + collections::{BTreeMap, BTreeSet}, + mem, + path::Path, + thread, +}; use brk_error::Result; use brk_indexer::Indexer; @@ -87,19 +93,19 @@ impl Vecs { format: Format, indexes: &indexes::Vecs, price: Option<&price::Vecs>, - states_path: &Path, ) -> Result { - let db = Database::open(&parent.join("stateful"))?; + let db_path = parent.join("stateful"); + let states_path = db_path.join("states"); + + let db = Database::open(&db_path)?; db.set_min_len(PAGE_SIZE * 20_000_000)?; db.set_min_regions(50_000)?; let compute_dollars = price.is_some(); - let chain_db = Database::open(&parent.join("chain"))?; - Ok(Self { chain_state: RawVec::forced_import_with( - ImportOptions::new(&chain_db, "chain", version + VERSION + Version::ZERO) + ImportOptions::new(&db, "chain", version + VERSION + Version::ZERO) .with_saved_stamped_changes(SAVED_STAMPED_CHANGES), )?, @@ -377,7 +383,7 @@ impl Vecs { format, indexes, price, - states_path, + &states_path, )?, address_cohorts: address_cohorts::Vecs::forced_import( &db, @@ -385,7 +391,7 @@ impl Vecs { format, indexes, price, - states_path, + &states_path, )?, p2aaddressindex_to_anyaddressindex: RawVec::forced_import_with( @@ -558,17 +564,16 @@ impl Vecs { base_version + self.height_to_opreturn_supply.inner_version(), )?; - let mut chain_state: Vec = vec![]; let mut chain_state_starting_height = Height::from(self.chain_state.len()); let stateful_starting_height = match separate_utxo_vecs .par_iter_mut() - .map(|(_, v)| v.starting_height()) + .map(|(_, v)| Height::from(v.min_height_vecs_len())) .min() .unwrap_or_default() .min( separate_address_vecs .par_iter_mut() - .map(|(_, v)| v.starting_height()) + .map(|(_, v)| Height::from(v.min_height_vecs_len())) .min() .unwrap_or_default(), ) @@ -588,7 +593,82 @@ impl Vecs { .cmp(&chain_state_starting_height) { Ordering::Greater => unreachable!(), - Ordering::Equal => { + Ordering::Equal => chain_state_starting_height, + Ordering::Less => Height::ZERO, + }; + + // dbg!(stateful_starting_height); + // let stateful_starting_height = stateful_starting_height + // .checked_sub(Height::new(1)) + // .unwrap_or_default(); + // dbg!(stateful_starting_height); + + let starting_height = starting_indexes.height.min(stateful_starting_height); + // dbg!(starting_height); + let last_height = Height::from(indexer.vecs.height_to_blockhash.stamp()); + // dbg!(last_height); + if starting_height <= last_height { + // dbg!(starting_height); + + let starting_height = if starting_height.is_not_zero() { + let mut set = separate_utxo_vecs + .iter_mut() + .map(|(_, v)| v.import_state(starting_height).unwrap_or_default()) + .collect::>(); + if set.len() == 1 { + set.pop_first().unwrap() + } else { + Height::ZERO + } + } else { + Height::ZERO + }; + // dbg!(starting_height); + + let starting_height = if starting_height.is_not_zero() + && separate_address_vecs + .iter_mut() + .map(|(_, v)| v.import_state(starting_height).unwrap_or_default()) + .chain( + [ + self.chain_state.rollback_before(starting_height.into())?, + self.p2pk33addressindex_to_anyaddressindex + .rollback_before(starting_height.into())?, + self.p2pk65addressindex_to_anyaddressindex + .rollback_before(starting_height.into())?, + self.p2pkhaddressindex_to_anyaddressindex + .rollback_before(starting_height.into())?, + self.p2shaddressindex_to_anyaddressindex + .rollback_before(starting_height.into())?, + self.p2traddressindex_to_anyaddressindex + .rollback_before(starting_height.into())?, + self.p2wpkhaddressindex_to_anyaddressindex + .rollback_before(starting_height.into())?, + self.p2wshaddressindex_to_anyaddressindex + .rollback_before(starting_height.into())?, + self.p2aaddressindex_to_anyaddressindex + .rollback_before(starting_height.into())?, + self.loadedaddressindex_to_loadedaddressdata + .rollback_before(starting_height.into())?, + self.emptyaddressindex_to_emptyaddressdata + .rollback_before(starting_height.into())?, + ] + .into_iter() + .map(Height::from) + .map(Height::incremented), + ) + .all(|h| h == starting_height) + { + starting_height + } else { + Height::ZERO + }; + + // dbg!(starting_height); + // std::process::exit(0); + + let mut chain_state: Vec; + if starting_height.is_not_zero() { chain_state = self .chain_state .collect_range(None, None)? @@ -607,33 +687,10 @@ impl Vecs { } }) .collect::>(); - chain_state_starting_height - } - Ordering::Less => Height::ZERO, - }; - - let starting_height = starting_indexes.height.min(stateful_starting_height); - let last_height = Height::from(indexer.vecs.height_to_blockhash.stamp()); - if starting_height <= last_height { - let starting_height = if separate_utxo_vecs - .par_iter_mut() - .try_for_each(|(_, v)| v.import_state_at(starting_height)) - .is_err() - || separate_address_vecs - .par_iter_mut() - .try_for_each(|(_, v)| v.import_state_at(starting_height)) - .is_err() - { - Height::ZERO } else { - starting_height - }; - - if starting_height.is_zero() { info!("Starting processing utxos from the start"); chain_state = vec![]; - chain_state_starting_height = Height::ZERO; self.p2pk33addressindex_to_anyaddressindex.reset()?; self.p2pk65addressindex_to_anyaddressindex.reset()?; @@ -647,18 +704,20 @@ impl Vecs { self.emptyaddressindex_to_emptyaddressdata.reset()?; separate_utxo_vecs.par_iter_mut().try_for_each(|(_, v)| { - v.set_starting_height(starting_height); + v.reset_state_starting_height(); v.state.as_mut().unwrap().reset_price_to_amount_if_needed() })?; separate_address_vecs .par_iter_mut() .try_for_each(|(_, v)| { - v.set_starting_height(starting_height); + v.reset_state_starting_height(); v.state.as_mut().unwrap().reset_price_to_amount_if_needed() })?; } + chain_state_starting_height = starting_height; + starting_indexes.update_from_height(starting_height, indexes); let inputindex_to_outputindex_reader = inputindex_to_outputindex.create_reader(); @@ -971,7 +1030,7 @@ impl Vecs { } height_to_addresstype_to_typedindex_to_data - .entry(height) + .entry(prev_height) .or_default() .get_mut(output_type) .unwrap() diff --git a/crates/brk_computer/src/stateful/trait.rs b/crates/brk_computer/src/stateful/trait.rs index 5dac1499d..f5bf37835 100644 --- a/crates/brk_computer/src/stateful/trait.rs +++ b/crates/brk_computer/src/stateful/trait.rs @@ -6,10 +6,10 @@ use vecdb::{AnyCollectableVec, AnyIterableVec, Exit}; use crate::{Indexes, indexes, market, price}; pub trait DynCohortVecs: Send + Sync { - fn starting_height(&self) -> Height; - fn set_starting_height(&mut self, starting_height: Height); + fn min_height_vecs_len(&self) -> usize; + fn reset_state_starting_height(&mut self); - fn import_state_at(&mut self, starting_height: Height) -> Result<()>; + fn import_state(&mut self, starting_height: Height) -> Result; fn validate_computed_versions(&mut self, base_version: Version) -> Result<()>; diff --git a/crates/brk_computer/src/stateful/utxo_cohort.rs b/crates/brk_computer/src/stateful/utxo_cohort.rs index 023f7a62a..d4e12abfe 100644 --- a/crates/brk_computer/src/stateful/utxo_cohort.rs +++ b/crates/brk_computer/src/stateful/utxo_cohort.rs @@ -15,7 +15,7 @@ use crate::{ #[derive(Clone)] pub struct Vecs { - starting_height: Option, + state_starting_height: Option, pub state: Option, @@ -39,7 +39,7 @@ impl Vecs { let compute_dollars = price.is_some(); Ok(Self { - starting_height: None, + state_starting_height: None, state: states_path.map(|states_path| { UTXOCohortState::new( @@ -65,23 +65,22 @@ impl Vecs { } impl DynCohortVecs for Vecs { - fn starting_height(&self) -> Height { - self.inner.starting_height() + fn min_height_vecs_len(&self) -> usize { + self.inner.min_height_vecs_len() } - fn set_starting_height(&mut self, starting_height: Height) { - self.starting_height = Some(starting_height); + fn reset_state_starting_height(&mut self) { + self.state_starting_height = Some(Height::ZERO); } - fn import_state_at(&mut self, starting_height: Height) -> Result<()> { - if starting_height > self.starting_height() { - unreachable!() - } + fn import_state(&mut self, starting_height: Height) -> Result { + let starting_height = self + .inner + .import_state(starting_height, self.state.as_mut().unwrap())?; - self.set_starting_height(starting_height); + self.state_starting_height = Some(starting_height); - self.inner - .import_state_at(self.starting_height.unwrap(), self.state.as_mut().unwrap()) + Ok(starting_height) } fn validate_computed_versions(&mut self, base_version: Version) -> Result<()> { @@ -89,7 +88,7 @@ impl DynCohortVecs for Vecs { } fn forced_pushed_at(&mut self, height: Height, exit: &Exit) -> Result<()> { - if self.starting_height.unwrap() > height { + if self.state_starting_height.unwrap() > height { return Ok(()); } diff --git a/crates/brk_computer/src/states/block.rs b/crates/brk_computer/src/states/block.rs index 27aaad538..89f0bf6e7 100644 --- a/crates/brk_computer/src/states/block.rs +++ b/crates/brk_computer/src/states/block.rs @@ -1,13 +1,17 @@ use std::ops::{Add, AddAssign, SubAssign}; use brk_structs::{Dollars, Timestamp}; +use serde::Serialize; use super::SupplyState; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize)] pub struct BlockState { + #[serde(flatten)] pub supply: SupplyState, + #[serde(skip)] pub price: Option, + #[serde(skip)] pub timestamp: Timestamp, } diff --git a/crates/brk_computer/src/states/cohorts/common.rs b/crates/brk_computer/src/states/cohorts/common.rs index 36c9e6650..243ffc0d1 100644 --- a/crates/brk_computer/src/states/cohorts/common.rs +++ b/crates/brk_computer/src/states/cohorts/common.rs @@ -27,11 +27,12 @@ impl CohortState { } } - pub fn import_at(&mut self, height: Height) -> Result<()> { + pub fn import_at_or_before(&mut self, height: Height) -> Result { if let Some(price_to_amount) = self.price_to_amount.as_mut() { - price_to_amount.import_at(height)?; + price_to_amount.import_at_or_before(height) + } else { + Ok(height) } - Ok(()) } pub fn reset_price_to_amount_if_needed(&mut self) -> Result<()> { diff --git a/crates/brk_computer/src/states/price_to_amount.rs b/crates/brk_computer/src/states/price_to_amount.rs index 868c5d946..49f44106d 100644 --- a/crates/brk_computer/src/states/price_to_amount.rs +++ b/crates/brk_computer/src/states/price_to_amount.rs @@ -4,7 +4,7 @@ use std::{ path::{Path, PathBuf}, }; -use brk_error::Result; +use brk_error::{Error, Result}; use brk_structs::{Dollars, Height, Sats}; use derive_deref::{Deref, DerefMut}; use pco::standalone::{simple_decompress, simpler_compress}; @@ -30,9 +30,14 @@ impl PriceToAmount { } } - pub fn import_at(&mut self, height: Height) -> Result<()> { - self.state = Some(State::deserialize(&fs::read(self.path_state(height))?)?); - Ok(()) + pub fn import_at_or_before(&mut self, height: Height) -> Result { + let files = self.read_dir(None)?; + let (&height, path) = files + .range(..=height) + .next_back() + .ok_or(Error::Str("Not found"))?; + self.state = Some(State::deserialize(&fs::read(path)?)?); + Ok(height) } pub fn iter(&self) -> impl Iterator { @@ -77,27 +82,28 @@ impl PriceToAmount { Ok(()) } - pub fn flush(&mut self, height: Height) -> Result<()> { - let files: BTreeMap = fs::read_dir(&self.pathbuf)? + fn read_dir(&self, keep_only_before: Option) -> Result> { + Ok(fs::read_dir(&self.pathbuf)? .filter_map(|entry| { let path = entry.ok()?.path(); let name = path.file_name()?.to_str()?; - if let Some(height_str) = name.strip_prefix(STATE_AT_) { - if let Ok(h) = height_str.parse::().map(Height::from) { - if h < height { - Some((h, path)) - } else { - let _ = fs::remove_file(path); - None - } + let height_str = name.strip_prefix(STATE_AT_).unwrap_or(name); + if let Ok(h) = height_str.parse::().map(Height::from) { + if keep_only_before.is_none_or(|height| h < height) { + Some((h, path)) } else { + let _ = fs::remove_file(path); None } } else { None } }) - .collect(); + .collect::>()) + } + + pub fn flush(&mut self, height: Height) -> Result<()> { + let files = self.read_dir(Some(height))?; for (_, path) in files .iter() @@ -118,7 +124,7 @@ impl PriceToAmount { Self::path_state_(&self.pathbuf, height) } fn path_state_(path: &Path, height: Height) -> PathBuf { - path.join(format!("{STATE_AT_}{}", height)) + path.join(u32::from(height).to_string()) } } @@ -130,6 +136,7 @@ const COMPRESSION_LEVEL: usize = 4; impl State { fn serialize(&self) -> vecdb::Result> { let keys: Vec = self.keys().cloned().map(f64::from).collect(); + let values: Vec = self.values().cloned().map(u64::from).collect(); let compressed_keys = simpler_compress(&keys, COMPRESSION_LEVEL)?; diff --git a/crates/brk_mcp/Cargo.toml b/crates/brk_mcp/Cargo.toml index 446e98a75..d9ce8657c 100644 --- a/crates/brk_mcp/Cargo.toml +++ b/crates/brk_mcp/Cargo.toml @@ -13,7 +13,7 @@ build = "build.rs" axum = { workspace = true } brk_interface = { workspace = true } log = { workspace = true } -brk_rmcp = { version = "0.5.0", features = [ +brk_rmcp = { version = "0.6.0", features = [ "transport-worker", "transport-streamable-http-server", ] } diff --git a/crates/brk_parser/examples/main.rs b/crates/brk_parser/examples/main.rs index 613258856..bd5271ec6 100644 --- a/crates/brk_parser/examples/main.rs +++ b/crates/brk_parser/examples/main.rs @@ -28,10 +28,11 @@ fn main() -> Result<()> { println!("{height}: {hash}"); }); + let block_0 = parser.get(Height::new(0)); + println!( "{}", - parser - .get(Height::new(0)) + block_0 .txdata .first() .unwrap() @@ -41,10 +42,11 @@ fn main() -> Result<()> { .script_pubkey ); + let block_840_000 = parser.get(Height::new(840_000)); + println!( "{}", - parser - .get(Height::new(840_000)) + block_840_000 .txdata .first() .unwrap() diff --git a/crates/brk_structs/src/structs/cents.rs b/crates/brk_structs/src/structs/cents.rs index 74892a6f3..720ba67e4 100644 --- a/crates/brk_structs/src/structs/cents.rs +++ b/crates/brk_structs/src/structs/cents.rs @@ -24,20 +24,18 @@ use super::Dollars; )] pub struct Cents(i64); -const SIGNIFICANT_DIGITS: i32 = 4; - impl Cents { pub const fn mint(value: i64) -> Self { Self(value) } - pub fn round_to_4_digits(self) -> Self { + pub fn round_to(self, digits: i32) -> Self { let v = self.0; let ilog10 = v.checked_ilog10().unwrap_or(0) as i32; - Self::from(if ilog10 >= SIGNIFICANT_DIGITS { - let log_diff = ilog10 - SIGNIFICANT_DIGITS + 1; + Self::from(if ilog10 >= digits { + let log_diff = ilog10 - digits + 1; let pow = 10.0_f64.powi(log_diff); diff --git a/crates/brk_structs/src/structs/dollars.rs b/crates/brk_structs/src/structs/dollars.rs index 5e0719c90..95de0cad4 100644 --- a/crates/brk_structs/src/structs/dollars.rs +++ b/crates/brk_structs/src/structs/dollars.rs @@ -39,8 +39,12 @@ impl Dollars { Dollars((self.0 * 100.0).round() / 100.0) } - pub fn round_to_4_digits(self) -> Self { - Self::from(Cents::from(self).round_to_4_digits()) + pub fn round_to(self, digits: i32) -> Self { + Self::from(Cents::from(self).round_to(digits)) + } + + pub fn is_negative(&self) -> bool { + self.0 < 0.0 } } diff --git a/crates/brk_structs/src/structs/height.rs b/crates/brk_structs/src/structs/height.rs index 33aa58028..04fbd3ef3 100644 --- a/crates/brk_structs/src/structs/height.rs +++ b/crates/brk_structs/src/structs/height.rs @@ -66,6 +66,10 @@ impl Height { pub fn is_zero(self) -> bool { self == Self::ZERO } + + pub fn is_not_zero(self) -> bool { + self != Self::ZERO + } } impl PartialEq for Height { diff --git a/crates/brk_structs/src/structs/loadedaddressdata.rs b/crates/brk_structs/src/structs/loadedaddressdata.rs index 70803a275..4a61316c8 100644 --- a/crates/brk_structs/src/structs/loadedaddressdata.rs +++ b/crates/brk_structs/src/structs/loadedaddressdata.rs @@ -21,7 +21,17 @@ impl LoadedAddressData { } pub fn realized_price(&self) -> Dollars { - (self.realized_cap / Bitcoin::from(self.amount())).round_to_4_digits() + let p = (self.realized_cap / Bitcoin::from(self.amount())).round_to(4); + if p.is_negative() { + dbg!(( + self.realized_cap, + self.amount(), + Bitcoin::from(self.amount()), + p + )); + panic!(""); + } + p } #[inline] @@ -38,7 +48,12 @@ impl LoadedAddressData { self.received += amount; self.outputs_len += 1; if let Some(price) = price { - self.realized_cap += price * amount; + let added = price * amount; + self.realized_cap += added; + if added.is_negative() || self.realized_cap.is_negative() { + dbg!((self.realized_cap, price, amount, added)); + panic!(); + } } } @@ -49,10 +64,20 @@ impl LoadedAddressData { self.sent += amount; self.outputs_len -= 1; if let Some(previous_price) = previous_price { - self.realized_cap = self - .realized_cap - .checked_sub(previous_price * amount) - .unwrap(); + let subtracted = previous_price * amount; + let realized_cap = self.realized_cap.checked_sub(subtracted).unwrap(); + if self.realized_cap.is_negative() || realized_cap.is_negative() { + dbg!(( + self, + realized_cap, + previous_price, + amount, + previous_price * amount, + subtracted + )); + panic!(); + } + self.realized_cap = realized_cap; } Ok(()) } diff --git a/websites/default/packages/unpkg.sh b/websites/default/packages/unpkg.sh index 813e6359c..8ec1f1387 100755 --- a/websites/default/packages/unpkg.sh +++ b/websites/default/packages/unpkg.sh @@ -1,9 +1,5 @@ #!/bin/bash -# unpkg-downloader.sh - Download complete packages from unpkg.com -# Usage: ./unpkg-downloader.sh [output-dir] -# Example: ./unpkg-downloader.sh "@solidjs/signals" "0.4.1" - set -e # Colors for output @@ -407,4 +403,9 @@ main() { } # Run the main function with all arguments -main "$@" +# main "$@" + +main "@solidjs/signals" +main "@leeoniya/ufuzzy" +main "lean-qr" +main "lightweight-charts" diff --git a/websites/default/packages/update.sh b/websites/default/packages/update.sh deleted file mode 100755 index 56182daea..000000000 --- a/websites/default/packages/update.sh +++ /dev/null @@ -1,4 +0,0 @@ -./unpkg.sh "@solidjs/signals" -./unpkg.sh "@leeoniya/ufuzzy" -./unpkg.sh "lean-qr" -./unpkg.sh "lightweight-charts"