mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-22 12:23:04 -07:00
Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a98546f605 | |||
| 3567559d4e | |||
| 216476ee45 | |||
| 3fc28c07fb | |||
| 85f6ef063d | |||
| 1e71e2d68f | |||
| b24a29895f | |||
| 0167a2ae59 | |||
| 2c867103ca | |||
| 8c289df336 | |||
| 4489920cbf | |||
| 029a85081b | |||
| 1bc739d07f | |||
| c229e218f6 | |||
| a66f4ad4bd | |||
| 1dd687dab7 | |||
| 50ff6e2745 | |||
| 811dec713b | |||
| 617d6f4bd7 | |||
| 57cd2d6252 | |||
| ec64f8d048 | |||
| ed288a9dba | |||
| 27da0a4102 | |||
| 3c01ba1a76 | |||
| 252c8833ae | |||
| f45fb6efe6 | |||
| 8cc1f8d691 | |||
| bff22b5182 | |||
| d31d47eb32 | |||
| 5fe984c39d | |||
| 7f07b0daa7 | |||
| 6d35c26b3f | |||
| be4e693a27 | |||
| 5810276156 | |||
| d10ac3f87b | |||
| 9810bc09e9 | |||
| a0a13eb2a8 | |||
| 6e996797b8 | |||
| 663092b501 | |||
| 8ea13544de | |||
| e73daa6214 | |||
| cf92c60a01 | |||
| b7f51b03bc | |||
| 903e69ff77 | |||
| c4167ddaad | |||
| 50bfdb0d68 | |||
| a6cb09ff1c |
@@ -18,3 +18,8 @@ _*
|
||||
|
||||
# Logs
|
||||
.log
|
||||
|
||||
# Profiling
|
||||
profile.json.gz
|
||||
flamegraph.svg
|
||||
*.trace
|
||||
|
||||
Generated
+366
-236
File diff suppressed because it is too large
Load Diff
+26
-22
@@ -4,7 +4,7 @@ members = ["crates/*"]
|
||||
package.description = "The Bitcoin Research Kit is a suite of tools designed to extract, compute and display data stored on a Bitcoin Core node"
|
||||
package.license = "MIT"
|
||||
package.edition = "2024"
|
||||
package.version = "0.0.69"
|
||||
package.version = "0.0.78"
|
||||
package.homepage = "https://bitcoinresearchkit.org"
|
||||
package.repository = "https://github.com/bitcoinresearchkit/brk"
|
||||
|
||||
@@ -13,6 +13,10 @@ lto = "fat"
|
||||
codegen-units = 1
|
||||
panic = "abort"
|
||||
|
||||
[profile.profiling]
|
||||
inherits = "release"
|
||||
debug = true
|
||||
|
||||
[profile.dist]
|
||||
inherits = "release"
|
||||
|
||||
@@ -22,39 +26,39 @@ axum = "0.8.4"
|
||||
bincode = { version = "2.0.1", features = ["serde"] }
|
||||
bitcoin = { version = "0.32.6", features = ["serde"] }
|
||||
bitcoincore-rpc = "0.19.0"
|
||||
brk_bundler = { version = "0.0.69", path = "crates/brk_bundler" }
|
||||
brk_cli = { version = "0.0.69", path = "crates/brk_cli" }
|
||||
brk_computer = { version = "0.0.69", path = "crates/brk_computer" }
|
||||
brk_core = { version = "0.0.69", path = "crates/brk_core" }
|
||||
brk_exit = { version = "0.0.69", path = "crates/brk_exit" }
|
||||
brk_fetcher = { version = "0.0.69", path = "crates/brk_fetcher" }
|
||||
brk_indexer = { version = "0.0.69", path = "crates/brk_indexer" }
|
||||
brk_interface = { version = "0.0.69", path = "crates/brk_interface" }
|
||||
brk_logger = { version = "0.0.69", path = "crates/brk_logger" }
|
||||
brk_mcp = { version = "0.0.69", path = "crates/brk_mcp" }
|
||||
brk_parser = { version = "0.0.69", path = "crates/brk_parser" }
|
||||
brk_rmcp = { version = "0.1.7", features = ["transport-streamable-http-server", "transport-worker"]}
|
||||
brk_server = { version = "0.0.69", path = "crates/brk_server" }
|
||||
brk_state = { version = "0.0.69", path = "crates/brk_state" }
|
||||
brk_store = { version = "0.0.69", path = "crates/brk_store" }
|
||||
brk_vec = { version = "0.0.69", path = "crates/brk_vec" }
|
||||
brk_bundler = { version = "0.0.78", path = "crates/brk_bundler" }
|
||||
brk_cli = { version = "0.0.78", path = "crates/brk_cli" }
|
||||
brk_computer = { version = "0.0.78", path = "crates/brk_computer" }
|
||||
brk_core = { version = "0.0.78", path = "crates/brk_core" }
|
||||
brk_exit = { version = "0.0.78", path = "crates/brk_exit" }
|
||||
brk_fetcher = { version = "0.0.78", path = "crates/brk_fetcher" }
|
||||
brk_indexer = { version = "0.0.78", path = "crates/brk_indexer" }
|
||||
brk_interface = { version = "0.0.78", path = "crates/brk_interface" }
|
||||
brk_logger = { version = "0.0.78", path = "crates/brk_logger" }
|
||||
brk_mcp = { version = "0.0.78", path = "crates/brk_mcp" }
|
||||
brk_parser = { version = "0.0.78", path = "crates/brk_parser" }
|
||||
brk_rmcp = { version = "0.2.1", features = ["transport-streamable-http-server", "transport-worker"]}
|
||||
# brk_rmcp = { path = "../rust-sdk/crates/rmcp", features = ["transport-streamable-http-server", "transport-worker"]}
|
||||
brk_server = { version = "0.0.78", path = "crates/brk_server" }
|
||||
brk_store = { version = "0.0.78", path = "crates/brk_store" }
|
||||
brk_vec = { version = "0.0.78", path = "crates/brk_vec" }
|
||||
byteview = "=0.6.1"
|
||||
clap = { version = "4.5.40", features = ["string"] }
|
||||
clap_derive = "4.5.40"
|
||||
clap = { version = "4.5.41", features = ["string"] }
|
||||
clap_derive = "4.5.41"
|
||||
color-eyre = "0.6.5"
|
||||
derive_deref = "1.1.1"
|
||||
fjall = "2.11.1"
|
||||
jiff = "0.2.15"
|
||||
log = { version = "0.4.27" }
|
||||
minreq = { version = "2.13.4", features = ["https", "serde_json"] }
|
||||
minreq = { version = "2.14.0", features = ["https", "serde_json"] }
|
||||
rayon = "1.10.0"
|
||||
schemars = "1.0.0"
|
||||
schemars = "1.0.4"
|
||||
serde = { version = "1.0.219" }
|
||||
serde_bytes = "0.11.17"
|
||||
serde_derive = "1.0.219"
|
||||
serde_json = { version = "1.0.140", features = ["float_roundtrip"] }
|
||||
tabled = "0.20.0"
|
||||
tokio = { version = "1.45.1", features = ["rt-multi-thread"] }
|
||||
tokio = { version = "1.46.1", features = ["rt-multi-thread"] }
|
||||
zerocopy = { version = "0.8.26" }
|
||||
zerocopy-derive = "0.8.26"
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ The toolkit can be used in various ways to accommodate as many needs as possible
|
||||
It has a wide range of functionalities including charts, tables and simulations which you can visit for free and without the need for an account. \
|
||||
Also available at: [kibo.money](https://kibo.money) // [satonomics.xyz](https://satonomics.xyz)
|
||||
- **[API](https://github.com/bitcoinresearchkit/brk/tree/main/crates/brk_server#brk-server)** \
|
||||
Researchers and developers are free to use BRK's public API with  dataset variants at their disposal. \
|
||||
Researchers and developers are free to use BRK's public API with  dataset variants at their disposal. \
|
||||
Just like the website, it's entirely free, with no authentication or rate-limiting.
|
||||
- **[AI](https://github.com/bitcoinresearchkit/brk/blob/main/crates/brk_mcp/README.md#brk-mcp)** \
|
||||
LLMs have to possibility to connect to BRK's backend through a [MCP](https://modelcontextprotocol.io/introduction). \
|
||||
@@ -73,7 +73,6 @@ In contrast, existing alternatives tend to be either [very costly](https://studi
|
||||
- [`brk_parser`](https://crates.io/crates/brk_parser): A very fast Bitcoin Core block parser and iterator built on top of bitcoin-rust
|
||||
- [`brk_interface`](https://crates.io/crates/brk_interface): An interface to BRK's engine
|
||||
- [`brk_server`](https://crates.io/crates/brk_server): A server that serves Bitcoin data and swappable front-ends, built on top of `brk_indexer`, `brk_fetcher` and `brk_computer`
|
||||
- [`brk_state`](https://crates.io/crates/brk_state): Various states used mainly by the computer
|
||||
- [`brk_store`](https://crates.io/crates/brk_store): A thin wrapper around [`fjall`](https://crates.io/crates/fjall)
|
||||
- [`brk_vec`](https://crates.io/crates/brk_vec): A push-only, truncable, compressable, saveable Vec
|
||||
- [`brk_bundler`](https://crates.io/crates/brk_bundler): A thin wrapper around [`rolldown`](https://rolldown.rs/)
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
# TODO
|
||||
|
||||
- __crates__
|
||||
- _cli_
|
||||
- check disk space on first launch
|
||||
- add custom path support for config.toml
|
||||
- maybe add bitcoind download and launch support
|
||||
- via: https://github.com/rust-bitcoin/corepc/blob/master/node
|
||||
- test read/write speed, add warning if too low (<2gb/s)
|
||||
- pull latest version and notify is out of date
|
||||
- _computer_
|
||||
- **add rollback of states (in stateful)**
|
||||
- add support for per index computation
|
||||
- fix feerate which is always ZERO due to coinbase transaction
|
||||
- before computing multiple sources check their length, panic if not equal
|
||||
- add oracle price dataset (https://utxo.live/oracle/UTXOracle.py)
|
||||
- add address counts relative to all datasets
|
||||
- make decade, quarter, year datasets `computed` instead of `eager`
|
||||
- add 6 months (semester) interval datasets to builder
|
||||
- some datasets in `indexes` can probably be removed
|
||||
- add revived/sent supply datasets
|
||||
- add `in-sats` version of all price datasets (average and co)
|
||||
- add `p2pk` group (sum of `p2pk33` and `p2pk65`)
|
||||
- add chopiness datasets
|
||||
- add utxo count, address count, supply data for by reused addresses in groups by address type
|
||||
- add more date ranges (3-6 months and more)
|
||||
- add puell multiple dataset
|
||||
- add pi cycle dataset
|
||||
- add emas of price
|
||||
- add 7d and 30d ema to sell side risk ratio and sopr
|
||||
- don't compute everything for all cohorts as some datasets combinations are irrelevant
|
||||
- addresses/utxos by amount don't need mvrvz for example
|
||||
- add all possible charts from:
|
||||
- https://mainnet.observer
|
||||
- https://glassnode.com
|
||||
- https://checkonchain.com
|
||||
- https://researchbitcoin.net/exciting-update-coming-to-the-bitcoin-lab/
|
||||
- https://mempool.space/research
|
||||
- _indexer_
|
||||
- parse only the needed block number
|
||||
- maybe using https://developer.bitcoin.org/reference/rpc/getblockhash.html
|
||||
- _interface_
|
||||
- create pagination enum
|
||||
- from to
|
||||
- from option<count>
|
||||
- to option<count>
|
||||
- page + option<per page> default 1000 max 1000
|
||||
- from/to/count params don’t cap all combinations
|
||||
- example: from -10,000 count 10, won’t work if underlying vec isn’t 10k or more long
|
||||
- _parser_
|
||||
- save `vec` file instead of `json`
|
||||
- support lock file, process in read only if already opened in write mode
|
||||
- if less than X (10 maybe ?) get block using rpc instead of parsing the block files
|
||||
- _server_
|
||||
- api
|
||||
- add extensions support (.json .csv …)
|
||||
- if format instead of extension then don't download file
|
||||
- add support for https (rustls)
|
||||
- _vec_
|
||||
- add native lock file support (once it's available in stable rust)
|
||||
- improve compressed mode (slow reads)
|
||||
- add ema support
|
||||
- __docs__
|
||||
- _README_
|
||||
- add a comparison table with alternatives
|
||||
- add contribution section where help is needed
|
||||
- documentation/mcp/datasets/different front ends
|
||||
- add faq
|
||||
- __websites__
|
||||
- _default_
|
||||
- explorer
|
||||
- blocks
|
||||
- transactions
|
||||
- addresses
|
||||
- miners
|
||||
- maybe xpubs
|
||||
- charts
|
||||
- improve some names and colors
|
||||
- remove `sum` series when it's a duplicate of the `base` (in subsidy for example)
|
||||
- selected unit sometimes changes when going back end forth
|
||||
- add support for custom charts
|
||||
- separate z-score charts from "realized price" (with their own prices), have 4y, 2y and 1y
|
||||
- price scale format depends on unit, hide digits for sats for example (if/when possible)
|
||||
- table
|
||||
- pagination
|
||||
- exports (.json, .csv,…)
|
||||
- search
|
||||
- datasets add legend, and keywords ?
|
||||
- height/address/txid
|
||||
- api
|
||||
- add api page with interactivity
|
||||
- global
|
||||
- **fix navigation/history**
|
||||
- move share button to footer ?
|
||||
- Use `ichart.createPane()` in wrapper
|
||||
- improve behavior when local storage is unavailable
|
||||
- by having a global state
|
||||
- __global__
|
||||
- check `TODO`s in codebase
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 136 KiB After Width: | Height: | Size: 133 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 253 KiB After Width: | Height: | Size: 263 KiB |
@@ -21,7 +21,6 @@ full = [
|
||||
"parser",
|
||||
"interface",
|
||||
"server",
|
||||
"state",
|
||||
"store",
|
||||
"vec",
|
||||
]
|
||||
@@ -36,7 +35,6 @@ mcp = ["brk_mcp"]
|
||||
parser = ["brk_parser"]
|
||||
interface = ["brk_interface"]
|
||||
server = ["brk_server"]
|
||||
state = ["brk_state"]
|
||||
store = ["brk_store"]
|
||||
vec = ["brk_vec"]
|
||||
|
||||
@@ -53,7 +51,6 @@ brk_mcp = { workspace = true, optional = true }
|
||||
brk_parser = { workspace = true, optional = true }
|
||||
brk_interface = { workspace = true, optional = true }
|
||||
brk_server = { workspace = true, optional = true }
|
||||
brk_state = { workspace = true, optional = true }
|
||||
brk_store = { workspace = true, optional = true }
|
||||
brk_vec = { workspace = true, optional = true }
|
||||
|
||||
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
cargo build --profile profiling
|
||||
flamegraph -- ../../target/profiling/brk
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
cargo build --profile profiling
|
||||
samply record ../../target/profiling/brk
|
||||
@@ -47,10 +47,6 @@ pub use brk_interface as interface;
|
||||
#[doc(inline)]
|
||||
pub use brk_server as server;
|
||||
|
||||
#[cfg(feature = "state")]
|
||||
#[doc(inline)]
|
||||
pub use brk_state as state;
|
||||
|
||||
#[cfg(feature = "store")]
|
||||
#[doc(inline)]
|
||||
pub use brk_store as store;
|
||||
|
||||
@@ -9,7 +9,8 @@ repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
log = { workspace = true }
|
||||
notify = "8.0.0"
|
||||
brk_rolldown = "0.0.1"
|
||||
notify = "8.1.0"
|
||||
brk_rolldown = "0.1.1"
|
||||
# brk_rolldown = { path = "../../../rolldown/crates/rolldown"}
|
||||
sugar_path = "1.2.0"
|
||||
tokio = { workspace = true }
|
||||
|
||||
@@ -81,7 +81,7 @@ pub async fn bundle(websites_path: &Path, source_folder: &str, watch: bool) -> i
|
||||
let mut entry_watcher = notify::recommended_watcher(
|
||||
move |res: Result<notify::Event, notify::Error>| match res {
|
||||
Ok(_) => write_index_clone(),
|
||||
Err(e) => error!("watch error: {:?}", e),
|
||||
Err(e) => error!("watch error: {e:?}"),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
@@ -112,7 +112,7 @@ pub async fn bundle(websites_path: &Path, source_folder: &str, watch: bool) -> i
|
||||
let _ = fs::copy(&source_path, &dist_path);
|
||||
}
|
||||
}),
|
||||
Err(e) => error!("watch error: {:?}", e),
|
||||
Err(e) => error!("watch error: {e:?}"),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -24,7 +24,7 @@ color-eyre = { workspace = true }
|
||||
log = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
toml = "0.8.23"
|
||||
toml = "0.9.1"
|
||||
|
||||
[[bin]]
|
||||
name = "brk"
|
||||
|
||||
@@ -88,7 +88,7 @@ pub struct Config {
|
||||
#[arg(long, value_name = "SECONDS")]
|
||||
delay: Option<u64>,
|
||||
|
||||
/// Activate the Model Context Protocol (MCP) endpoint to give LLMs access to BRK (experimental), default: false, saved
|
||||
/// Activate the Model Context Protocol (MCP) endpoint to give LLMs access to BRK (experimental), default: true, saved
|
||||
#[serde(default, deserialize_with = "default_on_error")]
|
||||
#[arg(long, value_name = "BOOL")]
|
||||
mcp: Option<bool>,
|
||||
@@ -367,7 +367,7 @@ impl Config {
|
||||
}
|
||||
|
||||
pub fn mcp(&self) -> bool {
|
||||
self.mcp.is_some_and(|b| b)
|
||||
self.mcp.is_none_or(|b| b)
|
||||
}
|
||||
|
||||
pub fn watch(&self) -> bool {
|
||||
|
||||
@@ -8,6 +8,7 @@ homepage.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
bincode = { workspace = true }
|
||||
bitcoin = { workspace = true }
|
||||
bitcoincore-rpc = { workspace = true }
|
||||
brk_core = { workspace = true }
|
||||
@@ -16,10 +17,18 @@ brk_fetcher = { workspace = true }
|
||||
brk_indexer = { workspace = true }
|
||||
brk_logger = { workspace = true }
|
||||
brk_parser = { workspace = true }
|
||||
brk_state = { workspace = true }
|
||||
brk_store = { workspace = true }
|
||||
brk_vec = { workspace = true }
|
||||
color-eyre = { workspace = true }
|
||||
derive_deref = { workspace = true }
|
||||
either = "1.15.0"
|
||||
fjall = { workspace = true }
|
||||
jiff = { workspace = true }
|
||||
log = { workspace = true }
|
||||
rayon = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
zerocopy = { workspace = true }
|
||||
zerocopy-derive = { workspace = true }
|
||||
|
||||
[package.metadata.cargo-machete]
|
||||
ignored = ["zerocopy"]
|
||||
|
||||
@@ -13,7 +13,8 @@ pub fn main() -> color_eyre::Result<()> {
|
||||
|
||||
brk_logger::init(Some(Path::new(".log")));
|
||||
|
||||
let bitcoin_dir = default_bitcoin_path();
|
||||
// let bitcoin_dir = default_bitcoin_path();
|
||||
let bitcoin_dir = Path::new("/Volumes/WD_BLACK/bitcoin");
|
||||
|
||||
let rpc = Box::leak(Box::new(bitcoincore_rpc::Client::new(
|
||||
"http://localhost:8332",
|
||||
@@ -23,11 +24,11 @@ pub fn main() -> color_eyre::Result<()> {
|
||||
|
||||
// Can't increase main thread's stack programatically, thus we need to use another thread
|
||||
thread::Builder::new()
|
||||
.stack_size(32 * 1024 * 1024)
|
||||
.stack_size(256 * 1024 * 1024)
|
||||
.spawn(move || -> color_eyre::Result<()> {
|
||||
let parser = Parser::new(bitcoin_dir.join("blocks"), rpc);
|
||||
|
||||
let _outputs_dir = default_brk_path().join("outputs");
|
||||
let _outputs_dir = Path::new("/Volumes/WD_BLACK/brk").join("outputs");
|
||||
let outputs_dir = _outputs_dir.as_path();
|
||||
// let outputs_dir = Path::new("../../_outputs");
|
||||
|
||||
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
cargo build --profile profiling
|
||||
flamegraph -- ../../target/profiling/examples/main
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
cargo build --example main --profile profiling
|
||||
samply record ../../target/profiling/examples/main
|
||||
@@ -10,12 +10,14 @@ use brk_exit::Exit;
|
||||
use brk_fetcher::Fetcher;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{Computation, Format};
|
||||
use log::info;
|
||||
|
||||
mod states;
|
||||
mod stores;
|
||||
mod utils;
|
||||
mod vecs;
|
||||
|
||||
use log::info;
|
||||
use states::*;
|
||||
use stores::Stores;
|
||||
use vecs::Vecs;
|
||||
|
||||
@@ -66,7 +68,12 @@ impl Computer {
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
info!("Computing...");
|
||||
self.vecs
|
||||
.compute(indexer, starting_indexes, self.fetcher.as_mut(), exit)
|
||||
self.vecs.compute(
|
||||
indexer,
|
||||
starting_indexes,
|
||||
self.fetcher.as_mut(),
|
||||
exit,
|
||||
&mut self.stores,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{AddressData, Dollars, Height, Result, Sats};
|
||||
|
||||
use crate::SupplyState;
|
||||
|
||||
use super::CohortState;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AddressCohortState {
|
||||
pub address_count: usize,
|
||||
pub inner: CohortState,
|
||||
}
|
||||
|
||||
impl AddressCohortState {
|
||||
pub fn default_and_import(path: &Path, name: &str, compute_dollars: bool) -> Result<Self> {
|
||||
Ok(Self {
|
||||
address_count: 0,
|
||||
inner: CohortState::default_and_import(path, name, compute_dollars)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn height(&self) -> Option<Height> {
|
||||
self.inner.height()
|
||||
}
|
||||
|
||||
pub fn reset_price_to_amount(&mut self) -> Result<()> {
|
||||
self.inner.reset_price_to_amount()
|
||||
}
|
||||
|
||||
pub fn reset_single_iteration_values(&mut self) {
|
||||
self.inner.reset_single_iteration_values();
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn send(
|
||||
&mut self,
|
||||
addressdata: &mut AddressData,
|
||||
value: Sats,
|
||||
current_price: Option<Dollars>,
|
||||
prev_price: Option<Dollars>,
|
||||
blocks_old: usize,
|
||||
days_old: f64,
|
||||
older_than_hour: bool,
|
||||
) -> Result<()> {
|
||||
let compute_price = current_price.is_some();
|
||||
|
||||
let prev_realized_price = compute_price.then(|| addressdata.realized_price());
|
||||
let prev_supply_state = SupplyState {
|
||||
utxos: addressdata.outputs_len as usize,
|
||||
value: addressdata.amount(),
|
||||
};
|
||||
|
||||
addressdata.send(value, prev_price)?;
|
||||
|
||||
let supply_state = SupplyState {
|
||||
utxos: addressdata.outputs_len as usize,
|
||||
value: addressdata.amount(),
|
||||
};
|
||||
|
||||
self.inner.send_(
|
||||
&SupplyState { utxos: 1, value },
|
||||
current_price,
|
||||
prev_price,
|
||||
blocks_old,
|
||||
days_old,
|
||||
older_than_hour,
|
||||
compute_price.then(|| (addressdata.realized_price(), &supply_state)),
|
||||
prev_realized_price.map(|prev_price| (prev_price, &prev_supply_state)),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn receive(&mut self, address_data: &mut AddressData, value: Sats, price: Option<Dollars>) {
|
||||
let compute_price = price.is_some();
|
||||
|
||||
let prev_realized_price = compute_price.then(|| address_data.realized_price());
|
||||
let prev_supply_state = SupplyState {
|
||||
utxos: address_data.outputs_len as usize,
|
||||
value: address_data.amount(),
|
||||
};
|
||||
|
||||
address_data.receive(value, price);
|
||||
|
||||
let supply_state = SupplyState {
|
||||
utxos: address_data.outputs_len as usize,
|
||||
value: address_data.amount(),
|
||||
};
|
||||
|
||||
self.inner.receive_(
|
||||
&SupplyState { utxos: 1, value },
|
||||
price,
|
||||
compute_price.then(|| (address_data.realized_price(), &supply_state)),
|
||||
prev_realized_price.map(|prev_price| (prev_price, &prev_supply_state)),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn add(&mut self, addressdata: &AddressData) {
|
||||
self.address_count += 1;
|
||||
self.inner.increment_(
|
||||
&addressdata.into(),
|
||||
addressdata.realized_cap,
|
||||
addressdata.realized_price(),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn subtract(&mut self, addressdata: &AddressData) {
|
||||
self.address_count = self.address_count.checked_sub(1).unwrap();
|
||||
self.inner.decrement_(
|
||||
&addressdata.into(),
|
||||
addressdata.realized_cap,
|
||||
addressdata.realized_price(),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn commit(&mut self, height: Height) -> Result<()> {
|
||||
self.inner.commit(height)
|
||||
}
|
||||
}
|
||||
+114
-13
@@ -2,9 +2,7 @@ use std::{cmp::Ordering, path::Path};
|
||||
|
||||
use brk_core::{CheckedSub, Dollars, Height, Result, Sats};
|
||||
|
||||
use crate::{PriceToAmount, UnrealizedState};
|
||||
|
||||
use super::{RealizedState, SupplyState};
|
||||
use crate::{PriceToAmount, RealizedState, SupplyState, UnrealizedState};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CohortState {
|
||||
@@ -12,7 +10,8 @@ pub struct CohortState {
|
||||
pub realized: Option<RealizedState>,
|
||||
pub satblocks_destroyed: Sats,
|
||||
pub satdays_destroyed: Sats,
|
||||
pub price_to_amount: PriceToAmount,
|
||||
|
||||
price_to_amount: PriceToAmount,
|
||||
}
|
||||
|
||||
impl CohortState {
|
||||
@@ -26,6 +25,22 @@ impl CohortState {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn height(&self) -> Option<Height> {
|
||||
self.price_to_amount.height()
|
||||
}
|
||||
|
||||
pub fn reset_price_to_amount(&mut self) -> Result<()> {
|
||||
self.price_to_amount.reset()
|
||||
}
|
||||
|
||||
pub fn price_to_amount_first_key_value(&self) -> Option<(&Dollars, &Sats)> {
|
||||
self.price_to_amount.first_key_value()
|
||||
}
|
||||
|
||||
pub fn price_to_amount_last_key_value(&self) -> Option<(&Dollars, &Sats)> {
|
||||
self.price_to_amount.last_key_value()
|
||||
}
|
||||
|
||||
pub fn reset_single_iteration_values(&mut self) {
|
||||
self.satdays_destroyed = Sats::ZERO;
|
||||
self.satblocks_destroyed = Sats::ZERO;
|
||||
@@ -41,7 +56,23 @@ impl CohortState {
|
||||
if let Some(realized) = self.realized.as_mut() {
|
||||
let price = price.unwrap();
|
||||
realized.increment(supply_state, price);
|
||||
*self.price_to_amount.entry(price).or_default() += supply_state.value;
|
||||
self.price_to_amount.increment(price, supply_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn increment_(
|
||||
&mut self,
|
||||
supply_state: &SupplyState,
|
||||
realized_cap: Dollars,
|
||||
realized_price: Dollars,
|
||||
) {
|
||||
self.supply += supply_state;
|
||||
|
||||
if supply_state.value > Sats::ZERO {
|
||||
if let Some(realized) = self.realized.as_mut() {
|
||||
realized.increment_(realized_cap);
|
||||
self.price_to_amount.increment(realized_price, supply_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,27 +84,60 @@ impl CohortState {
|
||||
if let Some(realized) = self.realized.as_mut() {
|
||||
let price = price.unwrap();
|
||||
realized.decrement(supply_state, price);
|
||||
self.decrement_price_to_amount(supply_state, price);
|
||||
self.price_to_amount.decrement(price, supply_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn decrement_price_to_amount(&mut self, supply_state: &SupplyState, price: Dollars) {
|
||||
let amount = self.price_to_amount.get_mut(&price).unwrap();
|
||||
*amount -= supply_state.value;
|
||||
if *amount == Sats::ZERO {
|
||||
self.price_to_amount.remove(&price);
|
||||
pub fn decrement_(
|
||||
&mut self,
|
||||
supply_state: &SupplyState,
|
||||
realized_cap: Dollars,
|
||||
realized_price: Dollars,
|
||||
) {
|
||||
self.supply -= supply_state;
|
||||
|
||||
if supply_state.value > Sats::ZERO {
|
||||
if let Some(realized) = self.realized.as_mut() {
|
||||
realized.decrement_(realized_cap);
|
||||
self.price_to_amount.decrement(realized_price, supply_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receive(&mut self, supply_state: &SupplyState, price: Option<Dollars>) {
|
||||
self.receive_(
|
||||
supply_state,
|
||||
price,
|
||||
price.map(|price| (price, supply_state)),
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn receive_(
|
||||
&mut self,
|
||||
supply_state: &SupplyState,
|
||||
price: Option<Dollars>,
|
||||
price_to_amount_increment: Option<(Dollars, &SupplyState)>,
|
||||
price_to_amount_decrement: Option<(Dollars, &SupplyState)>,
|
||||
) {
|
||||
self.supply += supply_state;
|
||||
|
||||
if supply_state.value > Sats::ZERO {
|
||||
if let Some(realized) = self.realized.as_mut() {
|
||||
let price = price.unwrap();
|
||||
realized.receive(supply_state, price);
|
||||
*self.price_to_amount.entry(price).or_default() += supply_state.value;
|
||||
|
||||
if let Some((price, supply)) = price_to_amount_increment
|
||||
&& supply.value.is_not_zero()
|
||||
{
|
||||
self.price_to_amount.increment(price, supply);
|
||||
}
|
||||
if let Some((price, supply)) = price_to_amount_decrement
|
||||
&& supply.value.is_not_zero()
|
||||
{
|
||||
self.price_to_amount.decrement(price, supply);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,6 +151,34 @@ impl CohortState {
|
||||
days_old: f64,
|
||||
older_than_hour: bool,
|
||||
) {
|
||||
self.send_(
|
||||
supply_state,
|
||||
current_price,
|
||||
prev_price,
|
||||
blocks_old,
|
||||
days_old,
|
||||
older_than_hour,
|
||||
None,
|
||||
prev_price.map(|prev_price| (prev_price, supply_state)),
|
||||
);
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn send_(
|
||||
&mut self,
|
||||
supply_state: &SupplyState,
|
||||
current_price: Option<Dollars>,
|
||||
prev_price: Option<Dollars>,
|
||||
blocks_old: usize,
|
||||
days_old: f64,
|
||||
older_than_hour: bool,
|
||||
price_to_amount_increment: Option<(Dollars, &SupplyState)>,
|
||||
price_to_amount_decrement: Option<(Dollars, &SupplyState)>,
|
||||
) {
|
||||
if supply_state.utxos == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
self.supply -= supply_state;
|
||||
|
||||
if supply_state.value > Sats::ZERO {
|
||||
@@ -99,7 +191,16 @@ impl CohortState {
|
||||
let current_price = current_price.unwrap();
|
||||
let prev_price = prev_price.unwrap();
|
||||
realized.send(supply_state, current_price, prev_price, older_than_hour);
|
||||
self.decrement_price_to_amount(supply_state, prev_price);
|
||||
if let Some((price, supply)) = price_to_amount_increment
|
||||
&& supply.value.is_not_zero()
|
||||
{
|
||||
self.price_to_amount.increment(price, supply);
|
||||
}
|
||||
if let Some((price, supply)) = price_to_amount_decrement
|
||||
&& supply.value.is_not_zero()
|
||||
{
|
||||
self.price_to_amount.decrement(price, supply);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
mod address;
|
||||
mod common;
|
||||
mod utxo;
|
||||
|
||||
pub use address::*;
|
||||
pub use common::*;
|
||||
pub use utxo::*;
|
||||
@@ -0,0 +1,27 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{Height, Result};
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
|
||||
use super::CohortState;
|
||||
|
||||
#[derive(Clone, Deref, DerefMut)]
|
||||
pub struct UTXOCohortState(CohortState);
|
||||
|
||||
impl UTXOCohortState {
|
||||
pub fn default_and_import(path: &Path, name: &str, compute_dollars: bool) -> Result<Self> {
|
||||
Ok(Self(CohortState::default_and_import(
|
||||
path,
|
||||
name,
|
||||
compute_dollars,
|
||||
)?))
|
||||
}
|
||||
|
||||
pub fn height(&self) -> Option<Height> {
|
||||
self.0.height()
|
||||
}
|
||||
|
||||
pub fn reset_price_to_amount(&mut self) -> Result<()> {
|
||||
self.0.reset_price_to_amount()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
mod block;
|
||||
mod cohorts;
|
||||
mod price_to_amount;
|
||||
mod realized;
|
||||
mod supply;
|
||||
mod transacted;
|
||||
mod unrealized;
|
||||
|
||||
pub use block::*;
|
||||
pub use cohorts::*;
|
||||
pub use price_to_amount::*;
|
||||
pub use realized::*;
|
||||
pub use supply::*;
|
||||
pub use transacted::*;
|
||||
pub use unrealized::*;
|
||||
+31
-15
@@ -2,7 +2,6 @@ use std::{
|
||||
collections::BTreeMap,
|
||||
fs::{self, File},
|
||||
io::{BufReader, BufWriter},
|
||||
ops::{Deref, DerefMut},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
@@ -11,6 +10,8 @@ use brk_core::{Dollars, Height, Result, Sats};
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::states::SupplyState;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PriceToAmount {
|
||||
pathbuf: PathBuf,
|
||||
@@ -46,8 +47,36 @@ impl PriceToAmount {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = (&Dollars, &Sats)> {
|
||||
self.state.iter()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.state.is_empty()
|
||||
}
|
||||
|
||||
pub fn first_key_value(&self) -> Option<(&Dollars, &Sats)> {
|
||||
self.state.first_key_value()
|
||||
}
|
||||
|
||||
pub fn last_key_value(&self) -> Option<(&Dollars, &Sats)> {
|
||||
self.state.last_key_value()
|
||||
}
|
||||
|
||||
pub fn increment(&mut self, price: Dollars, supply_state: &SupplyState) {
|
||||
*self.state.entry(price).or_default() += supply_state.value;
|
||||
}
|
||||
|
||||
pub fn decrement(&mut self, price: Dollars, supply_state: &SupplyState) {
|
||||
let amount = self.state.get_mut(&price).unwrap();
|
||||
*amount -= supply_state.value;
|
||||
if *amount == Sats::ZERO {
|
||||
self.state.remove(&price);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) -> Result<()> {
|
||||
self.clear();
|
||||
self.state.clear();
|
||||
self.height = None;
|
||||
fs::remove_dir_all(&self.pathbuf)?;
|
||||
fs::create_dir_all(&self.pathbuf)?;
|
||||
@@ -89,16 +118,3 @@ impl PriceToAmount {
|
||||
path.join("height")
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for PriceToAmount {
|
||||
type Target = BTreeMap<Dollars, Sats>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.state
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for PriceToAmount {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.state
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,10 @@ impl RealizedState {
|
||||
return;
|
||||
}
|
||||
|
||||
self.increment_(price * supply_state.value)
|
||||
}
|
||||
|
||||
pub fn increment_(&mut self, realized_cap: Dollars) {
|
||||
if self.cap == Dollars::NAN {
|
||||
self.cap = Dollars::ZERO;
|
||||
self.profit = Dollars::ZERO;
|
||||
@@ -52,13 +56,15 @@ impl RealizedState {
|
||||
self.adj_value_destroyed = Dollars::ZERO;
|
||||
}
|
||||
|
||||
let value = price * supply_state.value;
|
||||
self.cap += value;
|
||||
self.cap += realized_cap;
|
||||
}
|
||||
|
||||
pub fn decrement(&mut self, supply_state: &SupplyState, price: Dollars) {
|
||||
let value = price * supply_state.value;
|
||||
self.cap = self.cap.checked_sub(value).unwrap();
|
||||
self.decrement_(price * supply_state.value);
|
||||
}
|
||||
|
||||
pub fn decrement_(&mut self, realized_cap: Dollars) {
|
||||
self.cap = self.cap.checked_sub(realized_cap).unwrap();
|
||||
}
|
||||
|
||||
pub fn receive(&mut self, supply_state: &SupplyState, current_price: Dollars) {
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::ops::{Add, AddAssign, SubAssign};
|
||||
|
||||
use brk_core::{CheckedSub, Sats};
|
||||
use brk_core::{AddressData, CheckedSub, Sats};
|
||||
use serde::Serialize;
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
@@ -39,3 +39,12 @@ impl SubAssign<&SupplyState> for SupplyState {
|
||||
self.value = self.value.checked_sub(rhs.value).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&AddressData> for SupplyState {
|
||||
fn from(value: &AddressData) -> Self {
|
||||
Self {
|
||||
utxos: value.outputs_len as usize,
|
||||
value: value.amount(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
use std::ops::{Add, AddAssign};
|
||||
|
||||
use brk_core::{ByAmountRange, GroupedByType, OutputType, Sats};
|
||||
|
||||
use super::SupplyState;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Transacted {
|
||||
pub spendable_supply: SupplyState,
|
||||
pub by_type: GroupedByType<SupplyState>,
|
||||
pub by_size_group: ByAmountRange<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;
|
||||
|
||||
*self.by_size_group.get_mut(value) += &supply;
|
||||
}
|
||||
}
|
||||
|
||||
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_group: self.by_size_group + rhs.by_size_group,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for Transacted {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.by_size_group += rhs.by_size_group;
|
||||
self.spendable_supply += &rhs.spendable_supply;
|
||||
self.by_type += rhs.by_type;
|
||||
}
|
||||
}
|
||||
@@ -1,34 +1,647 @@
|
||||
use std::path::Path;
|
||||
use std::{path::Path, thread};
|
||||
|
||||
use brk_core::Version;
|
||||
use fjall::TransactionalKeyspace;
|
||||
use brk_core::{
|
||||
AddressData, ByAddressType, EmptyAddressData, Height, OutputType, P2AAddressIndex,
|
||||
P2PK33AddressIndex, P2PK65AddressIndex, P2PKHAddressIndex, P2SHAddressIndex, P2TRAddressIndex,
|
||||
P2WPKHAddressIndex, P2WSHAddressIndex, Result, TypeIndex, Version,
|
||||
};
|
||||
use brk_store::{AnyStore, Store};
|
||||
use fjall::{PersistMode, TransactionalKeyspace};
|
||||
use log::info;
|
||||
|
||||
const _VERSION: Version = Version::ZERO;
|
||||
use crate::vecs::stateful::{AddressTypeToTypeIndexTree, WithAddressDataSource};
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Stores {
|
||||
// pub address_to_utxos_received: Store<AddressIndexOutputIndex, Unit>,
|
||||
// pub address_to_utxos_spent: Store<AddressIndexOutputIndex, Unit>,
|
||||
keyspace: TransactionalKeyspace,
|
||||
|
||||
pub p2aaddressindex_to_addressdata: Store<P2AAddressIndex, AddressData>,
|
||||
pub p2aaddressindex_to_emptyaddressdata: Store<P2AAddressIndex, EmptyAddressData>,
|
||||
pub p2pk33addressindex_to_addressdata: Store<P2PK33AddressIndex, AddressData>,
|
||||
pub p2pk33addressindex_to_emptyaddressdata: Store<P2PK33AddressIndex, EmptyAddressData>,
|
||||
pub p2pk65addressindex_to_addressdata: Store<P2PK65AddressIndex, AddressData>,
|
||||
pub p2pk65addressindex_to_emptyaddressdata: Store<P2PK65AddressIndex, EmptyAddressData>,
|
||||
pub p2pkhaddressindex_to_addressdata: Store<P2PKHAddressIndex, AddressData>,
|
||||
pub p2pkhaddressindex_to_emptyaddressdata: Store<P2PKHAddressIndex, EmptyAddressData>,
|
||||
pub p2shaddressindex_to_addressdata: Store<P2SHAddressIndex, AddressData>,
|
||||
pub p2shaddressindex_to_emptyaddressdata: Store<P2SHAddressIndex, EmptyAddressData>,
|
||||
pub p2traddressindex_to_addressdata: Store<P2TRAddressIndex, AddressData>,
|
||||
pub p2traddressindex_to_emptyaddressdata: Store<P2TRAddressIndex, EmptyAddressData>,
|
||||
pub p2wpkhaddressindex_to_addressdata: Store<P2WPKHAddressIndex, AddressData>,
|
||||
pub p2wpkhaddressindex_to_emptyaddressdata: Store<P2WPKHAddressIndex, EmptyAddressData>,
|
||||
pub p2wshaddressindex_to_addressdata: Store<P2WSHAddressIndex, AddressData>,
|
||||
pub p2wshaddressindex_to_emptyaddressdata: Store<P2WSHAddressIndex, EmptyAddressData>,
|
||||
}
|
||||
|
||||
impl Stores {
|
||||
pub fn import(_: &Path, _: Version, _: &TransactionalKeyspace) -> color_eyre::Result<Self> {
|
||||
// let address_to_utxos_received = Store::import(
|
||||
// keyspace.clone(),
|
||||
// path,
|
||||
// "address_to_utxos_received",
|
||||
// version + VERSION + Version::ZERO,
|
||||
// )?;
|
||||
// let address_to_utxos_spent = Store::import(
|
||||
// keyspace.clone(),
|
||||
// path,
|
||||
// "address_to_utxos_spent",
|
||||
// version + VERSION + Version::ZERO,
|
||||
// )?;
|
||||
pub fn import(
|
||||
path: &Path,
|
||||
version: Version,
|
||||
keyspace: &TransactionalKeyspace,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let (
|
||||
(p2aaddressindex_to_addressdata, p2aaddressindex_to_emptyaddressdata),
|
||||
(p2pk33addressindex_to_addressdata, p2pk33addressindex_to_emptyaddressdata),
|
||||
(p2pk65addressindex_to_addressdata, p2pk65addressindex_to_emptyaddressdata),
|
||||
(p2pkhaddressindex_to_addressdata, p2pkhaddressindex_to_emptyaddressdata),
|
||||
(p2shaddressindex_to_addressdata, p2shaddressindex_to_emptyaddressdata),
|
||||
(p2traddressindex_to_addressdata, p2traddressindex_to_emptyaddressdata),
|
||||
(p2wpkhaddressindex_to_addressdata, p2wpkhaddressindex_to_emptyaddressdata),
|
||||
(p2wshaddressindex_to_addressdata, p2wshaddressindex_to_emptyaddressdata),
|
||||
) = thread::scope(|scope| {
|
||||
let p2a = scope.spawn(|| {
|
||||
(
|
||||
Store::import(
|
||||
keyspace,
|
||||
path,
|
||||
"p2aaddressindex_to_addressdata",
|
||||
version + VERSION + Version::ZERO,
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
Store::import(
|
||||
keyspace,
|
||||
path,
|
||||
"p2aaddressindex_to_emptyaddressdata",
|
||||
version + VERSION + Version::ZERO,
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
});
|
||||
|
||||
let p2pk33 = scope.spawn(|| {
|
||||
(
|
||||
Store::import(
|
||||
keyspace,
|
||||
path,
|
||||
"p2pk33addressindex_to_addressdata",
|
||||
version + VERSION + Version::ZERO,
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
Store::import(
|
||||
keyspace,
|
||||
path,
|
||||
"p2pk33addressindex_to_emptyaddressdata",
|
||||
version + VERSION + Version::ZERO,
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
});
|
||||
|
||||
let p2pk65 = scope.spawn(|| {
|
||||
(
|
||||
Store::import(
|
||||
keyspace,
|
||||
path,
|
||||
"p2pk65addressindex_to_addressdata",
|
||||
version + VERSION + Version::ZERO,
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
Store::import(
|
||||
keyspace,
|
||||
path,
|
||||
"p2pk65addressindex_to_emptyaddressdata",
|
||||
version + VERSION + Version::ZERO,
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
});
|
||||
|
||||
let p2pkh = scope.spawn(|| {
|
||||
(
|
||||
Store::import(
|
||||
keyspace,
|
||||
path,
|
||||
"p2pkhaddressindex_to_addressdata",
|
||||
version + VERSION + Version::ZERO,
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
Store::import(
|
||||
keyspace,
|
||||
path,
|
||||
"p2pkhaddressindex_to_emptyaddressdata",
|
||||
version + VERSION + Version::ZERO,
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
});
|
||||
|
||||
let p2sh = scope.spawn(|| {
|
||||
(
|
||||
Store::import(
|
||||
keyspace,
|
||||
path,
|
||||
"p2shaddressindex_to_addressdata",
|
||||
version + VERSION + Version::ZERO,
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
Store::import(
|
||||
keyspace,
|
||||
path,
|
||||
"p2shaddressindex_to_emptyaddressdata",
|
||||
version + VERSION + Version::ZERO,
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
});
|
||||
|
||||
let p2tr = scope.spawn(|| {
|
||||
(
|
||||
Store::import(
|
||||
keyspace,
|
||||
path,
|
||||
"p2traddressindex_to_addressdata",
|
||||
version + VERSION + Version::ZERO,
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
Store::import(
|
||||
keyspace,
|
||||
path,
|
||||
"p2traddressindex_to_emptyaddressdata",
|
||||
version + VERSION + Version::ZERO,
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
});
|
||||
|
||||
let p2wpkh = scope.spawn(|| {
|
||||
(
|
||||
Store::import(
|
||||
keyspace,
|
||||
path,
|
||||
"p2wpkhaddressindex_to_addressdata",
|
||||
version + VERSION + Version::ZERO,
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
Store::import(
|
||||
keyspace,
|
||||
path,
|
||||
"p2wpkhaddressindex_to_emptyaddressdata",
|
||||
version + VERSION + Version::ZERO,
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
});
|
||||
|
||||
let p2wsh = scope.spawn(|| {
|
||||
(
|
||||
Store::import(
|
||||
keyspace,
|
||||
path,
|
||||
"p2wshaddressindex_to_addressdata",
|
||||
version + VERSION + Version::ZERO,
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
Store::import(
|
||||
keyspace,
|
||||
path,
|
||||
"p2wshaddressindex_to_emptyaddressdata",
|
||||
version + VERSION + Version::ZERO,
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
});
|
||||
|
||||
(
|
||||
p2a.join().unwrap(),
|
||||
p2pk33.join().unwrap(),
|
||||
p2pk65.join().unwrap(),
|
||||
p2pkh.join().unwrap(),
|
||||
p2sh.join().unwrap(),
|
||||
p2tr.join().unwrap(),
|
||||
p2wpkh.join().unwrap(),
|
||||
p2wsh.join().unwrap(),
|
||||
)
|
||||
});
|
||||
|
||||
Ok(Self {
|
||||
// address_to_utxos_received,
|
||||
// address_to_utxos_spent,
|
||||
keyspace: keyspace.clone(),
|
||||
|
||||
p2aaddressindex_to_addressdata,
|
||||
p2aaddressindex_to_emptyaddressdata,
|
||||
|
||||
p2pk33addressindex_to_addressdata,
|
||||
p2pk33addressindex_to_emptyaddressdata,
|
||||
|
||||
p2pk65addressindex_to_addressdata,
|
||||
p2pk65addressindex_to_emptyaddressdata,
|
||||
|
||||
p2pkhaddressindex_to_addressdata,
|
||||
p2pkhaddressindex_to_emptyaddressdata,
|
||||
|
||||
p2shaddressindex_to_addressdata,
|
||||
p2shaddressindex_to_emptyaddressdata,
|
||||
|
||||
p2traddressindex_to_addressdata,
|
||||
p2traddressindex_to_emptyaddressdata,
|
||||
|
||||
p2wpkhaddressindex_to_addressdata,
|
||||
p2wpkhaddressindex_to_emptyaddressdata,
|
||||
|
||||
p2wshaddressindex_to_addressdata,
|
||||
p2wshaddressindex_to_emptyaddressdata,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn starting_height(&self) -> Height {
|
||||
self.as_slice()
|
||||
.into_iter()
|
||||
.map(|store| store.height().map(Height::incremented).unwrap_or_default())
|
||||
.min()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) -> Result<()> {
|
||||
info!("Resetting stores...");
|
||||
info!("> If it gets stuck here, stop the program and start it again");
|
||||
|
||||
self.as_mut_slice()
|
||||
.into_iter()
|
||||
.try_for_each(|store| store.reset())?;
|
||||
|
||||
self.keyspace
|
||||
.persist(PersistMode::SyncAll)
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
pub fn get_addressdata(
|
||||
&self,
|
||||
address_type: OutputType,
|
||||
type_index: TypeIndex,
|
||||
) -> Result<Option<AddressData>> {
|
||||
Ok(match address_type {
|
||||
OutputType::P2A => self
|
||||
.p2aaddressindex_to_addressdata
|
||||
.get(&type_index.into())?
|
||||
.map(|c| c.into_owned()),
|
||||
OutputType::P2PK33 => self
|
||||
.p2pk33addressindex_to_addressdata
|
||||
.get(&type_index.into())?
|
||||
.map(|c| c.into_owned()),
|
||||
OutputType::P2PK65 => self
|
||||
.p2pk65addressindex_to_addressdata
|
||||
.get(&type_index.into())?
|
||||
.map(|c| c.into_owned()),
|
||||
OutputType::P2PKH => self
|
||||
.p2pkhaddressindex_to_addressdata
|
||||
.get(&type_index.into())?
|
||||
.map(|c| c.into_owned()),
|
||||
OutputType::P2SH => self
|
||||
.p2shaddressindex_to_addressdata
|
||||
.get(&type_index.into())?
|
||||
.map(|c| c.into_owned()),
|
||||
OutputType::P2TR => self
|
||||
.p2traddressindex_to_addressdata
|
||||
.get(&type_index.into())?
|
||||
.map(|c| c.into_owned()),
|
||||
OutputType::P2WPKH => self
|
||||
.p2wpkhaddressindex_to_addressdata
|
||||
.get(&type_index.into())?
|
||||
.map(|c| c.into_owned()),
|
||||
OutputType::P2WSH => self
|
||||
.p2wshaddressindex_to_addressdata
|
||||
.get(&type_index.into())?
|
||||
.map(|c| c.into_owned()),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_emptyaddressdata(
|
||||
&self,
|
||||
address_type: OutputType,
|
||||
type_index: TypeIndex,
|
||||
) -> Result<Option<EmptyAddressData>> {
|
||||
Ok(match address_type {
|
||||
OutputType::P2A => self
|
||||
.p2aaddressindex_to_emptyaddressdata
|
||||
.get(&type_index.into())?
|
||||
.map(|c| c.into_owned()),
|
||||
OutputType::P2PK33 => self
|
||||
.p2pk33addressindex_to_emptyaddressdata
|
||||
.get(&type_index.into())?
|
||||
.map(|c| c.into_owned()),
|
||||
OutputType::P2PK65 => self
|
||||
.p2pk65addressindex_to_emptyaddressdata
|
||||
.get(&type_index.into())?
|
||||
.map(|c| c.into_owned()),
|
||||
OutputType::P2PKH => self
|
||||
.p2pkhaddressindex_to_emptyaddressdata
|
||||
.get(&type_index.into())?
|
||||
.map(|c| c.into_owned()),
|
||||
OutputType::P2SH => self
|
||||
.p2shaddressindex_to_emptyaddressdata
|
||||
.get(&type_index.into())?
|
||||
.map(|c| c.into_owned()),
|
||||
OutputType::P2TR => self
|
||||
.p2traddressindex_to_emptyaddressdata
|
||||
.get(&type_index.into())?
|
||||
.map(|c| c.into_owned()),
|
||||
OutputType::P2WPKH => self
|
||||
.p2wpkhaddressindex_to_emptyaddressdata
|
||||
.get(&type_index.into())?
|
||||
.map(|c| c.into_owned()),
|
||||
OutputType::P2WSH => self
|
||||
.p2wshaddressindex_to_emptyaddressdata
|
||||
.get(&type_index.into())?
|
||||
.map(|c| c.into_owned()),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn commit(
|
||||
&mut self,
|
||||
height: Height,
|
||||
addresstype_to_typeindex_to_addressdata: AddressTypeToTypeIndexTree<
|
||||
WithAddressDataSource<AddressData>,
|
||||
>,
|
||||
addresstype_to_typeindex_to_emptyaddressdata: AddressTypeToTypeIndexTree<
|
||||
WithAddressDataSource<EmptyAddressData>,
|
||||
>,
|
||||
) -> Result<()> {
|
||||
let ByAddressType {
|
||||
p2pk65,
|
||||
p2pk33,
|
||||
p2pkh,
|
||||
p2sh,
|
||||
p2wpkh,
|
||||
p2wsh,
|
||||
p2tr,
|
||||
p2a,
|
||||
} = addresstype_to_typeindex_to_addressdata.unwrap();
|
||||
|
||||
let ByAddressType {
|
||||
p2pk65: empty_p2pk65,
|
||||
p2pk33: empty_p2pk33,
|
||||
p2pkh: empty_p2pkh,
|
||||
p2sh: empty_p2sh,
|
||||
p2wpkh: empty_p2wpkh,
|
||||
p2wsh: empty_p2wsh,
|
||||
p2tr: empty_p2tr,
|
||||
p2a: empty_p2a,
|
||||
} = addresstype_to_typeindex_to_emptyaddressdata.unwrap();
|
||||
|
||||
thread::scope(|s| {
|
||||
s.spawn(|| {
|
||||
self.p2aaddressindex_to_addressdata.commit_(
|
||||
height,
|
||||
empty_p2a
|
||||
.iter()
|
||||
.filter(|(_, addressdata)| addressdata.is_from_addressdata())
|
||||
.map(|(typeindex, _)| (*typeindex).into()),
|
||||
p2a.iter().map(|(typeindex, addressdata)| {
|
||||
((*typeindex).into(), addressdata.deref().clone())
|
||||
}),
|
||||
)
|
||||
});
|
||||
s.spawn(|| {
|
||||
self.p2pk33addressindex_to_addressdata.commit_(
|
||||
height,
|
||||
empty_p2pk33
|
||||
.iter()
|
||||
.filter(|(_, addressdata)| addressdata.is_from_addressdata())
|
||||
.map(|(typeindex, _)| (*typeindex).into()),
|
||||
p2pk33.iter().map(|(typeindex, addressdata)| {
|
||||
((*typeindex).into(), addressdata.deref().clone())
|
||||
}),
|
||||
)
|
||||
});
|
||||
s.spawn(|| {
|
||||
self.p2pk65addressindex_to_addressdata.commit_(
|
||||
height,
|
||||
empty_p2pk65
|
||||
.iter()
|
||||
.filter(|(_, addressdata)| addressdata.is_from_addressdata())
|
||||
.map(|(typeindex, _)| (*typeindex).into()),
|
||||
p2pk65.iter().map(|(typeindex, addressdata)| {
|
||||
((*typeindex).into(), addressdata.deref().clone())
|
||||
}),
|
||||
)
|
||||
});
|
||||
s.spawn(|| {
|
||||
self.p2pkhaddressindex_to_addressdata.commit_(
|
||||
height,
|
||||
empty_p2pkh
|
||||
.iter()
|
||||
.filter(|(_, addressdata)| addressdata.is_from_addressdata())
|
||||
.map(|(typeindex, _)| (*typeindex).into()),
|
||||
p2pkh.iter().map(|(typeindex, addressdata)| {
|
||||
((*typeindex).into(), addressdata.deref().clone())
|
||||
}),
|
||||
)
|
||||
});
|
||||
s.spawn(|| {
|
||||
self.p2shaddressindex_to_addressdata.commit_(
|
||||
height,
|
||||
empty_p2sh
|
||||
.iter()
|
||||
.filter(|(_, addressdata)| addressdata.is_from_addressdata())
|
||||
.map(|(typeindex, _)| (*typeindex).into()),
|
||||
p2sh.iter().map(|(typeindex, addressdata)| {
|
||||
((*typeindex).into(), addressdata.deref().clone())
|
||||
}),
|
||||
)
|
||||
});
|
||||
s.spawn(|| {
|
||||
self.p2traddressindex_to_addressdata.commit_(
|
||||
height,
|
||||
empty_p2tr
|
||||
.iter()
|
||||
.filter(|(_, addressdata)| addressdata.is_from_addressdata())
|
||||
.map(|(typeindex, _)| (*typeindex).into()),
|
||||
p2tr.iter().map(|(typeindex, addressdata)| {
|
||||
((*typeindex).into(), addressdata.deref().clone())
|
||||
}),
|
||||
)
|
||||
});
|
||||
s.spawn(|| {
|
||||
self.p2wpkhaddressindex_to_addressdata.commit_(
|
||||
height,
|
||||
empty_p2wpkh
|
||||
.iter()
|
||||
.filter(|(_, addressdata)| addressdata.is_from_addressdata())
|
||||
.map(|(typeindex, _)| (*typeindex).into()),
|
||||
p2wpkh.iter().map(|(typeindex, addressdata)| {
|
||||
((*typeindex).into(), addressdata.deref().clone())
|
||||
}),
|
||||
)
|
||||
});
|
||||
s.spawn(|| {
|
||||
self.p2wshaddressindex_to_addressdata.commit_(
|
||||
height,
|
||||
empty_p2wsh
|
||||
.iter()
|
||||
.filter(|(_, addressdata)| addressdata.is_from_addressdata())
|
||||
.map(|(typeindex, _)| (*typeindex).into()),
|
||||
p2wsh.iter().map(|(typeindex, addressdata)| {
|
||||
((*typeindex).into(), addressdata.deref().clone())
|
||||
}),
|
||||
)
|
||||
});
|
||||
});
|
||||
|
||||
thread::scope(|scope| {
|
||||
scope.spawn(|| {
|
||||
self.p2aaddressindex_to_emptyaddressdata.commit_(
|
||||
height,
|
||||
p2a.iter()
|
||||
.filter(|(_, addressdata)| addressdata.is_from_emptyaddressdata())
|
||||
.map(|(typeindex, _)| (*typeindex).into()),
|
||||
empty_p2a.iter().map(|(typeindex, addressdata)| {
|
||||
((*typeindex).into(), addressdata.deref().clone())
|
||||
}),
|
||||
)
|
||||
});
|
||||
scope.spawn(|| {
|
||||
self.p2pk33addressindex_to_emptyaddressdata.commit_(
|
||||
height,
|
||||
p2pk33
|
||||
.iter()
|
||||
.filter(|(_, addressdata)| addressdata.is_from_emptyaddressdata())
|
||||
.map(|(typeindex, _)| (*typeindex).into()),
|
||||
empty_p2pk33.iter().map(|(typeindex, addressdata)| {
|
||||
((*typeindex).into(), addressdata.deref().clone())
|
||||
}),
|
||||
)
|
||||
});
|
||||
scope.spawn(|| {
|
||||
self.p2pk65addressindex_to_emptyaddressdata.commit_(
|
||||
height,
|
||||
p2pk65
|
||||
.iter()
|
||||
.filter(|(_, addressdata)| addressdata.is_from_emptyaddressdata())
|
||||
.map(|(typeindex, _)| (*typeindex).into()),
|
||||
empty_p2pk65.iter().map(|(typeindex, addressdata)| {
|
||||
((*typeindex).into(), addressdata.deref().clone())
|
||||
}),
|
||||
)
|
||||
});
|
||||
scope.spawn(|| {
|
||||
self.p2pkhaddressindex_to_emptyaddressdata.commit_(
|
||||
height,
|
||||
p2pkh
|
||||
.iter()
|
||||
.filter(|(_, addressdata)| addressdata.is_from_emptyaddressdata())
|
||||
.map(|(typeindex, _)| (*typeindex).into()),
|
||||
empty_p2pkh.iter().map(|(typeindex, addressdata)| {
|
||||
((*typeindex).into(), addressdata.deref().clone())
|
||||
}),
|
||||
)
|
||||
});
|
||||
scope.spawn(|| {
|
||||
self.p2shaddressindex_to_emptyaddressdata.commit_(
|
||||
height,
|
||||
p2sh.iter()
|
||||
.filter(|(_, addressdata)| addressdata.is_from_emptyaddressdata())
|
||||
.map(|(typeindex, _)| (*typeindex).into()),
|
||||
empty_p2sh.iter().map(|(typeindex, addressdata)| {
|
||||
((*typeindex).into(), addressdata.deref().clone())
|
||||
}),
|
||||
)
|
||||
});
|
||||
scope.spawn(|| {
|
||||
self.p2traddressindex_to_emptyaddressdata.commit_(
|
||||
height,
|
||||
p2tr.iter()
|
||||
.filter(|(_, addressdata)| addressdata.is_from_emptyaddressdata())
|
||||
.map(|(typeindex, _)| (*typeindex).into()),
|
||||
empty_p2tr.iter().map(|(typeindex, addressdata)| {
|
||||
((*typeindex).into(), addressdata.deref().clone())
|
||||
}),
|
||||
)
|
||||
});
|
||||
scope.spawn(|| {
|
||||
self.p2wpkhaddressindex_to_emptyaddressdata.commit_(
|
||||
height,
|
||||
p2wpkh
|
||||
.iter()
|
||||
.filter(|(_, addressdata)| addressdata.is_from_emptyaddressdata())
|
||||
.map(|(typeindex, _)| (*typeindex).into()),
|
||||
empty_p2wpkh.iter().map(|(typeindex, addressdata)| {
|
||||
((*typeindex).into(), addressdata.deref().clone())
|
||||
}),
|
||||
)
|
||||
});
|
||||
scope.spawn(|| {
|
||||
self.p2wshaddressindex_to_emptyaddressdata.commit_(
|
||||
height,
|
||||
p2wsh
|
||||
.iter()
|
||||
.filter(|(_, addressdata)| addressdata.is_from_emptyaddressdata())
|
||||
.map(|(typeindex, _)| (*typeindex).into()),
|
||||
empty_p2wsh.iter().map(|(typeindex, addressdata)| {
|
||||
((*typeindex).into(), addressdata.deref().clone())
|
||||
}),
|
||||
)
|
||||
});
|
||||
});
|
||||
|
||||
self.keyspace
|
||||
.persist(PersistMode::SyncAll)
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
pub fn rotate_memtables(&self) {
|
||||
self.as_slice()
|
||||
.into_iter()
|
||||
.for_each(|store| store.rotate_memtable());
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> [&(dyn AnyStore + Send + Sync); 16] {
|
||||
[
|
||||
&self.p2aaddressindex_to_addressdata,
|
||||
&self.p2aaddressindex_to_emptyaddressdata,
|
||||
&self.p2pk33addressindex_to_addressdata,
|
||||
&self.p2pk33addressindex_to_emptyaddressdata,
|
||||
&self.p2pk65addressindex_to_addressdata,
|
||||
&self.p2pk65addressindex_to_emptyaddressdata,
|
||||
&self.p2pkhaddressindex_to_addressdata,
|
||||
&self.p2pkhaddressindex_to_emptyaddressdata,
|
||||
&self.p2shaddressindex_to_addressdata,
|
||||
&self.p2shaddressindex_to_emptyaddressdata,
|
||||
&self.p2traddressindex_to_addressdata,
|
||||
&self.p2traddressindex_to_emptyaddressdata,
|
||||
&self.p2wpkhaddressindex_to_addressdata,
|
||||
&self.p2wpkhaddressindex_to_emptyaddressdata,
|
||||
&self.p2wshaddressindex_to_addressdata,
|
||||
&self.p2wshaddressindex_to_emptyaddressdata,
|
||||
]
|
||||
}
|
||||
|
||||
fn as_mut_slice(&mut self) -> [&mut (dyn AnyStore + Send + Sync); 16] {
|
||||
[
|
||||
&mut self.p2aaddressindex_to_addressdata,
|
||||
&mut self.p2aaddressindex_to_emptyaddressdata,
|
||||
&mut self.p2pk33addressindex_to_addressdata,
|
||||
&mut self.p2pk33addressindex_to_emptyaddressdata,
|
||||
&mut self.p2pk65addressindex_to_addressdata,
|
||||
&mut self.p2pk65addressindex_to_emptyaddressdata,
|
||||
&mut self.p2pkhaddressindex_to_addressdata,
|
||||
&mut self.p2pkhaddressindex_to_emptyaddressdata,
|
||||
&mut self.p2shaddressindex_to_addressdata,
|
||||
&mut self.p2shaddressindex_to_emptyaddressdata,
|
||||
&mut self.p2traddressindex_to_addressdata,
|
||||
&mut self.p2traddressindex_to_emptyaddressdata,
|
||||
&mut self.p2wpkhaddressindex_to_addressdata,
|
||||
&mut self.p2wpkhaddressindex_to_emptyaddressdata,
|
||||
&mut self.p2wshaddressindex_to_addressdata,
|
||||
&mut self.p2wshaddressindex_to_emptyaddressdata,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,11 @@ use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, AnyIterableVec, Computation, EagerVec, Format};
|
||||
|
||||
use crate::vecs::grouped::Source;
|
||||
|
||||
use super::{
|
||||
Indexes,
|
||||
grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, StorableVecGeneatorOptions},
|
||||
grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, VecBuilderOptions},
|
||||
indexes,
|
||||
};
|
||||
|
||||
@@ -34,8 +36,9 @@ impl Vecs {
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
version: Version,
|
||||
_computation: Computation,
|
||||
computation: Computation,
|
||||
format: Format,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> color_eyre::Result<Self> {
|
||||
Ok(Self {
|
||||
height_to_interval: EagerVec::forced_import(
|
||||
@@ -47,18 +50,22 @@ impl Vecs {
|
||||
timeindexes_to_timestamp: ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
"timestamp",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_first(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_first(),
|
||||
)?,
|
||||
indexes_to_block_interval: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"block_interval",
|
||||
false,
|
||||
Source::None,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default()
|
||||
.add_percentiles()
|
||||
.add_minmax()
|
||||
.add_average(),
|
||||
@@ -66,32 +73,32 @@ impl Vecs {
|
||||
indexes_to_block_count: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"block_count",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_sum()
|
||||
.add_cumulative(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_sum().add_cumulative(),
|
||||
)?,
|
||||
indexes_to_block_weight: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"block_weight",
|
||||
false,
|
||||
Source::None,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_sum()
|
||||
.add_cumulative(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_sum().add_cumulative(),
|
||||
)?,
|
||||
indexes_to_block_size: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"block_size",
|
||||
false,
|
||||
Source::None,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_sum()
|
||||
.add_cumulative(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_sum().add_cumulative(),
|
||||
)?,
|
||||
height_to_vbytes: EagerVec::forced_import(
|
||||
path,
|
||||
@@ -102,12 +109,12 @@ impl Vecs {
|
||||
indexes_to_block_vbytes: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"block_vbytes",
|
||||
false,
|
||||
Source::None,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_sum()
|
||||
.add_cumulative(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_sum().add_cumulative(),
|
||||
)?,
|
||||
difficultyepoch_to_timestamp: EagerVec::forced_import(
|
||||
path,
|
||||
|
||||
@@ -7,13 +7,13 @@ use brk_vec::{AnyCollectableVec, Computation, Format, VecIterator};
|
||||
|
||||
use crate::vecs::{
|
||||
fetched,
|
||||
grouped::{ComputedRatioVecsFromDateIndex, ComputedValueVecsFromHeight},
|
||||
grouped::{ComputedRatioVecsFromDateIndex, ComputedValueVecsFromHeight, Source},
|
||||
stateful, transactions,
|
||||
};
|
||||
|
||||
use super::{
|
||||
Indexes,
|
||||
grouped::{ComputedVecsFromHeight, StorableVecGeneatorOptions},
|
||||
grouped::{ComputedVecsFromHeight, VecBuilderOptions},
|
||||
indexes,
|
||||
};
|
||||
|
||||
@@ -51,8 +51,9 @@ impl Vecs {
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
version: Version,
|
||||
_computation: Computation,
|
||||
computation: Computation,
|
||||
format: Format,
|
||||
indexes: &indexes::Vecs,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let compute_dollars = fetched.is_some();
|
||||
@@ -61,194 +62,234 @@ impl Vecs {
|
||||
indexes_to_coinblocks_created: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"coinblocks_created",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_sum()
|
||||
.add_cumulative(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_sum().add_cumulative(),
|
||||
)?,
|
||||
indexes_to_coinblocks_stored: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"coinblocks_stored",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_sum()
|
||||
.add_cumulative(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_sum().add_cumulative(),
|
||||
)?,
|
||||
indexes_to_liveliness: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"liveliness",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
indexes_to_vaultedness: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"vaultedness",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
indexes_to_activity_to_vaultedness_ratio: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"activity_to_vaultedness_ratio",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
indexes_to_vaulted_supply: ComputedValueVecsFromHeight::forced_import(
|
||||
path,
|
||||
"vaulted_supply",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ONE,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
compute_dollars,
|
||||
indexes,
|
||||
)?,
|
||||
indexes_to_active_supply: ComputedValueVecsFromHeight::forced_import(
|
||||
path,
|
||||
"active_supply",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ONE,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
compute_dollars,
|
||||
indexes,
|
||||
)?,
|
||||
indexes_to_thermo_cap: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"thermo_cap",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ONE,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
indexes_to_investor_cap: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"investor_cap",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ONE,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
indexes_to_vaulted_cap: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"vaulted_cap",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ONE,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
indexes_to_active_cap: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"active_cap",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ONE,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
indexes_to_vaulted_price: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"vaulted_price",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
indexes_to_vaulted_price_ratio: ComputedRatioVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
"vaulted_price",
|
||||
false,
|
||||
Source::None,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
true,
|
||||
)?,
|
||||
indexes_to_active_price: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"active_price",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
indexes_to_active_price_ratio: ComputedRatioVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
"active_price",
|
||||
false,
|
||||
Source::None,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
true,
|
||||
)?,
|
||||
indexes_to_true_market_mean: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"true_market_mean",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
indexes_to_true_market_mean_ratio: ComputedRatioVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
"true_market_mean",
|
||||
false,
|
||||
Source::None,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
true,
|
||||
)?,
|
||||
indexes_to_cointime_value_destroyed: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"cointime_value_destroyed",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_sum()
|
||||
.add_cumulative(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_sum().add_cumulative(),
|
||||
)?,
|
||||
indexes_to_cointime_value_created: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"cointime_value_created",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_sum()
|
||||
.add_cumulative(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_sum().add_cumulative(),
|
||||
)?,
|
||||
indexes_to_cointime_value_stored: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"cointime_value_stored",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_sum()
|
||||
.add_cumulative(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_sum().add_cumulative(),
|
||||
)?,
|
||||
indexes_to_cointime_price: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"cointime_price",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
indexes_to_cointime_cap: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"cointime_cap",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
indexes_to_cointime_price_ratio: ComputedRatioVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
"cointime_price",
|
||||
false,
|
||||
Source::None,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
true,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
@@ -264,7 +305,7 @@ impl Vecs {
|
||||
stateful: &stateful::Vecs,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
let circulating_supply = &stateful.utxos_vecs.all.1.height_to_supply;
|
||||
let circulating_supply = &stateful.utxo_vecs.all.1.height_to_supply;
|
||||
|
||||
self.indexes_to_coinblocks_created.compute_all(
|
||||
indexer,
|
||||
@@ -282,7 +323,7 @@ impl Vecs {
|
||||
)?;
|
||||
|
||||
let indexes_to_coinblocks_destroyed =
|
||||
&stateful.utxos_vecs.all.1.indexes_to_coinblocks_destroyed;
|
||||
&stateful.utxo_vecs.all.1.indexes_to_coinblocks_destroyed;
|
||||
|
||||
self.indexes_to_coinblocks_stored.compute_all(
|
||||
indexer,
|
||||
@@ -392,7 +433,7 @@ impl Vecs {
|
||||
|
||||
if let Some(fetched) = fetched {
|
||||
let realized_cap = stateful
|
||||
.utxos_vecs
|
||||
.utxo_vecs
|
||||
.all
|
||||
.1
|
||||
.height_to_realized_cap
|
||||
@@ -400,7 +441,7 @@ impl Vecs {
|
||||
.unwrap();
|
||||
|
||||
let realized_price = stateful
|
||||
.utxos_vecs
|
||||
.utxo_vecs
|
||||
.all
|
||||
.1
|
||||
.indexes_to_realized_price
|
||||
|
||||
@@ -5,9 +5,11 @@ use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, AnyVec, Computation, Format};
|
||||
|
||||
use crate::vecs::grouped::Source;
|
||||
|
||||
use super::{
|
||||
Indexes,
|
||||
grouped::{ComputedVecsFromHeight, StorableVecGeneatorOptions},
|
||||
grouped::{ComputedVecsFromHeight, VecBuilderOptions},
|
||||
indexes,
|
||||
};
|
||||
|
||||
@@ -25,41 +27,50 @@ impl Vecs {
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
version: Version,
|
||||
_computation: Computation,
|
||||
computation: Computation,
|
||||
format: Format,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> color_eyre::Result<Self> {
|
||||
Ok(Self {
|
||||
constant_0: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"constant_0",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
constant_1: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"constant_1",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
constant_50: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"constant_50",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
constant_100: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"constant_100",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2,18 +2,21 @@ use std::path::Path;
|
||||
|
||||
use brk_core::{
|
||||
Cents, Close, DateIndex, DecadeIndex, DifficultyEpoch, Dollars, Height, High, Low, MonthIndex,
|
||||
OHLCCents, OHLCDollars, OHLCSats, Open, QuarterIndex, Sats, Version, WeekIndex, YearIndex,
|
||||
OHLCCents, OHLCDollars, OHLCSats, Open, QuarterIndex, Sats, SemesterIndex, Version, WeekIndex,
|
||||
YearIndex,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_fetcher::Fetcher;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, AnyIterableVec, Computation, EagerVec, Format, StoredIndex};
|
||||
use brk_vec::{
|
||||
AnyCollectableVec, AnyIterableVec, AnyVec, Computation, EagerVec, Format, StoredIndex,
|
||||
};
|
||||
|
||||
use crate::vecs::grouped::Source;
|
||||
|
||||
use super::{
|
||||
Indexes,
|
||||
grouped::{
|
||||
ComputedVecsFromDateIndex, ComputedVecsFromHeightStrict, StorableVecGeneatorOptions,
|
||||
},
|
||||
grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeightStrict, VecBuilderOptions},
|
||||
indexes,
|
||||
};
|
||||
|
||||
@@ -57,6 +60,8 @@ pub struct Vecs {
|
||||
pub monthindex_to_ohlc_in_sats: EagerVec<MonthIndex, OHLCSats>,
|
||||
pub quarterindex_to_ohlc: EagerVec<QuarterIndex, OHLCDollars>,
|
||||
pub quarterindex_to_ohlc_in_sats: EagerVec<QuarterIndex, OHLCSats>,
|
||||
pub semesterindex_to_ohlc: EagerVec<SemesterIndex, OHLCDollars>,
|
||||
pub semesterindex_to_ohlc_in_sats: EagerVec<SemesterIndex, OHLCSats>,
|
||||
pub yearindex_to_ohlc: EagerVec<YearIndex, OHLCDollars>,
|
||||
pub yearindex_to_ohlc_in_sats: EagerVec<YearIndex, OHLCSats>,
|
||||
// pub halvingepoch_to_ohlc: StorableVec<Halvingepoch, OHLCDollars>,
|
||||
@@ -72,8 +77,9 @@ impl Vecs {
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
version: Version,
|
||||
_computation: Computation,
|
||||
computation: Computation,
|
||||
format: Format,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let mut fetched_path = path.to_owned();
|
||||
fetched_path.pop();
|
||||
@@ -83,7 +89,7 @@ impl Vecs {
|
||||
dateindex_to_ohlc_in_cents: EagerVec::forced_import(
|
||||
&fetched_path,
|
||||
"ohlc_in_cents",
|
||||
version + VERSION + Version::ZERO,
|
||||
version + Version::ZERO,
|
||||
format,
|
||||
)?,
|
||||
dateindex_to_ohlc: EagerVec::forced_import(
|
||||
@@ -125,7 +131,7 @@ impl Vecs {
|
||||
height_to_ohlc_in_cents: EagerVec::forced_import(
|
||||
&fetched_path,
|
||||
"ohlc_in_cents",
|
||||
version + VERSION + Version::ZERO,
|
||||
version + Version::ZERO,
|
||||
format,
|
||||
)?,
|
||||
height_to_ohlc: EagerVec::forced_import(
|
||||
@@ -167,122 +173,138 @@ impl Vecs {
|
||||
timeindexes_to_open: ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
"open",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_first(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_first(),
|
||||
)?,
|
||||
timeindexes_to_high: ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
"high",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_max(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_max(),
|
||||
)?,
|
||||
timeindexes_to_low: ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
"low",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_min(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_min(),
|
||||
)?,
|
||||
timeindexes_to_close: ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
"close",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
timeindexes_to_open_in_sats: ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
"open_in_sats",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_first(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_first(),
|
||||
)?,
|
||||
timeindexes_to_high_in_sats: ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
"high_in_sats",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_max(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_max(),
|
||||
)?,
|
||||
timeindexes_to_low_in_sats: ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
"low_in_sats",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_min(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_min(),
|
||||
)?,
|
||||
timeindexes_to_close_in_sats: ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
"close_in_sats",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
chainindexes_to_open: ComputedVecsFromHeightStrict::forced_import(
|
||||
path,
|
||||
"open",
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_first(),
|
||||
VecBuilderOptions::default().add_first(),
|
||||
)?,
|
||||
chainindexes_to_high: ComputedVecsFromHeightStrict::forced_import(
|
||||
path,
|
||||
"high",
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_max(),
|
||||
VecBuilderOptions::default().add_max(),
|
||||
)?,
|
||||
chainindexes_to_low: ComputedVecsFromHeightStrict::forced_import(
|
||||
path,
|
||||
"low",
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_min(),
|
||||
VecBuilderOptions::default().add_min(),
|
||||
)?,
|
||||
chainindexes_to_close: ComputedVecsFromHeightStrict::forced_import(
|
||||
path,
|
||||
"close",
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
chainindexes_to_open_in_sats: ComputedVecsFromHeightStrict::forced_import(
|
||||
path,
|
||||
"open_in_sats",
|
||||
version + VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_first(),
|
||||
VecBuilderOptions::default().add_first(),
|
||||
)?,
|
||||
chainindexes_to_high_in_sats: ComputedVecsFromHeightStrict::forced_import(
|
||||
path,
|
||||
"high_in_sats",
|
||||
version + VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_max(),
|
||||
VecBuilderOptions::default().add_max(),
|
||||
)?,
|
||||
chainindexes_to_low_in_sats: ComputedVecsFromHeightStrict::forced_import(
|
||||
path,
|
||||
"low_in_sats",
|
||||
version + VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_min(),
|
||||
VecBuilderOptions::default().add_min(),
|
||||
)?,
|
||||
chainindexes_to_close_in_sats: ComputedVecsFromHeightStrict::forced_import(
|
||||
path,
|
||||
"close_in_sats",
|
||||
version + VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
weekindex_to_ohlc: EagerVec::forced_import(
|
||||
path,
|
||||
@@ -332,6 +354,18 @@ impl Vecs {
|
||||
version + VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
format,
|
||||
)?,
|
||||
semesterindex_to_ohlc: EagerVec::forced_import(
|
||||
path,
|
||||
"ohlc",
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)?,
|
||||
semesterindex_to_ohlc_in_sats: EagerVec::forced_import(
|
||||
path,
|
||||
"ohlc_in_sats",
|
||||
version + VERSION + VERSION_IN_SATS + Version::ZERO,
|
||||
format,
|
||||
)?,
|
||||
yearindex_to_ohlc: EagerVec::forced_import(
|
||||
path,
|
||||
"ohlc",
|
||||
@@ -426,7 +460,19 @@ impl Vecs {
|
||||
starting_indexes.dateindex,
|
||||
&indexes.dateindex_to_date,
|
||||
|(di, d, this)| {
|
||||
let mut ohlc = fetcher.get_date(d).unwrap();
|
||||
let get_prev = || {
|
||||
this.get_or_read(di, &this.mmap().load())
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_owned()
|
||||
};
|
||||
|
||||
let mut ohlc = if di.unwrap_to_usize() + 100 >= this.len() {
|
||||
fetcher.get_date(d).unwrap_or_else(|_| get_prev())
|
||||
} else {
|
||||
get_prev()
|
||||
};
|
||||
|
||||
if let Some(prev) = di.decremented() {
|
||||
let prev_open = *this
|
||||
.get_or_read(prev, &this.mmap().load())
|
||||
@@ -604,12 +650,15 @@ impl Vecs {
|
||||
starting_indexes.weekindex,
|
||||
self.timeindexes_to_close.weekindex.unwrap_last(),
|
||||
|(i, close, ..)| {
|
||||
let open = weekindex_first_iter.unwrap_get_inner(i);
|
||||
let high = weekindex_max_iter.unwrap_get_inner(i);
|
||||
let low = weekindex_min_iter.unwrap_get_inner(i);
|
||||
(
|
||||
i,
|
||||
OHLCDollars {
|
||||
open: weekindex_first_iter.unwrap_get_inner(i),
|
||||
high: weekindex_max_iter.unwrap_get_inner(i),
|
||||
low: weekindex_min_iter.unwrap_get_inner(i),
|
||||
open,
|
||||
high,
|
||||
low,
|
||||
close,
|
||||
},
|
||||
)
|
||||
@@ -687,6 +736,27 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let mut semesterindex_first_iter =
|
||||
self.timeindexes_to_open.semesterindex.unwrap_first().iter();
|
||||
let mut semesterindex_max_iter = self.timeindexes_to_high.semesterindex.unwrap_max().iter();
|
||||
let mut semesterindex_min_iter = self.timeindexes_to_low.semesterindex.unwrap_min().iter();
|
||||
self.semesterindex_to_ohlc.compute_transform(
|
||||
starting_indexes.semesterindex,
|
||||
self.timeindexes_to_close.semesterindex.unwrap_last(),
|
||||
|(i, close, ..)| {
|
||||
(
|
||||
i,
|
||||
OHLCDollars {
|
||||
open: semesterindex_first_iter.unwrap_get_inner(i),
|
||||
high: semesterindex_max_iter.unwrap_get_inner(i),
|
||||
low: semesterindex_min_iter.unwrap_get_inner(i),
|
||||
close,
|
||||
},
|
||||
)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let mut yearindex_first_iter = self.timeindexes_to_open.yearindex.unwrap_first().iter();
|
||||
let mut yearindex_max_iter = self.timeindexes_to_high.yearindex.unwrap_max().iter();
|
||||
let mut yearindex_min_iter = self.timeindexes_to_low.yearindex.unwrap_min().iter();
|
||||
@@ -1038,6 +1108,40 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let mut semesterindex_first_iter = self
|
||||
.timeindexes_to_open_in_sats
|
||||
.semesterindex
|
||||
.unwrap_first()
|
||||
.iter();
|
||||
let mut semesterindex_max_iter = self
|
||||
.timeindexes_to_high_in_sats
|
||||
.semesterindex
|
||||
.unwrap_max()
|
||||
.iter();
|
||||
let mut semesterindex_min_iter = self
|
||||
.timeindexes_to_low_in_sats
|
||||
.semesterindex
|
||||
.unwrap_min()
|
||||
.iter();
|
||||
self.semesterindex_to_ohlc_in_sats.compute_transform(
|
||||
starting_indexes.semesterindex,
|
||||
self.timeindexes_to_close_in_sats
|
||||
.semesterindex
|
||||
.unwrap_last(),
|
||||
|(i, close, ..)| {
|
||||
(
|
||||
i,
|
||||
OHLCSats {
|
||||
open: semesterindex_first_iter.unwrap_get_inner(i),
|
||||
high: semesterindex_max_iter.unwrap_get_inner(i),
|
||||
low: semesterindex_min_iter.unwrap_get_inner(i),
|
||||
close,
|
||||
},
|
||||
)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let mut yearindex_first_iter = self
|
||||
.timeindexes_to_open_in_sats
|
||||
.yearindex
|
||||
@@ -1127,6 +1231,7 @@ impl Vecs {
|
||||
&self.difficultyepoch_to_ohlc,
|
||||
&self.monthindex_to_ohlc,
|
||||
&self.quarterindex_to_ohlc,
|
||||
&self.semesterindex_to_ohlc,
|
||||
&self.yearindex_to_ohlc,
|
||||
// &self.halvingepoch_to_ohlc,
|
||||
&self.decadeindex_to_ohlc,
|
||||
@@ -1136,6 +1241,7 @@ impl Vecs {
|
||||
&self.difficultyepoch_to_ohlc_in_sats,
|
||||
&self.monthindex_to_ohlc_in_sats,
|
||||
&self.quarterindex_to_ohlc_in_sats,
|
||||
&self.semesterindex_to_ohlc_in_sats,
|
||||
&self.yearindex_to_ohlc_in_sats,
|
||||
// &self.halvingepoch_to_ohlc_in_sats,
|
||||
&self.decadeindex_to_ohlc_in_sats,
|
||||
|
||||
@@ -0,0 +1,474 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{FromCoarserIndex, Result, Version};
|
||||
use brk_exit::Exit;
|
||||
use brk_vec::{
|
||||
AnyCollectableVec, AnyIterableVec, BoxedAnyIterableVec, CloneableAnyIterableVec, Computation,
|
||||
ComputedVec, ComputedVecFrom2, Format, StoredIndex,
|
||||
};
|
||||
|
||||
use crate::vecs::grouped::{EagerVecBuilder, VecBuilderOptions};
|
||||
|
||||
use super::ComputedType;
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedVecBuilder<I, T, S1I, S2T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: ComputedType,
|
||||
S2T: ComputedType,
|
||||
{
|
||||
pub first: Option<Box<ComputedVecFrom2<I, T, S1I, T, I, S2T>>>,
|
||||
pub average: Option<Box<ComputedVecFrom2<I, T, S1I, T, I, S2T>>>,
|
||||
pub sum: Option<Box<ComputedVecFrom2<I, T, S1I, T, I, S2T>>>,
|
||||
pub max: Option<Box<ComputedVecFrom2<I, T, S1I, T, I, S2T>>>,
|
||||
pub min: Option<Box<ComputedVecFrom2<I, T, S1I, T, I, S2T>>>,
|
||||
pub last: Option<Box<ComputedVecFrom2<I, T, S1I, T, I, S2T>>>,
|
||||
pub cumulative: Option<Box<ComputedVecFrom2<I, T, S1I, T, I, S2T>>>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<I, T, S1I, S2T> ComputedVecBuilder<I, T, S1I, S2T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: ComputedType + 'static,
|
||||
S1I: StoredIndex + 'static + FromCoarserIndex<I>,
|
||||
S2T: ComputedType,
|
||||
{
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
version: Version,
|
||||
format: Format,
|
||||
computation: Computation,
|
||||
source: Option<BoxedAnyIterableVec<S1I, T>>,
|
||||
source_extra: &EagerVecBuilder<S1I, T>,
|
||||
len_source: BoxedAnyIterableVec<I, S2T>,
|
||||
options: ComputedVecBuilderOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let only_one_active = options.is_only_one_active();
|
||||
|
||||
let suffix = |s: &str| format!("{name}_{s}");
|
||||
|
||||
let maybe_suffix = |s: &str| {
|
||||
if only_one_active {
|
||||
name.to_string()
|
||||
} else {
|
||||
suffix(s)
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
first: options.first.then(|| {
|
||||
Box::new(
|
||||
ComputedVec::forced_import_or_init_from_2(
|
||||
computation,
|
||||
path,
|
||||
&maybe_suffix("first"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
source_extra
|
||||
.first
|
||||
.as_ref()
|
||||
.map_or_else(|| source.as_ref().unwrap().clone(), |v| v.clone()),
|
||||
len_source.clone(),
|
||||
|i: I, source, len_source| {
|
||||
if i.unwrap_to_usize() >= len_source.len() {
|
||||
return None;
|
||||
}
|
||||
source
|
||||
.next_at(S1I::min_from(i))
|
||||
.map(|(_, cow)| cow.into_owned())
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
last: options.last.then(|| {
|
||||
Box::new(
|
||||
ComputedVec::forced_import_or_init_from_2(
|
||||
computation,
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
source_extra.last.as_ref().map_or_else(
|
||||
|| {
|
||||
source
|
||||
.as_ref()
|
||||
.unwrap_or_else(|| {
|
||||
dbg!(path, name, I::to_string());
|
||||
panic!()
|
||||
})
|
||||
.clone()
|
||||
},
|
||||
|v| v.clone(),
|
||||
),
|
||||
len_source.clone(),
|
||||
|i: I, source, len_source| {
|
||||
if i.unwrap_to_usize() >= len_source.len() {
|
||||
return None;
|
||||
}
|
||||
source
|
||||
.next_at(S1I::max_from(i, source.len()))
|
||||
.map(|(_, cow)| cow.into_owned())
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
min: options.min.then(|| {
|
||||
Box::new(
|
||||
ComputedVec::forced_import_or_init_from_2(
|
||||
computation,
|
||||
path,
|
||||
&maybe_suffix("min"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
source_extra
|
||||
.min
|
||||
.as_ref()
|
||||
.map_or_else(|| source.as_ref().unwrap().clone(), |v| v.clone()),
|
||||
len_source.clone(),
|
||||
|i: I, source, len_source| {
|
||||
if i.unwrap_to_usize() >= len_source.len() {
|
||||
return None;
|
||||
}
|
||||
S1I::inclusive_range_from(i, source.len())
|
||||
.flat_map(|i| source.next_at(i).map(|(_, cow)| cow.into_owned()))
|
||||
.min()
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
max: options.max.then(|| {
|
||||
Box::new(
|
||||
ComputedVec::forced_import_or_init_from_2(
|
||||
computation,
|
||||
path,
|
||||
&maybe_suffix("max"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
source_extra
|
||||
.max
|
||||
.as_ref()
|
||||
.map_or_else(|| source.as_ref().unwrap().clone(), |v| v.clone()),
|
||||
len_source.clone(),
|
||||
|i: I, source, len_source| {
|
||||
if i.unwrap_to_usize() >= len_source.len() {
|
||||
return None;
|
||||
}
|
||||
S1I::inclusive_range_from(i, source.len())
|
||||
.flat_map(|i| source.next_at(i).map(|(_, cow)| cow.into_owned()))
|
||||
.max()
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
average: options.average.then(|| {
|
||||
Box::new(
|
||||
ComputedVec::forced_import_or_init_from_2(
|
||||
computation,
|
||||
path,
|
||||
&maybe_suffix("average"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
source_extra
|
||||
.average
|
||||
.as_ref()
|
||||
.map_or_else(|| source.as_ref().unwrap().clone(), |v| v.clone()),
|
||||
len_source.clone(),
|
||||
|i: I, source, len_source| {
|
||||
if i.unwrap_to_usize() >= len_source.len() {
|
||||
return None;
|
||||
}
|
||||
let vec = S1I::inclusive_range_from(i, source.len())
|
||||
.flat_map(|i| source.next_at(i).map(|(_, cow)| cow.into_owned()))
|
||||
.collect::<Vec<_>>();
|
||||
if vec.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let mut sum = T::from(0);
|
||||
let len = vec.len();
|
||||
vec.into_iter().for_each(|v| sum += v);
|
||||
Some(sum / len)
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
sum: options.sum.then(|| {
|
||||
Box::new(
|
||||
ComputedVec::forced_import_or_init_from_2(
|
||||
computation,
|
||||
path,
|
||||
&(if !options.last && !options.average && !options.min && !options.max {
|
||||
name.to_string()
|
||||
} else {
|
||||
maybe_suffix("sum")
|
||||
}),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
source_extra
|
||||
.sum
|
||||
.as_ref()
|
||||
.map_or_else(|| source.as_ref().unwrap().clone(), |v| v.clone()),
|
||||
len_source.clone(),
|
||||
|i: I, source, len_source| {
|
||||
if i.unwrap_to_usize() >= len_source.len() {
|
||||
return None;
|
||||
}
|
||||
let vec = S1I::inclusive_range_from(i, source.len())
|
||||
.flat_map(|i| source.next_at(i).map(|(_, cow)| cow.into_owned()))
|
||||
.collect::<Vec<_>>();
|
||||
if vec.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let mut sum = T::from(0);
|
||||
vec.into_iter().for_each(|v| sum += v);
|
||||
Some(sum)
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
cumulative: options.cumulative.then(|| {
|
||||
Box::new(
|
||||
ComputedVec::forced_import_or_init_from_2(
|
||||
computation,
|
||||
path,
|
||||
&suffix("cumulative"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
source_extra.cumulative.as_ref().unwrap().boxed_clone(),
|
||||
len_source.clone(),
|
||||
|i: I, source, len_source| {
|
||||
if i.unwrap_to_usize() >= len_source.len() {
|
||||
return None;
|
||||
}
|
||||
source
|
||||
.next_at(S1I::max_from(i, source.len()))
|
||||
.map(|(_, cow)| cow.into_owned())
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute_if_necessary<T2>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
len_source: &impl AnyIterableVec<I, T2>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
if let Some(first) = self.first.as_mut() {
|
||||
first.compute_if_necessary(max_from, len_source, exit)?;
|
||||
}
|
||||
if let Some(last) = self.last.as_mut() {
|
||||
last.compute_if_necessary(max_from, len_source, exit)?;
|
||||
}
|
||||
if let Some(min) = self.min.as_mut() {
|
||||
min.compute_if_necessary(max_from, len_source, exit)?;
|
||||
}
|
||||
if let Some(max) = self.max.as_mut() {
|
||||
max.compute_if_necessary(max_from, len_source, exit)?;
|
||||
}
|
||||
if let Some(average) = self.average.as_mut() {
|
||||
average.compute_if_necessary(max_from, len_source, exit)?;
|
||||
}
|
||||
if let Some(sum) = self.sum.as_mut() {
|
||||
sum.compute_if_necessary(max_from, len_source, exit)?;
|
||||
}
|
||||
if let Some(cumulative) = self.cumulative.as_mut() {
|
||||
cumulative.compute_if_necessary(max_from, len_source, exit)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn starting_index(&self, max_from: I) -> I {
|
||||
max_from.min(I::from(
|
||||
self.vecs().into_iter().map(|v| v.len()).min().unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn unwrap_first(&self) -> &ComputedVecFrom2<I, T, S1I, T, I, S2T> {
|
||||
self.first.as_ref().unwrap()
|
||||
}
|
||||
#[allow(unused)]
|
||||
pub fn unwrap_average(&self) -> &ComputedVecFrom2<I, T, S1I, T, I, S2T> {
|
||||
self.average.as_ref().unwrap()
|
||||
}
|
||||
pub fn unwrap_sum(&self) -> &ComputedVecFrom2<I, T, S1I, T, I, S2T> {
|
||||
self.sum.as_ref().unwrap()
|
||||
}
|
||||
pub fn unwrap_max(&self) -> &ComputedVecFrom2<I, T, S1I, T, I, S2T> {
|
||||
self.max.as_ref().unwrap()
|
||||
}
|
||||
pub fn unwrap_min(&self) -> &ComputedVecFrom2<I, T, S1I, T, I, S2T> {
|
||||
self.min.as_ref().unwrap()
|
||||
}
|
||||
pub fn unwrap_last(&self) -> &ComputedVecFrom2<I, T, S1I, T, I, S2T> {
|
||||
self.last.as_ref().unwrap()
|
||||
}
|
||||
#[allow(unused)]
|
||||
pub fn unwrap_cumulative(&self) -> &ComputedVecFrom2<I, T, S1I, T, I, S2T> {
|
||||
self.cumulative.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
let mut v: Vec<&dyn AnyCollectableVec> = vec![];
|
||||
|
||||
if let Some(first) = self.first.as_ref() {
|
||||
v.push(first.as_ref());
|
||||
}
|
||||
if let Some(last) = self.last.as_ref() {
|
||||
v.push(last.as_ref());
|
||||
}
|
||||
if let Some(min) = self.min.as_ref() {
|
||||
v.push(min.as_ref());
|
||||
}
|
||||
if let Some(max) = self.max.as_ref() {
|
||||
v.push(max.as_ref());
|
||||
}
|
||||
if let Some(average) = self.average.as_ref() {
|
||||
v.push(average.as_ref());
|
||||
}
|
||||
if let Some(sum) = self.sum.as_ref() {
|
||||
v.push(sum.as_ref());
|
||||
}
|
||||
if let Some(cumulative) = self.cumulative.as_ref() {
|
||||
v.push(cumulative.as_ref());
|
||||
}
|
||||
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Copy)]
|
||||
pub struct ComputedVecBuilderOptions {
|
||||
average: bool,
|
||||
sum: bool,
|
||||
max: bool,
|
||||
min: bool,
|
||||
first: bool,
|
||||
last: bool,
|
||||
cumulative: bool,
|
||||
}
|
||||
|
||||
impl From<VecBuilderOptions> for ComputedVecBuilderOptions {
|
||||
fn from(value: VecBuilderOptions) -> Self {
|
||||
Self {
|
||||
average: value.average(),
|
||||
sum: value.sum(),
|
||||
max: value.max(),
|
||||
min: value.min(),
|
||||
first: value.first(),
|
||||
last: value.last(),
|
||||
cumulative: value.cumulative(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ComputedVecBuilderOptions {
|
||||
pub fn add_first(mut self) -> Self {
|
||||
self.first = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_last(mut self) -> Self {
|
||||
self.last = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_min(mut self) -> Self {
|
||||
self.min = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_max(mut self) -> Self {
|
||||
self.max = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_average(mut self) -> Self {
|
||||
self.average = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_sum(mut self) -> Self {
|
||||
self.sum = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_cumulative(mut self) -> Self {
|
||||
self.cumulative = true;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_min(mut self) -> Self {
|
||||
self.min = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_max(mut self) -> Self {
|
||||
self.max = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_average(mut self) -> Self {
|
||||
self.average = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_sum(mut self) -> Self {
|
||||
self.sum = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_cumulative(mut self) -> Self {
|
||||
self.cumulative = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_minmax(mut self) -> Self {
|
||||
self.min = true;
|
||||
self.max = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_only_one_active(&self) -> bool {
|
||||
[
|
||||
self.average,
|
||||
self.sum,
|
||||
self.max,
|
||||
self.min,
|
||||
self.first,
|
||||
self.last,
|
||||
self.cumulative,
|
||||
]
|
||||
.iter()
|
||||
.filter(|b| **b)
|
||||
.count()
|
||||
== 1
|
||||
}
|
||||
|
||||
pub fn copy_self_extra(&self) -> Self {
|
||||
Self {
|
||||
cumulative: self.cumulative,
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
+66
-28
@@ -10,7 +10,7 @@ use crate::utils::get_percentile;
|
||||
use super::ComputedType;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ComputedVecBuilder<I, T>
|
||||
pub struct EagerVecBuilder<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: ComputedType,
|
||||
@@ -31,7 +31,7 @@ where
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<I, T> ComputedVecBuilder<I, T>
|
||||
impl<I, T> EagerVecBuilder<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: ComputedType,
|
||||
@@ -41,20 +41,10 @@ where
|
||||
name: &str,
|
||||
version: Version,
|
||||
format: Format,
|
||||
options: StorableVecGeneatorOptions,
|
||||
options: VecBuilderOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let only_one_active = options.is_only_one_active();
|
||||
|
||||
let prefix = |s: &str| format!("{s}_{name}");
|
||||
|
||||
let maybe_prefix = |s: &str| {
|
||||
if only_one_active {
|
||||
name.to_string()
|
||||
} else {
|
||||
prefix(s)
|
||||
}
|
||||
};
|
||||
|
||||
let suffix = |s: &str| format!("{name}_{s}");
|
||||
|
||||
let maybe_suffix = |s: &str| {
|
||||
@@ -70,7 +60,7 @@ where
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&maybe_prefix("first"),
|
||||
&maybe_suffix("first"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
@@ -130,7 +120,7 @@ where
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&(if !options.last {
|
||||
&(if !options.last && !options.average && !options.min && !options.max {
|
||||
name.to_string()
|
||||
} else {
|
||||
maybe_suffix("sum")
|
||||
@@ -145,7 +135,7 @@ where
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&prefix("cumulative"),
|
||||
&suffix("cumulative"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
@@ -221,7 +211,7 @@ where
|
||||
cumulative_vec.iter().unwrap_get_inner(index)
|
||||
});
|
||||
source.iter_at(index).try_for_each(|(i, v)| -> Result<()> {
|
||||
cumulative = cumulative.clone() + v.into_inner();
|
||||
cumulative = cumulative.clone() + v.into_owned();
|
||||
cumulative_vec.forced_push_at(i, cumulative.clone(), exit)
|
||||
})?;
|
||||
|
||||
@@ -261,7 +251,7 @@ where
|
||||
first_indexes
|
||||
.iter_at(index)
|
||||
.try_for_each(|(i, first_index)| -> Result<()> {
|
||||
let first_index = first_index.into_inner();
|
||||
let first_index = first_index.into_owned();
|
||||
|
||||
let count_index = count_indexes_iter.unwrap_get_inner(i);
|
||||
|
||||
@@ -284,7 +274,7 @@ where
|
||||
// dbg!(first_index, count_index, last_index);
|
||||
// })
|
||||
// .unwrap()
|
||||
// .into_inner();
|
||||
// .into_owned();
|
||||
last.forced_push_at(index, v, exit)?;
|
||||
}
|
||||
|
||||
@@ -304,7 +294,7 @@ where
|
||||
source_iter.set(first_index);
|
||||
let mut values = (&mut source_iter)
|
||||
.take(*count_index)
|
||||
.map(|(_, v)| v.into_inner())
|
||||
.map(|(_, v)| v.into_owned())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if needs_sorted {
|
||||
@@ -394,7 +384,7 @@ where
|
||||
pub fn from_aligned<I2>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
source: &ComputedVecBuilder<I2, T>,
|
||||
source: &EagerVecBuilder<I2, T>,
|
||||
first_indexes: &impl AnyIterableVec<I, I2>,
|
||||
count_indexes: &impl AnyIterableVec<I, StoredUsize>,
|
||||
exit: &Exit,
|
||||
@@ -435,7 +425,7 @@ where
|
||||
first_indexes
|
||||
.iter_at(index)
|
||||
.try_for_each(|(i, first_index, ..)| -> Result<()> {
|
||||
let first_index = first_index.into_inner();
|
||||
let first_index = first_index.into_owned();
|
||||
|
||||
let count_index = count_indexes_iter.unwrap_get_inner(i);
|
||||
|
||||
@@ -473,7 +463,7 @@ where
|
||||
source_max_iter.set(first_index);
|
||||
let mut values = source_max_iter
|
||||
.take(*count_index)
|
||||
.map(|(_, v)| v.into_inner())
|
||||
.map(|(_, v)| v.into_owned())
|
||||
.collect::<Vec<_>>();
|
||||
values.sort_unstable();
|
||||
max.forced_push_at(i, values.last().unwrap().clone(), exit)?;
|
||||
@@ -484,7 +474,7 @@ where
|
||||
source_min_iter.set(first_index);
|
||||
let mut values = source_min_iter
|
||||
.take(*count_index)
|
||||
.map(|(_, v)| v.into_inner())
|
||||
.map(|(_, v)| v.into_owned())
|
||||
.collect::<Vec<_>>();
|
||||
values.sort_unstable();
|
||||
min.forced_push_at(i, values.first().unwrap().clone(), exit)?;
|
||||
@@ -497,7 +487,7 @@ where
|
||||
source_average_iter.set(first_index);
|
||||
let values = source_average_iter
|
||||
.take(*count_index)
|
||||
.map(|(_, v)| v.into_inner())
|
||||
.map(|(_, v)| v.into_owned())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let len = values.len();
|
||||
@@ -513,7 +503,7 @@ where
|
||||
source_sum_iter.set(first_index);
|
||||
let values = source_sum_iter
|
||||
.take(*count_index)
|
||||
.map(|(_, v)| v.into_inner())
|
||||
.map(|(_, v)| v.into_owned())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let sum = values.into_iter().fold(T::from(0), |a, b| a + b);
|
||||
@@ -716,7 +706,7 @@ where
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Copy)]
|
||||
pub struct StorableVecGeneatorOptions {
|
||||
pub struct VecBuilderOptions {
|
||||
average: bool,
|
||||
sum: bool,
|
||||
max: bool,
|
||||
@@ -731,7 +721,55 @@ pub struct StorableVecGeneatorOptions {
|
||||
cumulative: bool,
|
||||
}
|
||||
|
||||
impl StorableVecGeneatorOptions {
|
||||
impl VecBuilderOptions {
|
||||
pub fn average(&self) -> bool {
|
||||
self.average
|
||||
}
|
||||
|
||||
pub fn sum(&self) -> bool {
|
||||
self.sum
|
||||
}
|
||||
|
||||
pub fn max(&self) -> bool {
|
||||
self.max
|
||||
}
|
||||
|
||||
pub fn _90p(&self) -> bool {
|
||||
self._90p
|
||||
}
|
||||
|
||||
pub fn _75p(&self) -> bool {
|
||||
self._75p
|
||||
}
|
||||
|
||||
pub fn median(&self) -> bool {
|
||||
self.median
|
||||
}
|
||||
|
||||
pub fn _25p(&self) -> bool {
|
||||
self._25p
|
||||
}
|
||||
|
||||
pub fn _10p(&self) -> bool {
|
||||
self._10p
|
||||
}
|
||||
|
||||
pub fn min(&self) -> bool {
|
||||
self.min
|
||||
}
|
||||
|
||||
pub fn first(&self) -> bool {
|
||||
self.first
|
||||
}
|
||||
|
||||
pub fn last(&self) -> bool {
|
||||
self.last
|
||||
}
|
||||
|
||||
pub fn cumulative(&self) -> bool {
|
||||
self.cumulative
|
||||
}
|
||||
|
||||
pub fn add_first(mut self) -> Self {
|
||||
self.first = true;
|
||||
self
|
||||
@@ -1,15 +1,18 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{
|
||||
DateIndex, DecadeIndex, MonthIndex, QuarterIndex, Result, Version, WeekIndex, YearIndex,
|
||||
DateIndex, DecadeIndex, MonthIndex, QuarterIndex, Result, SemesterIndex, Version, WeekIndex,
|
||||
YearIndex,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, AnyIterableVec, EagerVec, Format};
|
||||
use brk_vec::{
|
||||
AnyCollectableVec, AnyIterableVec, CloneableAnyIterableVec, Computation, EagerVec, Format,
|
||||
};
|
||||
|
||||
use crate::vecs::{Indexes, indexes};
|
||||
use crate::vecs::{Indexes, grouped::ComputedVecBuilder, indexes};
|
||||
|
||||
use super::{ComputedType, ComputedVecBuilder, StorableVecGeneatorOptions};
|
||||
use super::{ComputedType, EagerVecBuilder, Source, VecBuilderOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedVecsFromDateIndex<T>
|
||||
@@ -17,33 +20,37 @@ where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub dateindex: Option<EagerVec<DateIndex, T>>,
|
||||
pub dateindex_extra: ComputedVecBuilder<DateIndex, T>,
|
||||
pub weekindex: ComputedVecBuilder<WeekIndex, T>,
|
||||
pub monthindex: ComputedVecBuilder<MonthIndex, T>,
|
||||
pub quarterindex: ComputedVecBuilder<QuarterIndex, T>,
|
||||
pub yearindex: ComputedVecBuilder<YearIndex, T>,
|
||||
pub decadeindex: ComputedVecBuilder<DecadeIndex, T>,
|
||||
pub dateindex_extra: EagerVecBuilder<DateIndex, T>,
|
||||
pub weekindex: ComputedVecBuilder<WeekIndex, T, DateIndex, WeekIndex>,
|
||||
pub monthindex: ComputedVecBuilder<MonthIndex, T, DateIndex, MonthIndex>,
|
||||
pub quarterindex: ComputedVecBuilder<QuarterIndex, T, DateIndex, QuarterIndex>,
|
||||
pub semesterindex: ComputedVecBuilder<SemesterIndex, T, DateIndex, SemesterIndex>,
|
||||
pub yearindex: ComputedVecBuilder<YearIndex, T, DateIndex, YearIndex>,
|
||||
pub decadeindex: ComputedVecBuilder<DecadeIndex, T, DateIndex, DecadeIndex>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<T> ComputedVecsFromDateIndex<T>
|
||||
where
|
||||
T: ComputedType,
|
||||
T: ComputedType + 'static,
|
||||
{
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
compute_source: bool,
|
||||
source: Source<DateIndex, T>,
|
||||
version: Version,
|
||||
format: Format,
|
||||
options: StorableVecGeneatorOptions,
|
||||
computation: Computation,
|
||||
indexes: &indexes::Vecs,
|
||||
options: VecBuilderOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let dateindex = compute_source.then(|| {
|
||||
let dateindex = source.is_compute().then(|| {
|
||||
EagerVec::forced_import(path, name, version + VERSION + Version::ZERO, format).unwrap()
|
||||
});
|
||||
|
||||
let dateindex_extra = ComputedVecBuilder::forced_import(
|
||||
let dateindex_extra = EagerVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
@@ -53,44 +60,77 @@ where
|
||||
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
let dateindex_source = source.vec().or(dateindex.as_ref().map(|v| v.boxed_clone()));
|
||||
|
||||
Ok(Self {
|
||||
dateindex,
|
||||
dateindex_extra,
|
||||
weekindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
computation,
|
||||
dateindex_source.clone(),
|
||||
&dateindex_extra,
|
||||
indexes.weekindex_to_weekindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
monthindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
Computation::Lazy,
|
||||
dateindex_source.clone(),
|
||||
&dateindex_extra,
|
||||
indexes.monthindex_to_monthindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
quarterindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
Computation::Lazy,
|
||||
dateindex_source.clone(),
|
||||
&dateindex_extra,
|
||||
indexes.quarterindex_to_quarterindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
semesterindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
Computation::Lazy,
|
||||
dateindex_source.clone(),
|
||||
&dateindex_extra,
|
||||
indexes.semesterindex_to_semesterindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
yearindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
Computation::Lazy,
|
||||
dateindex_source.clone(),
|
||||
&dateindex_extra,
|
||||
indexes.yearindex_to_yearindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
decadeindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
Computation::Lazy,
|
||||
dateindex_source.clone(),
|
||||
&dateindex_extra,
|
||||
indexes.decadeindex_to_decadeindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
dateindex,
|
||||
dateindex_extra,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -133,65 +173,45 @@ where
|
||||
if let Some(dateindex) = dateindex {
|
||||
self.dateindex_extra
|
||||
.extend(starting_indexes.dateindex, dateindex, exit)?;
|
||||
|
||||
self.weekindex.compute(
|
||||
starting_indexes.weekindex,
|
||||
dateindex,
|
||||
&indexes.weekindex_to_first_dateindex,
|
||||
&indexes.weekindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex.compute(
|
||||
starting_indexes.monthindex,
|
||||
dateindex,
|
||||
&indexes.monthindex_to_first_dateindex,
|
||||
&indexes.monthindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
} else {
|
||||
let dateindex = self.dateindex.as_ref().unwrap();
|
||||
|
||||
self.dateindex_extra
|
||||
.extend(starting_indexes.dateindex, dateindex, exit)?;
|
||||
|
||||
self.weekindex.compute(
|
||||
starting_indexes.weekindex,
|
||||
dateindex,
|
||||
&indexes.weekindex_to_first_dateindex,
|
||||
&indexes.weekindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex.compute(
|
||||
starting_indexes.monthindex,
|
||||
dateindex,
|
||||
&indexes.monthindex_to_first_dateindex,
|
||||
&indexes.monthindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
self.quarterindex.from_aligned(
|
||||
self.weekindex.compute_if_necessary(
|
||||
starting_indexes.weekindex,
|
||||
&indexes.weekindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex.compute_if_necessary(
|
||||
starting_indexes.monthindex,
|
||||
&indexes.monthindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.quarterindex.compute_if_necessary(
|
||||
starting_indexes.quarterindex,
|
||||
&self.monthindex,
|
||||
&indexes.quarterindex_to_first_monthindex,
|
||||
&indexes.quarterindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex.from_aligned(
|
||||
self.semesterindex.compute_if_necessary(
|
||||
starting_indexes.semesterindex,
|
||||
&indexes.semesterindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex.compute_if_necessary(
|
||||
starting_indexes.yearindex,
|
||||
&self.monthindex,
|
||||
&indexes.yearindex_to_first_monthindex,
|
||||
&indexes.yearindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex.from_aligned(
|
||||
self.decadeindex.compute_if_necessary(
|
||||
starting_indexes.decadeindex,
|
||||
&self.yearindex,
|
||||
&indexes.decadeindex_to_first_yearindex,
|
||||
&indexes.decadeindex_to_yearindex_count,
|
||||
exit,
|
||||
)?;
|
||||
@@ -208,6 +228,7 @@ where
|
||||
self.weekindex.vecs(),
|
||||
self.monthindex.vecs(),
|
||||
self.quarterindex.vecs(),
|
||||
self.semesterindex.vecs(),
|
||||
self.yearindex.vecs(),
|
||||
self.decadeindex.vecs(),
|
||||
]
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{
|
||||
DateIndex, DecadeIndex, DifficultyEpoch, Height, MonthIndex, QuarterIndex, Result, Version,
|
||||
WeekIndex, YearIndex,
|
||||
DateIndex, DecadeIndex, DifficultyEpoch, Height, MonthIndex, QuarterIndex, Result,
|
||||
SemesterIndex, Version, WeekIndex, YearIndex,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, AnyIterableVec, EagerVec, Format};
|
||||
use brk_vec::{
|
||||
AnyCollectableVec, AnyIterableVec, CloneableAnyIterableVec, Computation, EagerVec, Format,
|
||||
};
|
||||
|
||||
use crate::vecs::{Indexes, indexes};
|
||||
use crate::vecs::{
|
||||
Indexes,
|
||||
grouped::{ComputedVecBuilder, Source},
|
||||
indexes,
|
||||
};
|
||||
|
||||
use super::{ComputedType, ComputedVecBuilder, StorableVecGeneatorOptions};
|
||||
use super::{ComputedType, EagerVecBuilder, VecBuilderOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedVecsFromHeight<T>
|
||||
@@ -18,37 +24,41 @@ where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub height: Option<EagerVec<Height, T>>,
|
||||
pub height_extra: ComputedVecBuilder<Height, T>,
|
||||
pub dateindex: ComputedVecBuilder<DateIndex, T>,
|
||||
pub weekindex: ComputedVecBuilder<WeekIndex, T>,
|
||||
pub difficultyepoch: ComputedVecBuilder<DifficultyEpoch, T>,
|
||||
pub monthindex: ComputedVecBuilder<MonthIndex, T>,
|
||||
pub quarterindex: ComputedVecBuilder<QuarterIndex, T>,
|
||||
pub yearindex: ComputedVecBuilder<YearIndex, T>,
|
||||
pub height_extra: EagerVecBuilder<Height, T>,
|
||||
pub dateindex: EagerVecBuilder<DateIndex, T>,
|
||||
pub weekindex: ComputedVecBuilder<WeekIndex, T, DateIndex, WeekIndex>,
|
||||
pub difficultyepoch: EagerVecBuilder<DifficultyEpoch, T>,
|
||||
pub monthindex: ComputedVecBuilder<MonthIndex, T, DateIndex, MonthIndex>,
|
||||
pub quarterindex: ComputedVecBuilder<QuarterIndex, T, DateIndex, QuarterIndex>,
|
||||
pub semesterindex: ComputedVecBuilder<SemesterIndex, T, DateIndex, SemesterIndex>,
|
||||
pub yearindex: ComputedVecBuilder<YearIndex, T, DateIndex, YearIndex>,
|
||||
// TODO: pub halvingepoch: StorableVecGeneator<Halvingepoch, T>,
|
||||
pub decadeindex: ComputedVecBuilder<DecadeIndex, T>,
|
||||
pub decadeindex: ComputedVecBuilder<DecadeIndex, T, DateIndex, DecadeIndex>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<T> ComputedVecsFromHeight<T>
|
||||
where
|
||||
T: ComputedType + Ord + From<f64>,
|
||||
T: ComputedType + Ord + From<f64> + 'static,
|
||||
f64: From<T>,
|
||||
{
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
compute_source: bool,
|
||||
source: Source<Height, T>,
|
||||
version: Version,
|
||||
format: Format,
|
||||
options: StorableVecGeneatorOptions,
|
||||
computation: Computation,
|
||||
indexes: &indexes::Vecs,
|
||||
options: VecBuilderOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let height = compute_source.then(|| {
|
||||
let height = source.is_compute().then(|| {
|
||||
EagerVec::forced_import(path, name, version + VERSION + Version::ZERO, format).unwrap()
|
||||
});
|
||||
|
||||
let height_extra = ComputedVecBuilder::forced_import(
|
||||
let height_extra = EagerVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
@@ -56,7 +66,7 @@ where
|
||||
options.copy_self_extra(),
|
||||
)?;
|
||||
|
||||
let dateindex = ComputedVecBuilder::forced_import(
|
||||
let dateindex = EagerVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
@@ -67,46 +77,77 @@ where
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
Ok(Self {
|
||||
height,
|
||||
height_extra,
|
||||
dateindex,
|
||||
weekindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
difficultyepoch: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
computation,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.weekindex_to_weekindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
monthindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
Computation::Lazy,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.monthindex_to_monthindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
quarterindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
Computation::Lazy,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.quarterindex_to_quarterindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
semesterindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
Computation::Lazy,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.semesterindex_to_semesterindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
yearindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
Computation::Lazy,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.yearindex_to_yearindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
decadeindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
Computation::Lazy,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.decadeindex_to_decadeindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
// halvingepoch: StorableVecGeneator::forced_import(path, name, version + VERSION + Version::ZERO, format, options)?,
|
||||
decadeindex: ComputedVecBuilder::forced_import(
|
||||
height,
|
||||
height_extra,
|
||||
dateindex,
|
||||
difficultyepoch: EagerVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
@@ -144,9 +185,9 @@ where
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
height: Option<&impl AnyIterableVec<Height, T>>,
|
||||
height_vec: Option<&impl AnyIterableVec<Height, T>>,
|
||||
) -> color_eyre::Result<()> {
|
||||
if let Some(height) = height {
|
||||
if let Some(height) = height_vec {
|
||||
self.height_extra
|
||||
.extend(starting_indexes.height, height, exit)?;
|
||||
|
||||
@@ -188,42 +229,38 @@ where
|
||||
)?;
|
||||
}
|
||||
|
||||
self.weekindex.from_aligned(
|
||||
self.weekindex.compute_if_necessary(
|
||||
starting_indexes.weekindex,
|
||||
&self.dateindex,
|
||||
&indexes.weekindex_to_first_dateindex,
|
||||
&indexes.weekindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex.from_aligned(
|
||||
self.monthindex.compute_if_necessary(
|
||||
starting_indexes.monthindex,
|
||||
&self.dateindex,
|
||||
&indexes.monthindex_to_first_dateindex,
|
||||
&indexes.monthindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.quarterindex.from_aligned(
|
||||
self.quarterindex.compute_if_necessary(
|
||||
starting_indexes.quarterindex,
|
||||
&self.monthindex,
|
||||
&indexes.quarterindex_to_first_monthindex,
|
||||
&indexes.quarterindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex.from_aligned(
|
||||
self.semesterindex.compute_if_necessary(
|
||||
starting_indexes.semesterindex,
|
||||
&indexes.semesterindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex.compute_if_necessary(
|
||||
starting_indexes.yearindex,
|
||||
&self.monthindex,
|
||||
&indexes.yearindex_to_first_monthindex,
|
||||
&indexes.yearindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex.from_aligned(
|
||||
self.decadeindex.compute_if_necessary(
|
||||
starting_indexes.decadeindex,
|
||||
&self.yearindex,
|
||||
&indexes.decadeindex_to_first_yearindex,
|
||||
&indexes.decadeindex_to_yearindex_count,
|
||||
exit,
|
||||
)?;
|
||||
@@ -242,6 +279,7 @@ where
|
||||
self.difficultyepoch.vecs(),
|
||||
self.monthindex.vecs(),
|
||||
self.quarterindex.vecs(),
|
||||
self.semesterindex.vecs(),
|
||||
self.yearindex.vecs(),
|
||||
// self.halvingepoch.vecs(),
|
||||
self.decadeindex.vecs(),
|
||||
|
||||
@@ -7,7 +7,7 @@ use brk_vec::{AnyCollectableVec, EagerVec, Format};
|
||||
|
||||
use crate::vecs::{Indexes, indexes};
|
||||
|
||||
use super::{ComputedType, ComputedVecBuilder, StorableVecGeneatorOptions};
|
||||
use super::{ComputedType, EagerVecBuilder, VecBuilderOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedVecsFromHeightStrict<T>
|
||||
@@ -15,8 +15,8 @@ where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub height: EagerVec<Height, T>,
|
||||
pub height_extra: ComputedVecBuilder<Height, T>,
|
||||
pub difficultyepoch: ComputedVecBuilder<DifficultyEpoch, T>,
|
||||
pub height_extra: EagerVecBuilder<Height, T>,
|
||||
pub difficultyepoch: EagerVecBuilder<DifficultyEpoch, T>,
|
||||
// TODO: pub halvingepoch: StorableVecGeneator<Halvingepoch, T>,
|
||||
}
|
||||
|
||||
@@ -32,12 +32,12 @@ where
|
||||
name: &str,
|
||||
version: Version,
|
||||
format: Format,
|
||||
options: StorableVecGeneatorOptions,
|
||||
options: VecBuilderOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let height =
|
||||
EagerVec::forced_import(path, name, version + VERSION + Version::ZERO, format)?;
|
||||
|
||||
let height_extra = ComputedVecBuilder::forced_import(
|
||||
let height_extra = EagerVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
@@ -50,7 +50,7 @@ where
|
||||
Ok(Self {
|
||||
height,
|
||||
height_extra,
|
||||
difficultyepoch: ComputedVecBuilder::forced_import(
|
||||
difficultyepoch: EagerVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
|
||||
@@ -2,17 +2,22 @@ use std::path::Path;
|
||||
|
||||
use brk_core::{
|
||||
Bitcoin, DateIndex, DecadeIndex, DifficultyEpoch, Dollars, Height, MonthIndex, QuarterIndex,
|
||||
Result, Sats, TxIndex, Version, WeekIndex, YearIndex,
|
||||
Result, Sats, SemesterIndex, TxIndex, Version, WeekIndex, YearIndex,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{
|
||||
AnyCollectableVec, AnyVec, CollectableVec, EagerVec, Format, StoredIndex, VecIterator,
|
||||
AnyCollectableVec, AnyVec, CloneableAnyIterableVec, CollectableVec, Computation, EagerVec,
|
||||
Format, StoredIndex, VecIterator,
|
||||
};
|
||||
|
||||
use crate::vecs::{Indexes, fetched, indexes};
|
||||
use crate::vecs::{
|
||||
Indexes, fetched,
|
||||
grouped::{ComputedVecBuilder, Source},
|
||||
indexes,
|
||||
};
|
||||
|
||||
use super::{ComputedType, ComputedVecBuilder, StorableVecGeneatorOptions};
|
||||
use super::{ComputedType, EagerVecBuilder, VecBuilderOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedVecsFromTxindex<T>
|
||||
@@ -20,40 +25,44 @@ where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub txindex: Option<Box<EagerVec<TxIndex, T>>>,
|
||||
pub height: ComputedVecBuilder<Height, T>,
|
||||
pub dateindex: ComputedVecBuilder<DateIndex, T>,
|
||||
pub weekindex: ComputedVecBuilder<WeekIndex, T>,
|
||||
pub difficultyepoch: ComputedVecBuilder<DifficultyEpoch, T>,
|
||||
pub monthindex: ComputedVecBuilder<MonthIndex, T>,
|
||||
pub quarterindex: ComputedVecBuilder<QuarterIndex, T>,
|
||||
pub yearindex: ComputedVecBuilder<YearIndex, T>,
|
||||
pub height: EagerVecBuilder<Height, T>,
|
||||
pub dateindex: EagerVecBuilder<DateIndex, T>,
|
||||
pub weekindex: ComputedVecBuilder<WeekIndex, T, DateIndex, WeekIndex>,
|
||||
pub difficultyepoch: EagerVecBuilder<DifficultyEpoch, T>,
|
||||
pub monthindex: ComputedVecBuilder<MonthIndex, T, DateIndex, MonthIndex>,
|
||||
pub quarterindex: ComputedVecBuilder<QuarterIndex, T, DateIndex, QuarterIndex>,
|
||||
pub semesterindex: ComputedVecBuilder<SemesterIndex, T, DateIndex, SemesterIndex>,
|
||||
pub yearindex: ComputedVecBuilder<YearIndex, T, DateIndex, YearIndex>,
|
||||
// TODO: pub halvingepoch: StorableVecGeneator<Halvingepoch, T>,
|
||||
pub decadeindex: ComputedVecBuilder<DecadeIndex, T>,
|
||||
pub decadeindex: ComputedVecBuilder<DecadeIndex, T, DateIndex, DecadeIndex>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<T> ComputedVecsFromTxindex<T>
|
||||
where
|
||||
T: ComputedType + Ord + From<f64>,
|
||||
T: ComputedType + Ord + From<f64> + 'static,
|
||||
f64: From<T>,
|
||||
{
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
compute_source: bool,
|
||||
source: Source<TxIndex, T>,
|
||||
version: Version,
|
||||
format: Format,
|
||||
options: StorableVecGeneatorOptions,
|
||||
computation: Computation,
|
||||
indexes: &indexes::Vecs,
|
||||
options: VecBuilderOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let txindex = compute_source.then(|| {
|
||||
let txindex = source.is_compute().then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(path, name, version + VERSION + Version::ZERO, format)
|
||||
.unwrap(),
|
||||
)
|
||||
});
|
||||
|
||||
let height = ComputedVecBuilder::forced_import(
|
||||
let height = EagerVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
@@ -63,45 +72,86 @@ where
|
||||
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
let dateindex = EagerVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?;
|
||||
|
||||
Ok(Self {
|
||||
txindex,
|
||||
height,
|
||||
dateindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
weekindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
difficultyepoch: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
computation,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.weekindex_to_weekindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
monthindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
Computation::Lazy,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.monthindex_to_monthindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
quarterindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
Computation::Lazy,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.quarterindex_to_quarterindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
semesterindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
Computation::Lazy,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.semesterindex_to_semesterindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
yearindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
Computation::Lazy,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.yearindex_to_yearindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
decadeindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
Computation::Lazy,
|
||||
None,
|
||||
&dateindex,
|
||||
indexes.decadeindex_to_decadeindex.boxed_clone(),
|
||||
options.into(),
|
||||
)?,
|
||||
|
||||
txindex,
|
||||
height,
|
||||
dateindex,
|
||||
difficultyepoch: EagerVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
@@ -109,13 +159,6 @@ where
|
||||
options,
|
||||
)?,
|
||||
// halvingepoch: StorableVecGeneator::forced_import(path, name, version + VERSION + Version::ZERO, format, options)?,
|
||||
decadeindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -196,42 +239,38 @@ where
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.weekindex.from_aligned(
|
||||
self.weekindex.compute_if_necessary(
|
||||
starting_indexes.weekindex,
|
||||
&self.dateindex,
|
||||
&indexes.weekindex_to_first_dateindex,
|
||||
&indexes.weekindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex.from_aligned(
|
||||
self.monthindex.compute_if_necessary(
|
||||
starting_indexes.monthindex,
|
||||
&self.dateindex,
|
||||
&indexes.monthindex_to_first_dateindex,
|
||||
&indexes.monthindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.quarterindex.from_aligned(
|
||||
self.quarterindex.compute_if_necessary(
|
||||
starting_indexes.quarterindex,
|
||||
&self.monthindex,
|
||||
&indexes.quarterindex_to_first_monthindex,
|
||||
&indexes.quarterindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex.from_aligned(
|
||||
self.semesterindex.compute_if_necessary(
|
||||
starting_indexes.semesterindex,
|
||||
&indexes.semesterindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex.compute_if_necessary(
|
||||
starting_indexes.yearindex,
|
||||
&self.monthindex,
|
||||
&indexes.yearindex_to_first_monthindex,
|
||||
&indexes.yearindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex.from_aligned(
|
||||
self.decadeindex.compute_if_necessary(
|
||||
starting_indexes.decadeindex,
|
||||
&self.yearindex,
|
||||
&indexes.decadeindex_to_first_yearindex,
|
||||
&indexes.decadeindex_to_yearindex_count,
|
||||
exit,
|
||||
)?;
|
||||
@@ -258,6 +297,7 @@ where
|
||||
self.difficultyepoch.vecs(),
|
||||
self.monthindex.vecs(),
|
||||
self.quarterindex.vecs(),
|
||||
self.semesterindex.vecs(),
|
||||
self.yearindex.vecs(),
|
||||
// self.halvingepoch.vecs(),
|
||||
self.decadeindex.vecs(),
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
mod builder;
|
||||
mod builder_computed;
|
||||
mod builder_eager;
|
||||
mod from_dateindex;
|
||||
mod from_height;
|
||||
mod from_height_strict;
|
||||
mod from_txindex;
|
||||
mod ratio_from_dateindex;
|
||||
mod source;
|
||||
mod r#type;
|
||||
mod value_from_dateindex;
|
||||
mod value_from_height;
|
||||
mod value_from_txindex;
|
||||
mod value_height;
|
||||
|
||||
pub use builder::*;
|
||||
pub use builder_computed::*;
|
||||
pub use builder_eager::*;
|
||||
pub use from_dateindex::*;
|
||||
pub use from_height::*;
|
||||
pub use from_height_strict::*;
|
||||
pub use from_txindex::*;
|
||||
pub use ratio_from_dateindex::*;
|
||||
pub use source::*;
|
||||
use r#type::*;
|
||||
pub use value_from_dateindex::*;
|
||||
pub use value_from_height::*;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,51 @@
|
||||
use brk_vec::BoxedAnyIterableVec;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Source<I, T> {
|
||||
Compute,
|
||||
None,
|
||||
Vec(BoxedAnyIterableVec<I, T>),
|
||||
}
|
||||
|
||||
impl<I, T> Source<I, T> {
|
||||
pub fn is_compute(&self) -> bool {
|
||||
matches!(self, Self::Compute)
|
||||
}
|
||||
|
||||
pub fn is_none(&self) -> bool {
|
||||
matches!(self, Self::None)
|
||||
}
|
||||
|
||||
pub fn is_vec(&self) -> bool {
|
||||
matches!(self, Self::Vec(_))
|
||||
}
|
||||
|
||||
pub fn vec(self) -> Option<BoxedAnyIterableVec<I, T>> {
|
||||
match self {
|
||||
Self::Vec(v) => Some(v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> From<bool> for Source<I, T> {
|
||||
fn from(value: bool) -> Self {
|
||||
if value { Self::Compute } else { Self::None }
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> From<BoxedAnyIterableVec<I, T>> for Source<I, T> {
|
||||
fn from(value: BoxedAnyIterableVec<I, T>) -> Self {
|
||||
Self::Vec(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> From<Option<BoxedAnyIterableVec<I, T>>> for Source<I, T> {
|
||||
fn from(value: Option<BoxedAnyIterableVec<I, T>>) -> Self {
|
||||
if let Some(v) = value {
|
||||
Self::Vec(v)
|
||||
} else {
|
||||
Self::None
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
use std::ops::{Add, Div};
|
||||
use std::ops::{Add, AddAssign, Div};
|
||||
|
||||
use brk_vec::StoredType;
|
||||
|
||||
pub trait ComputedType
|
||||
where
|
||||
Self: StoredType + From<usize> + Div<usize, Output = Self> + Add<Output = Self> + Ord,
|
||||
Self:
|
||||
StoredType + From<usize> + Div<usize, Output = Self> + Add<Output = Self> + AddAssign + Ord,
|
||||
{
|
||||
}
|
||||
impl<T> ComputedType for T where
|
||||
T: StoredType + From<usize> + Div<usize, Output = Self> + Add<Output = Self> + Ord
|
||||
T: StoredType + From<usize> + Div<usize, Output = Self> + Add<Output = Self> + AddAssign + Ord
|
||||
{
|
||||
}
|
||||
|
||||
@@ -3,11 +3,11 @@ use std::path::Path;
|
||||
use brk_core::{Bitcoin, DateIndex, Dollars, Result, Sats, Version};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, CollectableVec, EagerVec, Format, StoredVec};
|
||||
use brk_vec::{AnyCollectableVec, CollectableVec, Computation, EagerVec, Format, StoredVec};
|
||||
|
||||
use crate::vecs::{Indexes, fetched, grouped::ComputedVecsFromDateIndex, indexes};
|
||||
|
||||
use super::StorableVecGeneatorOptions;
|
||||
use super::{Source, VecBuilderOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedValueVecsFromDateIndex {
|
||||
@@ -19,39 +19,48 @@ pub struct ComputedValueVecsFromDateIndex {
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl ComputedValueVecsFromDateIndex {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
compute_source: bool,
|
||||
source: Source<DateIndex, Sats>,
|
||||
version: Version,
|
||||
format: Format,
|
||||
options: StorableVecGeneatorOptions,
|
||||
computation: Computation,
|
||||
options: VecBuilderOptions,
|
||||
compute_dollars: bool,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> color_eyre::Result<Self> {
|
||||
Ok(Self {
|
||||
sats: ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
name,
|
||||
compute_source,
|
||||
source,
|
||||
version + VERSION,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
options,
|
||||
)?,
|
||||
bitcoin: ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
&format!("{name}_in_btc"),
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
options,
|
||||
)?,
|
||||
dollars: compute_dollars.then(|| {
|
||||
ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
&format!("{name}_in_usd"),
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
options,
|
||||
)
|
||||
.unwrap()
|
||||
|
||||
@@ -3,11 +3,11 @@ use std::path::Path;
|
||||
use brk_core::{Bitcoin, Dollars, Height, Result, Sats, Version};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, CollectableVec, EagerVec, Format, StoredVec};
|
||||
use brk_vec::{AnyCollectableVec, CollectableVec, Computation, EagerVec, Format, StoredVec};
|
||||
|
||||
use crate::vecs::{Indexes, fetched, indexes};
|
||||
use crate::vecs::{Indexes, fetched, grouped::Source, indexes};
|
||||
|
||||
use super::{ComputedVecsFromHeight, StorableVecGeneatorOptions};
|
||||
use super::{ComputedVecsFromHeight, VecBuilderOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedValueVecsFromHeight {
|
||||
@@ -19,39 +19,48 @@ pub struct ComputedValueVecsFromHeight {
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl ComputedValueVecsFromHeight {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
compute_source: bool,
|
||||
source: Source<Height, Sats>,
|
||||
version: Version,
|
||||
format: Format,
|
||||
options: StorableVecGeneatorOptions,
|
||||
computation: Computation,
|
||||
options: VecBuilderOptions,
|
||||
compute_dollars: bool,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> color_eyre::Result<Self> {
|
||||
Ok(Self {
|
||||
sats: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
name,
|
||||
compute_source,
|
||||
source,
|
||||
version + VERSION,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
options,
|
||||
)?,
|
||||
bitcoin: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
&format!("{name}_in_btc"),
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
options,
|
||||
)?,
|
||||
dollars: compute_dollars.then(|| {
|
||||
ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
&format!("{name}_in_usd"),
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
options,
|
||||
)
|
||||
.unwrap()
|
||||
|
||||
@@ -4,13 +4,13 @@ use brk_core::{Bitcoin, Close, Dollars, Height, Sats, TxIndex, Version};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{
|
||||
AnyCollectableVec, BoxedAnyIterableVec, CloneableAnyIterableVec, CollectableVec, Computation,
|
||||
ComputedVecFrom3, Format, LazyVecFrom1, StoredIndex, StoredVec,
|
||||
AnyCollectableVec, CloneableAnyIterableVec, CollectableVec, Computation, ComputedVecFrom3,
|
||||
Format, LazyVecFrom1, StoredIndex, StoredVec,
|
||||
};
|
||||
|
||||
use crate::vecs::{Indexes, fetched, indexes};
|
||||
use crate::vecs::{Indexes, fetched, grouped::Source, indexes};
|
||||
|
||||
use super::{ComputedVecsFromTxindex, StorableVecGeneatorOptions};
|
||||
use super::{ComputedVecsFromTxindex, VecBuilderOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedValueVecsFromTxindex {
|
||||
@@ -41,14 +41,13 @@ impl ComputedValueVecsFromTxindex {
|
||||
path: &Path,
|
||||
name: &str,
|
||||
indexes: &indexes::Vecs,
|
||||
source: Option<BoxedAnyIterableVec<TxIndex, Sats>>,
|
||||
source: Source<TxIndex, Sats>,
|
||||
version: Version,
|
||||
computation: Computation,
|
||||
format: Format,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
options: StorableVecGeneatorOptions,
|
||||
options: VecBuilderOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let compute_source = source.is_none();
|
||||
let compute_dollars = fetched.is_some();
|
||||
|
||||
let name_in_btc = format!("{name}_in_btc");
|
||||
@@ -57,19 +56,23 @@ impl ComputedValueVecsFromTxindex {
|
||||
let sats = ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
name,
|
||||
compute_source,
|
||||
source.clone(),
|
||||
version + VERSION,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
options,
|
||||
)?;
|
||||
|
||||
let source_vec = source.vec();
|
||||
|
||||
let bitcoin_txindex = LazyVecFrom1::init(
|
||||
&name_in_btc,
|
||||
version + VERSION,
|
||||
source.map_or_else(|| sats.txindex.as_ref().unwrap().boxed_clone(), |s| s),
|
||||
source_vec.map_or_else(|| sats.txindex.as_ref().unwrap().boxed_clone(), |s| s),
|
||||
|txindex: TxIndex, iter| {
|
||||
iter.next_at(txindex.unwrap_to_usize()).map(|(_, value)| {
|
||||
let sats = value.into_inner();
|
||||
let sats = value.into_owned();
|
||||
Bitcoin::from(sats)
|
||||
})
|
||||
},
|
||||
@@ -78,9 +81,11 @@ impl ComputedValueVecsFromTxindex {
|
||||
let bitcoin = ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
&name_in_btc,
|
||||
false,
|
||||
Source::None,
|
||||
version + VERSION,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
options,
|
||||
)?;
|
||||
|
||||
@@ -100,14 +105,14 @@ impl ComputedValueVecsFromTxindex {
|
||||
height_to_close_iter| {
|
||||
let txindex = txindex.unwrap_to_usize();
|
||||
txindex_to_btc_iter.next_at(txindex).and_then(|(_, value)| {
|
||||
let btc = value.into_inner();
|
||||
let btc = value.into_owned();
|
||||
txindex_to_height_iter
|
||||
.next_at(txindex)
|
||||
.and_then(|(_, value)| {
|
||||
let height = value.into_inner();
|
||||
let height = value.into_owned();
|
||||
height_to_close_iter
|
||||
.next_at(height.unwrap_to_usize())
|
||||
.map(|(_, close)| *close.into_inner() * btc)
|
||||
.map(|(_, close)| *close.into_owned() * btc)
|
||||
})
|
||||
})
|
||||
},
|
||||
@@ -124,9 +129,11 @@ impl ComputedValueVecsFromTxindex {
|
||||
ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
&name_in_usd,
|
||||
false,
|
||||
Source::None,
|
||||
version + VERSION,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
options,
|
||||
)
|
||||
.unwrap()
|
||||
|
||||
@@ -5,7 +5,7 @@ use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, CollectableVec, EagerVec, Format, StoredVec};
|
||||
|
||||
use crate::vecs::{Indexes, fetched, indexes};
|
||||
use crate::vecs::{Indexes, fetched, grouped::Source, indexes};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedHeightValueVecs {
|
||||
@@ -20,13 +20,13 @@ impl ComputedHeightValueVecs {
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
compute_source: bool,
|
||||
source: Source<Height, Sats>,
|
||||
version: Version,
|
||||
format: Format,
|
||||
compute_dollars: bool,
|
||||
) -> color_eyre::Result<Self> {
|
||||
Ok(Self {
|
||||
sats: compute_source.then(|| {
|
||||
sats: source.is_compute().then(|| {
|
||||
EagerVec::forced_import(path, name, version + VERSION + Version::ZERO, format)
|
||||
.unwrap()
|
||||
}),
|
||||
|
||||
@@ -5,8 +5,8 @@ use brk_core::{
|
||||
InputIndex, MonthIndex, OpReturnIndex, OutputIndex, P2AAddressIndex, P2ABytes, P2MSOutputIndex,
|
||||
P2PK33AddressIndex, P2PK33Bytes, P2PK65AddressIndex, P2PK65Bytes, P2PKHAddressIndex,
|
||||
P2PKHBytes, P2SHAddressIndex, P2SHBytes, P2TRAddressIndex, P2TRBytes, P2WPKHAddressIndex,
|
||||
P2WPKHBytes, P2WSHAddressIndex, P2WSHBytes, QuarterIndex, Sats, StoredUsize, Timestamp,
|
||||
TxIndex, Txid, UnknownOutputIndex, Version, WeekIndex, YearIndex,
|
||||
P2WPKHBytes, P2WSHAddressIndex, P2WSHBytes, QuarterIndex, Sats, SemesterIndex, StoredUsize,
|
||||
Timestamp, TxIndex, Txid, UnknownOutputIndex, Version, WeekIndex, YearIndex,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
@@ -50,6 +50,7 @@ pub struct Vecs {
|
||||
pub monthindex_to_first_dateindex: EagerVec<MonthIndex, DateIndex>,
|
||||
pub monthindex_to_monthindex: EagerVec<MonthIndex, MonthIndex>,
|
||||
pub monthindex_to_quarterindex: EagerVec<MonthIndex, QuarterIndex>,
|
||||
pub monthindex_to_semesterindex: EagerVec<MonthIndex, SemesterIndex>,
|
||||
pub monthindex_to_yearindex: EagerVec<MonthIndex, YearIndex>,
|
||||
pub opreturnindex_to_opreturnindex:
|
||||
ComputedVecFrom1<OpReturnIndex, OpReturnIndex, OpReturnIndex, TxIndex>,
|
||||
@@ -76,6 +77,9 @@ pub struct Vecs {
|
||||
pub quarterindex_to_first_monthindex: EagerVec<QuarterIndex, MonthIndex>,
|
||||
pub quarterindex_to_monthindex_count: EagerVec<QuarterIndex, StoredUsize>,
|
||||
pub quarterindex_to_quarterindex: EagerVec<QuarterIndex, QuarterIndex>,
|
||||
pub semesterindex_to_first_monthindex: EagerVec<SemesterIndex, MonthIndex>,
|
||||
pub semesterindex_to_monthindex_count: EagerVec<SemesterIndex, StoredUsize>,
|
||||
pub semesterindex_to_semesterindex: EagerVec<SemesterIndex, SemesterIndex>,
|
||||
pub txindex_to_height: EagerVec<TxIndex, Height>,
|
||||
pub txindex_to_input_count:
|
||||
ComputedVecFrom2<TxIndex, StoredUsize, TxIndex, InputIndex, InputIndex, OutputIndex>,
|
||||
@@ -144,10 +148,10 @@ impl Vecs {
|
||||
txindex_to_first_inputindex_iter
|
||||
.next_at(txindex)
|
||||
.map(|(_, start)| {
|
||||
let start = usize::from(start.into_inner());
|
||||
let start = usize::from(start.into_owned());
|
||||
let end = txindex_to_first_inputindex_iter
|
||||
.next_at(txindex + 1)
|
||||
.map(|(_, v)| usize::from(v.into_inner()))
|
||||
.map(|(_, v)| usize::from(v.into_owned()))
|
||||
.unwrap_or_else(|| inputindex_to_outputindex_iter.len());
|
||||
StoredUsize::from((start..end).count())
|
||||
})
|
||||
@@ -167,10 +171,10 @@ impl Vecs {
|
||||
txindex_to_first_outputindex_iter
|
||||
.next_at(txindex)
|
||||
.map(|(_, start)| {
|
||||
let start = usize::from(start.into_inner());
|
||||
let start = usize::from(start.into_owned());
|
||||
let end = txindex_to_first_outputindex_iter
|
||||
.next_at(txindex + 1)
|
||||
.map(|(_, v)| usize::from(v.into_inner()))
|
||||
.map(|(_, v)| usize::from(v.into_owned()))
|
||||
.unwrap_or_else(|| outputindex_to_value_iter.len());
|
||||
StoredUsize::from((start..end).count())
|
||||
})
|
||||
@@ -413,6 +417,12 @@ impl Vecs {
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)?,
|
||||
monthindex_to_semesterindex: EagerVec::forced_import(
|
||||
path,
|
||||
"semesterindex",
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)?,
|
||||
monthindex_to_yearindex: EagerVec::forced_import(
|
||||
path,
|
||||
"yearindex",
|
||||
@@ -425,6 +435,12 @@ impl Vecs {
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)?,
|
||||
semesterindex_to_first_monthindex: EagerVec::forced_import(
|
||||
path,
|
||||
"first_monthindex",
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)?,
|
||||
weekindex_to_first_dateindex: EagerVec::forced_import(
|
||||
path,
|
||||
"first_dateindex",
|
||||
@@ -443,6 +459,12 @@ impl Vecs {
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)?,
|
||||
semesterindex_to_semesterindex: EagerVec::forced_import(
|
||||
path,
|
||||
"semesterindex",
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)?,
|
||||
weekindex_to_weekindex: EagerVec::forced_import(
|
||||
path,
|
||||
"weekindex",
|
||||
@@ -521,6 +543,12 @@ impl Vecs {
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)?,
|
||||
semesterindex_to_monthindex_count: EagerVec::forced_import(
|
||||
path,
|
||||
"monthindex_count",
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)?,
|
||||
yearindex_to_monthindex_count: EagerVec::forced_import(
|
||||
path,
|
||||
"monthindex_count",
|
||||
@@ -943,6 +971,45 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// ---
|
||||
// SemesterIndex
|
||||
// ---
|
||||
|
||||
let starting_semesterindex = self
|
||||
.monthindex_to_semesterindex
|
||||
.into_iter()
|
||||
.get_inner(starting_monthindex)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.monthindex_to_semesterindex.compute_from_index(
|
||||
starting_monthindex,
|
||||
&self.monthindex_to_first_dateindex,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.semesterindex_to_first_monthindex
|
||||
.compute_inverse_more_to_less(
|
||||
starting_monthindex,
|
||||
&self.monthindex_to_semesterindex,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// let semester_count = self.semesterindex_to_first_monthindex.len();
|
||||
|
||||
self.semesterindex_to_semesterindex.compute_from_index(
|
||||
starting_semesterindex,
|
||||
&self.semesterindex_to_first_monthindex,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.semesterindex_to_monthindex_count
|
||||
.compute_count_from_indexes(
|
||||
starting_semesterindex,
|
||||
&self.semesterindex_to_first_monthindex,
|
||||
&self.monthindex_to_monthindex,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// ---
|
||||
// YearIndex
|
||||
// ---
|
||||
@@ -1051,6 +1118,7 @@ impl Vecs {
|
||||
weekindex: starting_weekindex,
|
||||
monthindex: starting_monthindex,
|
||||
quarterindex: starting_quarterindex,
|
||||
semesterindex: starting_semesterindex,
|
||||
yearindex: starting_yearindex,
|
||||
decadeindex: starting_decadeindex,
|
||||
difficultyepoch: starting_difficultyepoch,
|
||||
@@ -1088,6 +1156,7 @@ impl Vecs {
|
||||
&self.monthindex_to_first_dateindex,
|
||||
&self.monthindex_to_monthindex,
|
||||
&self.monthindex_to_quarterindex,
|
||||
&self.monthindex_to_semesterindex,
|
||||
&self.monthindex_to_yearindex,
|
||||
&self.opreturnindex_to_opreturnindex,
|
||||
&self.outputindex_to_outputindex,
|
||||
@@ -1103,6 +1172,9 @@ impl Vecs {
|
||||
&self.quarterindex_to_first_monthindex,
|
||||
&self.quarterindex_to_monthindex_count,
|
||||
&self.quarterindex_to_quarterindex,
|
||||
&self.semesterindex_to_first_monthindex,
|
||||
&self.semesterindex_to_monthindex_count,
|
||||
&self.semesterindex_to_semesterindex,
|
||||
&self.txindex_to_height,
|
||||
&self.txindex_to_txindex,
|
||||
&self.txindex_to_input_count,
|
||||
@@ -1126,6 +1198,7 @@ pub struct Indexes {
|
||||
pub weekindex: WeekIndex,
|
||||
pub monthindex: MonthIndex,
|
||||
pub quarterindex: QuarterIndex,
|
||||
pub semesterindex: SemesterIndex,
|
||||
pub yearindex: YearIndex,
|
||||
pub decadeindex: DecadeIndex,
|
||||
pub difficultyepoch: DifficultyEpoch,
|
||||
@@ -1145,6 +1218,7 @@ impl Indexes {
|
||||
self.weekindex = WeekIndex::from(self.dateindex);
|
||||
self.monthindex = MonthIndex::from(self.dateindex);
|
||||
self.quarterindex = QuarterIndex::from(self.monthindex);
|
||||
self.semesterindex = SemesterIndex::from(self.monthindex);
|
||||
self.yearindex = YearIndex::from(self.monthindex);
|
||||
self.decadeindex = DecadeIndex::from(self.dateindex);
|
||||
self.difficultyepoch = DifficultyEpoch::from(self.height);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,9 +5,11 @@ use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, Computation, Format, VecIterator};
|
||||
|
||||
use crate::vecs::grouped::Source;
|
||||
|
||||
use super::{
|
||||
Indexes,
|
||||
grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, StorableVecGeneatorOptions},
|
||||
grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, VecBuilderOptions},
|
||||
indexes,
|
||||
};
|
||||
|
||||
@@ -24,33 +26,40 @@ impl Vecs {
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
version: Version,
|
||||
_computation: Computation,
|
||||
computation: Computation,
|
||||
format: Format,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> color_eyre::Result<Self> {
|
||||
Ok(Self {
|
||||
indexes_to_difficulty: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"difficulty",
|
||||
false,
|
||||
Source::None,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
indexes_to_difficultyepoch: ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
"difficultyepoch",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
indexes_to_halvingepoch: ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
"halvingepoch",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ pub mod transactions;
|
||||
pub use indexes::Indexes;
|
||||
use log::info;
|
||||
|
||||
use crate::stores::Stores;
|
||||
|
||||
const VERSION: Version = Version::ONE;
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -58,6 +60,7 @@ impl Vecs {
|
||||
version + VERSION + Version::ZERO,
|
||||
computation,
|
||||
format,
|
||||
&indexes,
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
@@ -68,30 +71,35 @@ impl Vecs {
|
||||
version + VERSION + Version::ZERO,
|
||||
computation,
|
||||
format,
|
||||
&indexes,
|
||||
)?,
|
||||
mining: mining::Vecs::forced_import(
|
||||
path,
|
||||
version + VERSION + Version::ZERO,
|
||||
computation,
|
||||
format,
|
||||
&indexes,
|
||||
)?,
|
||||
constants: constants::Vecs::forced_import(
|
||||
path,
|
||||
version + VERSION + Version::ZERO,
|
||||
computation,
|
||||
format,
|
||||
&indexes,
|
||||
)?,
|
||||
market: market::Vecs::forced_import(
|
||||
path,
|
||||
version + VERSION + Version::ZERO,
|
||||
computation,
|
||||
format,
|
||||
&indexes,
|
||||
)?,
|
||||
stateful: stateful::Vecs::forced_import(
|
||||
path,
|
||||
version + VERSION + Version::ZERO,
|
||||
computation,
|
||||
format,
|
||||
&indexes,
|
||||
fetched.as_ref(),
|
||||
)?,
|
||||
transactions: transactions::Vecs::forced_import(
|
||||
@@ -108,6 +116,7 @@ impl Vecs {
|
||||
version + VERSION + Version::ZERO,
|
||||
computation,
|
||||
format,
|
||||
&indexes,
|
||||
fetched.as_ref(),
|
||||
)?,
|
||||
indexes,
|
||||
@@ -121,6 +130,7 @@ impl Vecs {
|
||||
starting_indexes: brk_indexer::Indexes,
|
||||
fetcher: Option<&mut Fetcher>,
|
||||
exit: &Exit,
|
||||
stores: &mut Stores,
|
||||
) -> color_eyre::Result<()> {
|
||||
info!("Computing indexes...");
|
||||
let mut starting_indexes = self.indexes.compute(indexer, starting_indexes, exit)?;
|
||||
@@ -178,6 +188,7 @@ impl Vecs {
|
||||
&self.market,
|
||||
&mut starting_indexes,
|
||||
exit,
|
||||
stores,
|
||||
)?;
|
||||
|
||||
self.cointime.compute(
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
use std::{ops::Deref, path::Path};
|
||||
|
||||
use brk_core::{Bitcoin, DateIndex, Dollars, Height, Result, StoredUsize, Version};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{
|
||||
AnyCollectableVec, AnyIterableVec, AnyVec, Computation, EagerVec, Format, VecIterator,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
states::AddressCohortState,
|
||||
vecs::{
|
||||
Indexes, fetched,
|
||||
grouped::{ComputedVecsFromHeight, Source, VecBuilderOptions},
|
||||
indexes, market,
|
||||
stateful::{
|
||||
common,
|
||||
r#trait::{CohortVecs, DynCohortVecs},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vecs {
|
||||
starting_height: Height,
|
||||
|
||||
pub state: AddressCohortState,
|
||||
|
||||
pub inner: common::Vecs,
|
||||
|
||||
pub height_to_address_count: EagerVec<Height, StoredUsize>,
|
||||
pub indexes_to_address_count: ComputedVecsFromHeight<StoredUsize>,
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
cohort_name: Option<&str>,
|
||||
computation: Computation,
|
||||
format: Format,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
states_path: &Path,
|
||||
compute_relative_to_all: bool,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let compute_dollars = fetched.is_some();
|
||||
|
||||
let suffix = |s: &str| cohort_name.map_or(s.to_string(), |name| format!("{name}_{s}"));
|
||||
|
||||
Ok(Self {
|
||||
starting_height: Height::ZERO,
|
||||
state: AddressCohortState::default_and_import(
|
||||
states_path,
|
||||
cohort_name.unwrap_or_default(),
|
||||
compute_dollars,
|
||||
)?,
|
||||
height_to_address_count: EagerVec::forced_import(
|
||||
path,
|
||||
&suffix("address_count"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)?,
|
||||
indexes_to_address_count: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
&suffix("address_count"),
|
||||
Source::None,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
inner: common::Vecs::forced_import(
|
||||
path,
|
||||
cohort_name,
|
||||
computation,
|
||||
format,
|
||||
version,
|
||||
indexes,
|
||||
fetched,
|
||||
compute_relative_to_all,
|
||||
false,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl DynCohortVecs for Vecs {
|
||||
fn starting_height(&self) -> Height {
|
||||
[
|
||||
self.state.height().map_or(Height::MAX, |h| h.incremented()),
|
||||
self.height_to_address_count.len().into(),
|
||||
self.inner.starting_height(),
|
||||
]
|
||||
.into_iter()
|
||||
.min()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn init(&mut self, starting_height: Height) {
|
||||
if starting_height > self.starting_height() {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
self.starting_height = starting_height;
|
||||
|
||||
if let Some(prev_height) = starting_height.decremented() {
|
||||
self.state.address_count = *self
|
||||
.height_to_address_count
|
||||
.into_iter()
|
||||
.unwrap_get_inner(prev_height);
|
||||
}
|
||||
|
||||
self.inner
|
||||
.init(&mut self.starting_height, &mut self.state.inner);
|
||||
}
|
||||
|
||||
fn validate_computed_versions(&mut self, base_version: Version) -> Result<()> {
|
||||
self.height_to_address_count
|
||||
.validate_computed_version_or_reset_file(
|
||||
base_version + self.height_to_address_count.inner_version(),
|
||||
)?;
|
||||
|
||||
self.inner.validate_computed_versions(base_version)
|
||||
}
|
||||
|
||||
fn forced_pushed_at(&mut self, height: Height, exit: &Exit) -> Result<()> {
|
||||
if self.starting_height > height {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.height_to_address_count.forced_push_at(
|
||||
height,
|
||||
self.state.address_count.into(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.inner.forced_pushed_at(height, exit, &self.state.inner)
|
||||
}
|
||||
|
||||
fn compute_then_force_push_unrealized_states(
|
||||
&mut self,
|
||||
height: Height,
|
||||
height_price: Option<Dollars>,
|
||||
dateindex: Option<DateIndex>,
|
||||
date_price: Option<Option<Dollars>>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.inner.compute_then_force_push_unrealized_states(
|
||||
height,
|
||||
height_price,
|
||||
dateindex,
|
||||
date_price,
|
||||
exit,
|
||||
&self.state.inner,
|
||||
)
|
||||
}
|
||||
|
||||
fn safe_flush_stateful_vecs(&mut self, height: Height, exit: &Exit) -> Result<()> {
|
||||
self.height_to_address_count.safe_flush(exit)?;
|
||||
|
||||
self.inner
|
||||
.safe_flush_stateful_vecs(height, exit, &mut self.state.inner)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn compute_rest_part1(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
self.indexes_to_address_count.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(&self.height_to_address_count),
|
||||
)?;
|
||||
|
||||
self.inner
|
||||
.compute_rest_part1(indexer, indexes, fetched, starting_indexes, exit)
|
||||
}
|
||||
|
||||
fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
[
|
||||
self.inner.vecs(),
|
||||
self.indexes_to_address_count.vecs(),
|
||||
vec![&self.height_to_address_count],
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
|
||||
impl CohortVecs for Vecs {
|
||||
fn compute_from_stateful(
|
||||
&mut self,
|
||||
starting_indexes: &Indexes,
|
||||
others: &[&Self],
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.height_to_address_count.compute_sum_of_others(
|
||||
starting_indexes.height,
|
||||
others
|
||||
.iter()
|
||||
.map(|v| &v.height_to_address_count)
|
||||
.collect::<Vec<_>>()
|
||||
.as_slice(),
|
||||
exit,
|
||||
)?;
|
||||
self.inner.compute_from_stateful(
|
||||
starting_indexes,
|
||||
&others.iter().map(|v| &v.inner).collect::<Vec<_>>(),
|
||||
exit,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn compute_rest_part2(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
market: &market::Vecs,
|
||||
height_to_supply: &impl AnyIterableVec<Height, Bitcoin>,
|
||||
dateindex_to_supply: &impl AnyIterableVec<DateIndex, Bitcoin>,
|
||||
height_to_realized_cap: Option<&impl AnyIterableVec<Height, Dollars>>,
|
||||
dateindex_to_realized_cap: Option<&impl AnyIterableVec<DateIndex, Dollars>>,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
self.inner.compute_rest_part2(
|
||||
indexer,
|
||||
indexes,
|
||||
fetched,
|
||||
starting_indexes,
|
||||
market,
|
||||
height_to_supply,
|
||||
dateindex_to_supply,
|
||||
height_to_realized_cap,
|
||||
dateindex_to_realized_cap,
|
||||
exit,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Vecs {
|
||||
type Target = common::Vecs;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,550 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{
|
||||
AddressGroups, ByAmountRange, ByGreatEqualAmount, ByLowerThanAmount, GroupFilter, Height,
|
||||
Result, Version,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_vec::{Computation, Format};
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use rayon::prelude::*;
|
||||
|
||||
use crate::vecs::{
|
||||
Indexes, fetched, indexes,
|
||||
stateful::{
|
||||
address_cohort,
|
||||
r#trait::{CohortVecs, DynCohortVecs},
|
||||
},
|
||||
};
|
||||
|
||||
const VERSION: Version = Version::new(0);
|
||||
|
||||
#[derive(Clone, Deref, DerefMut)]
|
||||
pub struct Vecs(AddressGroups<(GroupFilter, address_cohort::Vecs)>);
|
||||
|
||||
impl Vecs {
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
version: Version,
|
||||
_computation: Computation,
|
||||
format: Format,
|
||||
indexes: &indexes::Vecs,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
states_path: &Path,
|
||||
) -> color_eyre::Result<Self> {
|
||||
Ok(Self(
|
||||
AddressGroups {
|
||||
amount_range: ByAmountRange {
|
||||
_0sats: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_with_0sats"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_1sat_to_10sats: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_1sat_under_10sats"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_10sats_to_100sats: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_10sats_under_100sats"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_100sats_to_1k_sats: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_100sats_under_1k_sats"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_1k_sats_to_10k_sats: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_1k_sats_under_10k_sats"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_10k_sats_to_100k_sats: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_10k_sats_under_100k_sats"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_100k_sats_to_1m_sats: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_100k_sats_under_1m_sats"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_1m_sats_to_10m_sats: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_1m_sats_under_10m_sats"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_10m_sats_to_1btc: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_10m_sats_under_1btc"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_1btc_to_10btc: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_1btc_under_10btc"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_10btc_to_100btc: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_10btc_under_100btc"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_100btc_to_1k_btc: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_100btc_under_1k_btc"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_1k_btc_to_10k_btc: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_1k_btc_under_10k_btc"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_10k_btc_to_100k_btc: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_10k_btc_under_100k_btc"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_100k_btc_or_more: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_100k_btc"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
},
|
||||
lt_amount: ByLowerThanAmount {
|
||||
_10sats: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_under_10sats"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_100sats: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_under_100sats"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_1k_sats: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_under_1k_sats"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_10k_sats: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_under_10k_sats"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_100k_sats: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_under_100k_sats"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_1m_sats: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_under_1m_sats"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_10m_sats: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_under_10m_sats"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_1btc: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_under_1btc"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_10btc: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_under_10btc"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_100btc: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_under_100btc"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_1k_btc: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_under_1k_btc"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_10k_btc: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_under_10k_btc"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_100k_btc: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_under_100k_btc"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
},
|
||||
ge_amount: ByGreatEqualAmount {
|
||||
_1sat: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_1sat"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_10sats: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_10sats"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_100sats: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_100sats"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_1k_sats: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_1k_sats"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_10k_sats: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_10k_sats"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_100k_sats: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_100k_sats"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_1m_sats: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_1m_sats"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_10m_sats: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_10m_sats"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_1btc: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_1btc"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_10btc: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_10btc"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_100btc: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_100btc"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_1k_btc: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_1k_btc"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
_10k_btc: address_cohort::Vecs::forced_import(
|
||||
path,
|
||||
Some("addrs_above_10k_btc"),
|
||||
_computation,
|
||||
format,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexes,
|
||||
fetched,
|
||||
states_path,
|
||||
true,
|
||||
)?,
|
||||
},
|
||||
}
|
||||
.into(),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn compute_overlapping_vecs(
|
||||
&mut self,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let by_size_range = self.0.amount_range.as_vec();
|
||||
|
||||
[
|
||||
self.0
|
||||
.ge_amount
|
||||
.as_mut_vec()
|
||||
.into_iter()
|
||||
.map(|(filter, vecs)| {
|
||||
(
|
||||
vecs,
|
||||
by_size_range
|
||||
.into_iter()
|
||||
.filter(|(other, _)| filter.includes(other))
|
||||
.map(|(_, v)| v)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
self.0
|
||||
.lt_amount
|
||||
.as_mut_vec()
|
||||
.into_iter()
|
||||
.map(|(filter, vecs)| {
|
||||
(
|
||||
vecs,
|
||||
by_size_range
|
||||
.into_iter()
|
||||
.filter(|(other, _)| filter.includes(other))
|
||||
.map(|(_, v)| v)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
]
|
||||
.into_par_iter()
|
||||
.flatten()
|
||||
.try_for_each(|(vecs, stateful)| {
|
||||
vecs.compute_from_stateful(starting_indexes, &stateful, exit)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn safe_flush_stateful_vecs(&mut self, height: Height, exit: &Exit) -> Result<()> {
|
||||
self.as_mut_separate_vecs()
|
||||
.par_iter_mut()
|
||||
.try_for_each(|(_, v)| v.safe_flush_stateful_vecs(height, exit))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
use brk_core::{ByAddressType, Height};
|
||||
use brk_vec::VecIterator;
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
|
||||
use crate::vecs::stateful::addresstype_to_height_to_addresscount::AddressTypeToHeightToAddressCount;
|
||||
|
||||
#[derive(Debug, Default, Deref, DerefMut)]
|
||||
pub struct AddressTypeToAddressCount(ByAddressType<usize>);
|
||||
|
||||
impl From<(&AddressTypeToHeightToAddressCount, Height)> for AddressTypeToAddressCount {
|
||||
fn from((groups, starting_height): (&AddressTypeToHeightToAddressCount, Height)) -> Self {
|
||||
if let Some(prev_height) = starting_height.decremented() {
|
||||
Self(ByAddressType {
|
||||
p2pk65: groups
|
||||
.p2pk65
|
||||
.into_iter()
|
||||
.unwrap_get_inner(prev_height)
|
||||
.into(),
|
||||
p2pk33: groups
|
||||
.p2pk33
|
||||
.into_iter()
|
||||
.unwrap_get_inner(prev_height)
|
||||
.into(),
|
||||
p2pkh: groups
|
||||
.p2pkh
|
||||
.into_iter()
|
||||
.unwrap_get_inner(prev_height)
|
||||
.into(),
|
||||
p2sh: groups.p2sh.into_iter().unwrap_get_inner(prev_height).into(),
|
||||
p2wpkh: groups
|
||||
.p2wpkh
|
||||
.into_iter()
|
||||
.unwrap_get_inner(prev_height)
|
||||
.into(),
|
||||
p2wsh: groups
|
||||
.p2wsh
|
||||
.into_iter()
|
||||
.unwrap_get_inner(prev_height)
|
||||
.into(),
|
||||
p2tr: groups.p2tr.into_iter().unwrap_get_inner(prev_height).into(),
|
||||
p2a: groups.p2a.into_iter().unwrap_get_inner(prev_height).into(),
|
||||
})
|
||||
} else {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
use brk_core::{ByAddressType, Height, Result, StoredUsize};
|
||||
use brk_exit::Exit;
|
||||
use brk_vec::EagerVec;
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
|
||||
use crate::vecs::stateful::addresstype_to_addresscount::AddressTypeToAddressCount;
|
||||
|
||||
#[derive(Debug, Clone, Deref, DerefMut)]
|
||||
pub struct AddressTypeToHeightToAddressCount(ByAddressType<EagerVec<Height, StoredUsize>>);
|
||||
|
||||
impl From<ByAddressType<EagerVec<Height, StoredUsize>>> for AddressTypeToHeightToAddressCount {
|
||||
fn from(value: ByAddressType<EagerVec<Height, StoredUsize>>) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddressTypeToHeightToAddressCount {
|
||||
pub fn forced_push_at(
|
||||
&mut self,
|
||||
height: Height,
|
||||
addresstype_to_usize: &AddressTypeToAddressCount,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.p2pk65
|
||||
.forced_push_at(height, addresstype_to_usize.p2pk65.into(), exit)?;
|
||||
self.p2pk33
|
||||
.forced_push_at(height, addresstype_to_usize.p2pk33.into(), exit)?;
|
||||
self.p2pkh
|
||||
.forced_push_at(height, addresstype_to_usize.p2pkh.into(), exit)?;
|
||||
self.p2sh
|
||||
.forced_push_at(height, addresstype_to_usize.p2sh.into(), exit)?;
|
||||
self.p2wpkh
|
||||
.forced_push_at(height, addresstype_to_usize.p2wpkh.into(), exit)?;
|
||||
self.p2wsh
|
||||
.forced_push_at(height, addresstype_to_usize.p2wsh.into(), exit)?;
|
||||
self.p2tr
|
||||
.forced_push_at(height, addresstype_to_usize.p2tr.into(), exit)?;
|
||||
self.p2a
|
||||
.forced_push_at(height, addresstype_to_usize.p2a.into(), exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
use brk_core::{ByAddressType, StoredUsize};
|
||||
use brk_exit::Exit;
|
||||
use brk_vec::AnyCollectableVec;
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
|
||||
use crate::vecs::{
|
||||
Indexes, grouped::ComputedVecsFromHeight, indexes,
|
||||
stateful::addresstype_to_height_to_addresscount::AddressTypeToHeightToAddressCount,
|
||||
};
|
||||
|
||||
#[derive(Clone, Deref, DerefMut)]
|
||||
pub struct AddressTypeToIndexesToAddressCount(ByAddressType<ComputedVecsFromHeight<StoredUsize>>);
|
||||
|
||||
impl From<ByAddressType<ComputedVecsFromHeight<StoredUsize>>>
|
||||
for AddressTypeToIndexesToAddressCount
|
||||
{
|
||||
fn from(value: ByAddressType<ComputedVecsFromHeight<StoredUsize>>) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddressTypeToIndexesToAddressCount {
|
||||
pub fn compute(
|
||||
&mut self,
|
||||
// height: Height,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
addresstype_to_height_to_addresscount: &AddressTypeToHeightToAddressCount,
|
||||
) -> color_eyre::Result<()> {
|
||||
self.p2pk65.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(&addresstype_to_height_to_addresscount.p2pk65),
|
||||
)?;
|
||||
self.p2pk33.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(&addresstype_to_height_to_addresscount.p2pk33),
|
||||
)?;
|
||||
self.p2pkh.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(&addresstype_to_height_to_addresscount.p2pkh),
|
||||
)?;
|
||||
self.p2sh.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(&addresstype_to_height_to_addresscount.p2sh),
|
||||
)?;
|
||||
self.p2wpkh.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(&addresstype_to_height_to_addresscount.p2wpkh),
|
||||
)?;
|
||||
self.p2wsh.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(&addresstype_to_height_to_addresscount.p2wsh),
|
||||
)?;
|
||||
self.p2tr.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(&addresstype_to_height_to_addresscount.p2tr),
|
||||
)?;
|
||||
self.p2a.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(&addresstype_to_height_to_addresscount.p2a),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
//
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
self.0
|
||||
.as_typed_vec()
|
||||
.into_iter()
|
||||
.flat_map(|(_, v)| v.vecs())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
use std::{collections::BTreeSet, mem};
|
||||
|
||||
use brk_core::TypeIndex;
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
|
||||
use super::ByAddressType;
|
||||
|
||||
#[derive(Debug, Deref, DerefMut)]
|
||||
pub struct AddressTypeToTypeIndexSet(ByAddressType<BTreeSet<TypeIndex>>);
|
||||
|
||||
impl AddressTypeToTypeIndexSet {
|
||||
pub fn merge(mut self, mut other: Self) -> Self {
|
||||
Self::merge_(&mut self.p2pk65, &mut other.p2pk65);
|
||||
Self::merge_(&mut self.p2pk33, &mut other.p2pk33);
|
||||
Self::merge_(&mut self.p2pkh, &mut other.p2pkh);
|
||||
Self::merge_(&mut self.p2sh, &mut other.p2sh);
|
||||
Self::merge_(&mut self.p2wpkh, &mut other.p2wpkh);
|
||||
Self::merge_(&mut self.p2wsh, &mut other.p2wsh);
|
||||
Self::merge_(&mut self.p2tr, &mut other.p2tr);
|
||||
Self::merge_(&mut self.p2a, &mut other.p2a);
|
||||
self
|
||||
}
|
||||
|
||||
fn merge_(own: &mut BTreeSet<TypeIndex>, other: &mut BTreeSet<TypeIndex>) {
|
||||
if own.len() >= other.len() {
|
||||
own.append(other);
|
||||
} else {
|
||||
other.append(own);
|
||||
mem::swap(own, other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AddressTypeToTypeIndexSet {
|
||||
fn default() -> Self {
|
||||
Self(ByAddressType {
|
||||
p2pk65: BTreeSet::default(),
|
||||
p2pk33: BTreeSet::default(),
|
||||
p2pkh: BTreeSet::default(),
|
||||
p2sh: BTreeSet::default(),
|
||||
p2wpkh: BTreeSet::default(),
|
||||
p2wsh: BTreeSet::default(),
|
||||
p2tr: BTreeSet::default(),
|
||||
p2a: BTreeSet::default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
use std::{collections::BTreeMap, mem};
|
||||
|
||||
use brk_core::TypeIndex;
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
|
||||
use super::ByAddressType;
|
||||
|
||||
#[derive(Debug, Deref, DerefMut)]
|
||||
pub struct AddressTypeToTypeIndexTree<T>(ByAddressType<BTreeMap<TypeIndex, T>>);
|
||||
|
||||
impl<T> AddressTypeToTypeIndexTree<T> {
|
||||
pub fn merge(mut self, mut other: Self) -> Self {
|
||||
Self::merge_(&mut self.p2pk65, &mut other.p2pk65);
|
||||
Self::merge_(&mut self.p2pk33, &mut other.p2pk33);
|
||||
Self::merge_(&mut self.p2pkh, &mut other.p2pkh);
|
||||
Self::merge_(&mut self.p2sh, &mut other.p2sh);
|
||||
Self::merge_(&mut self.p2wpkh, &mut other.p2wpkh);
|
||||
Self::merge_(&mut self.p2wsh, &mut other.p2wsh);
|
||||
Self::merge_(&mut self.p2tr, &mut other.p2tr);
|
||||
Self::merge_(&mut self.p2a, &mut other.p2a);
|
||||
self
|
||||
}
|
||||
|
||||
fn merge_(own: &mut BTreeMap<TypeIndex, T>, other: &mut BTreeMap<TypeIndex, T>) {
|
||||
if own.len() >= other.len() {
|
||||
own.append(other);
|
||||
} else {
|
||||
other.append(own);
|
||||
mem::swap(own, other);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap(self) -> ByAddressType<BTreeMap<TypeIndex, T>> {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for AddressTypeToTypeIndexTree<T> {
|
||||
fn default() -> Self {
|
||||
Self(ByAddressType {
|
||||
p2pk65: BTreeMap::default(),
|
||||
p2pk33: BTreeMap::default(),
|
||||
p2pkh: BTreeMap::default(),
|
||||
p2sh: BTreeMap::default(),
|
||||
p2wpkh: BTreeMap::default(),
|
||||
p2wsh: BTreeMap::default(),
|
||||
p2tr: BTreeMap::default(),
|
||||
p2a: BTreeMap::default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
|
||||
use super::ByAddressType;
|
||||
|
||||
#[derive(Debug, Deref, DerefMut)]
|
||||
pub struct AddressTypeToVec<T>(ByAddressType<Vec<T>>);
|
||||
|
||||
impl<T> Default for AddressTypeToVec<T> {
|
||||
fn default() -> Self {
|
||||
Self(ByAddressType {
|
||||
p2pk65: vec![],
|
||||
p2pk33: vec![],
|
||||
p2pkh: vec![],
|
||||
p2sh: vec![],
|
||||
p2wpkh: vec![],
|
||||
p2wsh: vec![],
|
||||
p2tr: vec![],
|
||||
p2a: vec![],
|
||||
})
|
||||
}
|
||||
}
|
||||
+286
-211
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,9 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use brk_core::Height;
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
|
||||
use crate::vecs::stateful::AddressTypeToVec;
|
||||
|
||||
#[derive(Debug, Default, Deref, DerefMut)]
|
||||
pub struct HeightToAddressTypeToVec<T>(pub BTreeMap<Height, AddressTypeToVec<T>>);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,258 +0,0 @@
|
||||
use std::{collections::BTreeMap, ops::ControlFlow};
|
||||
|
||||
use brk_core::{CheckedSub, Dollars, HalvingEpoch, Height, Result, Timestamp};
|
||||
use brk_exit::Exit;
|
||||
use brk_state::{BlockState, OutputFilter, Outputs, Transacted};
|
||||
use brk_vec::StoredIndex;
|
||||
use rayon::prelude::*;
|
||||
|
||||
use crate::vecs::Indexes;
|
||||
|
||||
use super::cohort;
|
||||
|
||||
pub trait OutputCohorts {
|
||||
fn tick_tock_next_block(&mut self, chain_state: &[BlockState], timestamp: Timestamp);
|
||||
fn send(&mut self, height_to_sent: BTreeMap<Height, Transacted>, chain_state: &[BlockState]);
|
||||
fn receive(&mut self, received: Transacted, height: Height, price: Option<Dollars>);
|
||||
fn compute_overlapping_vecs(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()>;
|
||||
}
|
||||
|
||||
impl OutputCohorts for Outputs<(OutputFilter, cohort::Vecs)> {
|
||||
fn tick_tock_next_block(&mut self, chain_state: &[BlockState], timestamp: Timestamp) {
|
||||
if chain_state.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let prev_timestamp = chain_state.last().unwrap().timestamp;
|
||||
|
||||
self.by_date_range
|
||||
.as_mut_vec()
|
||||
.into_par_iter()
|
||||
.for_each(|(filter, v)| {
|
||||
let state = &mut v.state;
|
||||
|
||||
let _ = chain_state
|
||||
.iter()
|
||||
.try_for_each(|block_state| -> ControlFlow<()> {
|
||||
let prev_days_old = block_state
|
||||
.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 = filter.contains(days_old);
|
||||
let was = filter.contains(prev_days_old);
|
||||
|
||||
if is && !was {
|
||||
state.increment(&block_state.supply, block_state.price);
|
||||
} else if was && !is {
|
||||
state.decrement(&block_state.supply, block_state.price);
|
||||
}
|
||||
|
||||
ControlFlow::Continue(())
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn send(&mut self, height_to_sent: BTreeMap<Height, Transacted>, chain_state: &[BlockState]) {
|
||||
let mut time_based_vecs = self
|
||||
.by_date_range
|
||||
.as_mut_vec()
|
||||
.into_iter()
|
||||
.chain(self.by_epoch.as_mut_vec())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let last_timestamp = chain_state.last().unwrap().timestamp;
|
||||
let current_price = chain_state.last().unwrap().price;
|
||||
|
||||
// dbg!(&height_to_sent);
|
||||
|
||||
height_to_sent.into_iter().for_each(|(height, sent)| {
|
||||
let block_state = chain_state.get(height.unwrap_to_usize()).unwrap();
|
||||
let prev_price = block_state.price;
|
||||
|
||||
let blocks_old = chain_state.len() - 1 - height.unwrap_to_usize();
|
||||
|
||||
let days_old = block_state
|
||||
.timestamp
|
||||
.difference_in_days_between(last_timestamp);
|
||||
|
||||
let days_old_foat = block_state
|
||||
.timestamp
|
||||
.difference_in_days_between_float(last_timestamp);
|
||||
|
||||
let older_than_hour =
|
||||
jiff::Timestamp::from(last_timestamp.checked_sub(block_state.timestamp).unwrap())
|
||||
.as_second()
|
||||
>= 60 * 60;
|
||||
|
||||
time_based_vecs
|
||||
.iter_mut()
|
||||
.filter(|(filter, _)| match filter {
|
||||
OutputFilter::From(from) => *from <= days_old,
|
||||
OutputFilter::To(to) => *to > days_old,
|
||||
OutputFilter::Range(range) => range.contains(&days_old),
|
||||
OutputFilter::Epoch(epoch) => *epoch == HalvingEpoch::from(height),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.for_each(|(_, vecs)| {
|
||||
vecs.state.send(
|
||||
&sent.spendable_supply,
|
||||
current_price,
|
||||
prev_price,
|
||||
blocks_old,
|
||||
days_old_foat,
|
||||
older_than_hour,
|
||||
);
|
||||
});
|
||||
|
||||
sent.by_type.spendable.as_typed_vec().into_iter().for_each(
|
||||
|(output_type, supply_state)| {
|
||||
self.by_type.get_mut(output_type).1.state.send(
|
||||
supply_state,
|
||||
current_price,
|
||||
prev_price,
|
||||
blocks_old,
|
||||
days_old_foat,
|
||||
older_than_hour,
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
sent.by_size_group
|
||||
.into_iter()
|
||||
.for_each(|(group, supply_state)| {
|
||||
self.by_size_range.get_mut(group).1.state.send(
|
||||
&supply_state,
|
||||
current_price,
|
||||
prev_price,
|
||||
blocks_old,
|
||||
days_old_foat,
|
||||
older_than_hour,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn receive(&mut self, received: Transacted, height: Height, price: Option<Dollars>) {
|
||||
let supply_state = received.spendable_supply;
|
||||
|
||||
[
|
||||
&mut self.by_date_range.start_to_1d.1,
|
||||
&mut self.by_epoch.mut_vec_from_height(height).1,
|
||||
]
|
||||
.into_iter()
|
||||
.for_each(|v| {
|
||||
v.state.receive(&supply_state, price);
|
||||
});
|
||||
|
||||
self.by_type
|
||||
.as_mut_vec()
|
||||
.into_iter()
|
||||
.for_each(|(filter, vecs)| {
|
||||
let output_type = match filter {
|
||||
OutputFilter::Type(output_type) => *output_type,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
vecs.state.receive(received.by_type.get(output_type), price)
|
||||
});
|
||||
|
||||
received
|
||||
.by_size_group
|
||||
.into_iter()
|
||||
.for_each(|(group, supply_state)| {
|
||||
self.by_size_range
|
||||
.get_mut(group)
|
||||
.1
|
||||
.state
|
||||
.receive(&supply_state, price);
|
||||
});
|
||||
}
|
||||
|
||||
fn compute_overlapping_vecs(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()> {
|
||||
let by_date_range = self.by_date_range.as_vec();
|
||||
let by_size_range = self.by_size_range.as_vec();
|
||||
|
||||
[
|
||||
vec![(&mut self.all.1, self.by_epoch.vecs().to_vec())],
|
||||
self.by_from_date
|
||||
.as_mut_vec()
|
||||
.into_iter()
|
||||
.map(|(filter, vecs)| {
|
||||
(
|
||||
vecs,
|
||||
by_date_range
|
||||
.into_iter()
|
||||
.filter(|(other, _)| filter.includes(other))
|
||||
.map(|(_, v)| v)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
self.by_up_to_date
|
||||
.as_mut_vec()
|
||||
.into_iter()
|
||||
.map(|(filter, vecs)| {
|
||||
(
|
||||
vecs,
|
||||
by_date_range
|
||||
.into_iter()
|
||||
.filter(|(other, _)| filter.includes(other))
|
||||
.map(|(_, v)| v)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
self.by_term
|
||||
.as_mut_vec()
|
||||
.into_iter()
|
||||
.map(|(filter, vecs)| {
|
||||
(
|
||||
vecs,
|
||||
by_date_range
|
||||
.into_iter()
|
||||
.filter(|(other, _)| filter.includes(other))
|
||||
.map(|(_, v)| v)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
self.by_from_size
|
||||
.as_mut_vec()
|
||||
.into_iter()
|
||||
.map(|(filter, vecs)| {
|
||||
(
|
||||
vecs,
|
||||
by_size_range
|
||||
.into_iter()
|
||||
.filter(|(other, _)| filter.includes(other))
|
||||
.map(|(_, v)| v)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
self.by_up_to_size
|
||||
.as_mut_vec()
|
||||
.into_iter()
|
||||
.map(|(filter, vecs)| {
|
||||
(
|
||||
vecs,
|
||||
by_size_range
|
||||
.into_iter()
|
||||
.filter(|(other, _)| filter.includes(other))
|
||||
.map(|(_, v)| v)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
]
|
||||
.into_par_iter()
|
||||
.flatten()
|
||||
.try_for_each(|(vecs, stateful)| {
|
||||
vecs.compute_from_stateful(starting_indexes, &stateful, exit)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use brk_vec::{IndexedVec, StoredIndex, StoredType};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RangeMap<I, T>(BTreeMap<I, T>);
|
||||
|
||||
impl<I, T> RangeMap<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredIndex,
|
||||
{
|
||||
pub fn get(&self, key: I) -> Option<&T> {
|
||||
self.0.range(..=key).next_back().map(|(&min, value)| {
|
||||
if min > key {
|
||||
unreachable!()
|
||||
}
|
||||
value
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> From<&IndexedVec<I, T>> for RangeMap<T, I>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredIndex + StoredType,
|
||||
{
|
||||
fn from(vec: &IndexedVec<I, T>) -> Self {
|
||||
Self(
|
||||
vec.into_iter()
|
||||
.map(|(i, v)| (v.into_owned(), i))
|
||||
.collect::<BTreeMap<_, _>>(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
use brk_core::{Bitcoin, DateIndex, Dollars, Height, Result, Version};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, AnyIterableVec};
|
||||
|
||||
use crate::vecs::{Indexes, fetched, indexes, market};
|
||||
|
||||
pub trait DynCohortVecs: Send + Sync {
|
||||
fn starting_height(&self) -> Height;
|
||||
|
||||
fn init(&mut self, starting_height: Height);
|
||||
|
||||
fn validate_computed_versions(&mut self, base_version: Version) -> Result<()>;
|
||||
|
||||
fn forced_pushed_at(&mut self, height: Height, exit: &Exit) -> Result<()>;
|
||||
|
||||
fn compute_then_force_push_unrealized_states(
|
||||
&mut self,
|
||||
height: Height,
|
||||
height_price: Option<Dollars>,
|
||||
dateindex: Option<DateIndex>,
|
||||
date_price: Option<Option<Dollars>>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>;
|
||||
|
||||
fn safe_flush_stateful_vecs(&mut self, height: Height, exit: &Exit) -> Result<()>;
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn compute_rest_part1(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()>;
|
||||
|
||||
fn vecs(&self) -> Vec<&dyn AnyCollectableVec>;
|
||||
}
|
||||
|
||||
pub trait CohortVecs: DynCohortVecs {
|
||||
fn compute_from_stateful(
|
||||
&mut self,
|
||||
starting_indexes: &Indexes,
|
||||
others: &[&Self],
|
||||
exit: &Exit,
|
||||
) -> Result<()>;
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn compute_rest_part2(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
market: &market::Vecs,
|
||||
height_to_supply: &impl AnyIterableVec<Height, Bitcoin>,
|
||||
dateindex_to_supply: &impl AnyIterableVec<DateIndex, Bitcoin>,
|
||||
height_to_realized_cap: Option<&impl AnyIterableVec<Height, Dollars>>,
|
||||
dateindex_to_realized_cap: Option<&impl AnyIterableVec<DateIndex, Dollars>>,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()>;
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
use std::{ops::Deref, path::Path};
|
||||
|
||||
use brk_core::{Bitcoin, DateIndex, Dollars, Height, Result, Version};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, AnyIterableVec, Computation, Format};
|
||||
|
||||
use crate::{
|
||||
UTXOCohortState,
|
||||
vecs::{
|
||||
Indexes, fetched, indexes, market,
|
||||
stateful::{
|
||||
common,
|
||||
r#trait::{CohortVecs, DynCohortVecs},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vecs {
|
||||
starting_height: Height,
|
||||
|
||||
pub state: UTXOCohortState,
|
||||
|
||||
inner: common::Vecs,
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
cohort_name: Option<&str>,
|
||||
computation: Computation,
|
||||
format: Format,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
states_path: &Path,
|
||||
compute_relative_to_all: bool,
|
||||
ratio_extended: bool,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let compute_dollars = fetched.is_some();
|
||||
|
||||
Ok(Self {
|
||||
starting_height: Height::ZERO,
|
||||
|
||||
state: UTXOCohortState::default_and_import(
|
||||
states_path,
|
||||
cohort_name.unwrap_or_default(),
|
||||
compute_dollars,
|
||||
)?,
|
||||
|
||||
inner: common::Vecs::forced_import(
|
||||
path,
|
||||
cohort_name,
|
||||
computation,
|
||||
format,
|
||||
version,
|
||||
indexes,
|
||||
fetched,
|
||||
compute_relative_to_all,
|
||||
ratio_extended,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl DynCohortVecs for Vecs {
|
||||
fn starting_height(&self) -> Height {
|
||||
[
|
||||
self.state.height().map_or(Height::MAX, |h| h.incremented()),
|
||||
self.inner.starting_height(),
|
||||
]
|
||||
.into_iter()
|
||||
.min()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn init(&mut self, starting_height: Height) {
|
||||
if starting_height > self.starting_height() {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
self.starting_height = starting_height;
|
||||
|
||||
self.inner.init(&mut self.starting_height, &mut self.state);
|
||||
}
|
||||
|
||||
fn validate_computed_versions(&mut self, base_version: Version) -> Result<()> {
|
||||
self.inner.validate_computed_versions(base_version)
|
||||
}
|
||||
|
||||
fn forced_pushed_at(&mut self, height: Height, exit: &Exit) -> Result<()> {
|
||||
if self.starting_height > height {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.inner.forced_pushed_at(height, exit, &self.state)
|
||||
}
|
||||
|
||||
fn compute_then_force_push_unrealized_states(
|
||||
&mut self,
|
||||
height: Height,
|
||||
height_price: Option<Dollars>,
|
||||
dateindex: Option<DateIndex>,
|
||||
date_price: Option<Option<Dollars>>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.inner.compute_then_force_push_unrealized_states(
|
||||
height,
|
||||
height_price,
|
||||
dateindex,
|
||||
date_price,
|
||||
exit,
|
||||
&self.state,
|
||||
)
|
||||
}
|
||||
|
||||
fn safe_flush_stateful_vecs(&mut self, height: Height, exit: &Exit) -> Result<()> {
|
||||
self.inner
|
||||
.safe_flush_stateful_vecs(height, exit, &mut self.state)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn compute_rest_part1(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
self.inner
|
||||
.compute_rest_part1(indexer, indexes, fetched, starting_indexes, exit)
|
||||
}
|
||||
|
||||
fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
self.inner.vecs()
|
||||
}
|
||||
}
|
||||
|
||||
impl CohortVecs for Vecs {
|
||||
fn compute_from_stateful(
|
||||
&mut self,
|
||||
starting_indexes: &Indexes,
|
||||
others: &[&Self],
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.inner.compute_from_stateful(
|
||||
starting_indexes,
|
||||
&others.iter().map(|v| &v.inner).collect::<Vec<_>>(),
|
||||
exit,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn compute_rest_part2(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
market: &market::Vecs,
|
||||
height_to_supply: &impl AnyIterableVec<Height, Bitcoin>,
|
||||
dateindex_to_supply: &impl AnyIterableVec<DateIndex, Bitcoin>,
|
||||
height_to_realized_cap: Option<&impl AnyIterableVec<Height, Dollars>>,
|
||||
dateindex_to_realized_cap: Option<&impl AnyIterableVec<DateIndex, Dollars>>,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
self.inner.compute_rest_part2(
|
||||
indexer,
|
||||
indexes,
|
||||
fetched,
|
||||
starting_indexes,
|
||||
market,
|
||||
height_to_supply,
|
||||
dateindex_to_supply,
|
||||
height_to_realized_cap,
|
||||
dateindex_to_realized_cap,
|
||||
exit,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Vecs {
|
||||
type Target = common::Vecs;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,62 @@
|
||||
use brk_core::{AddressData, EmptyAddressData};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum WithAddressDataSource<T> {
|
||||
New(T),
|
||||
FromAddressDataStore(T),
|
||||
FromEmptyAddressDataStore(T),
|
||||
}
|
||||
|
||||
impl<T> WithAddressDataSource<T> {
|
||||
pub fn is_new(&self) -> bool {
|
||||
matches!(self, Self::New(_))
|
||||
}
|
||||
|
||||
pub fn is_from_addressdata(&self) -> bool {
|
||||
matches!(self, Self::FromAddressDataStore(_))
|
||||
}
|
||||
|
||||
pub fn is_from_emptyaddressdata(&self) -> bool {
|
||||
matches!(self, Self::FromEmptyAddressDataStore(_))
|
||||
}
|
||||
|
||||
pub fn deref(&self) -> &T {
|
||||
match self {
|
||||
Self::New(v) => v,
|
||||
Self::FromAddressDataStore(v) => v,
|
||||
Self::FromEmptyAddressDataStore(v) => v,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deref_mut(&mut self) -> &mut T {
|
||||
match self {
|
||||
Self::New(v) => v,
|
||||
Self::FromAddressDataStore(v) => v,
|
||||
Self::FromEmptyAddressDataStore(v) => v,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WithAddressDataSource<EmptyAddressData>> for WithAddressDataSource<AddressData> {
|
||||
fn from(value: WithAddressDataSource<EmptyAddressData>) -> Self {
|
||||
match value {
|
||||
WithAddressDataSource::New(v) => Self::New(v.into()),
|
||||
WithAddressDataSource::FromAddressDataStore(v) => Self::FromAddressDataStore(v.into()),
|
||||
WithAddressDataSource::FromEmptyAddressDataStore(v) => {
|
||||
Self::FromEmptyAddressDataStore(v.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WithAddressDataSource<AddressData>> for WithAddressDataSource<EmptyAddressData> {
|
||||
fn from(value: WithAddressDataSource<AddressData>) -> Self {
|
||||
match value {
|
||||
WithAddressDataSource::New(v) => Self::New(v.into()),
|
||||
WithAddressDataSource::FromAddressDataStore(v) => Self::FromAddressDataStore(v.into()),
|
||||
WithAddressDataSource::FromEmptyAddressDataStore(v) => {
|
||||
Self::FromEmptyAddressDataStore(v.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,11 +11,13 @@ use brk_vec::{
|
||||
ComputedVecFrom1, ComputedVecFrom2, ComputedVecFrom3, Format, StoredIndex, VecIterator,
|
||||
};
|
||||
|
||||
use crate::vecs::grouped::Source;
|
||||
|
||||
use super::{
|
||||
Indexes, fetched,
|
||||
grouped::{
|
||||
ComputedValueVecsFromHeight, ComputedValueVecsFromTxindex, ComputedVecsFromHeight,
|
||||
ComputedVecsFromTxindex, StorableVecGeneatorOptions,
|
||||
ComputedVecsFromTxindex, VecBuilderOptions,
|
||||
},
|
||||
indexes,
|
||||
};
|
||||
@@ -110,13 +112,13 @@ impl Vecs {
|
||||
inputindex_to_outputindex_iter
|
||||
.next_at(index.unwrap_to_usize())
|
||||
.map(|(inputindex, outputindex)| {
|
||||
let outputindex = outputindex.into_inner();
|
||||
let outputindex = outputindex.into_owned();
|
||||
if outputindex == OutputIndex::COINBASE {
|
||||
Sats::ZERO
|
||||
} else if let Some((_, value)) =
|
||||
outputindex_to_value_iter.next_at(outputindex.unwrap_to_usize())
|
||||
{
|
||||
value.into_inner()
|
||||
value.into_owned()
|
||||
} else {
|
||||
dbg!(inputindex, outputindex);
|
||||
panic!()
|
||||
@@ -138,12 +140,12 @@ impl Vecs {
|
||||
txindex_to_base_size_iter
|
||||
.next_at(index)
|
||||
.map(|(_, base_size)| {
|
||||
let base_size = base_size.into_inner();
|
||||
let base_size = base_size.into_owned();
|
||||
let total_size = txindex_to_total_size_iter
|
||||
.next_at(index)
|
||||
.unwrap()
|
||||
.1
|
||||
.into_inner();
|
||||
.into_owned();
|
||||
|
||||
// This is the exact definition of a weight unit, as defined by BIP-141 (quote above).
|
||||
let wu = usize::from(base_size) * 3 + usize::from(total_size);
|
||||
@@ -164,7 +166,7 @@ impl Vecs {
|
||||
let index = index.unwrap_to_usize();
|
||||
iter.next_at(index).map(|(_, weight)| {
|
||||
StoredUsize::from(
|
||||
bitcoin::Weight::from(weight.into_inner()).to_vbytes_ceil() as usize
|
||||
bitcoin::Weight::from(weight.into_owned()).to_vbytes_ceil() as usize
|
||||
)
|
||||
})
|
||||
},
|
||||
@@ -182,12 +184,12 @@ impl Vecs {
|
||||
txindex_to_height_iter
|
||||
.next_at(index.unwrap_to_usize())
|
||||
.map(|(_, height)| {
|
||||
let height = height.into_inner();
|
||||
let height = height.into_owned();
|
||||
let txindex = height_to_first_txindex_iter
|
||||
.next_at(height.unwrap_to_usize())
|
||||
.unwrap()
|
||||
.1
|
||||
.into_inner();
|
||||
.into_owned();
|
||||
|
||||
index == txindex
|
||||
})
|
||||
@@ -211,12 +213,12 @@ impl Vecs {
|
||||
txindex_to_first_inputindex_iter
|
||||
.next_at(txindex)
|
||||
.map(|(_, first_index)| {
|
||||
let first_index = usize::from(first_index.into_inner());
|
||||
let first_index = usize::from(first_index.into_owned());
|
||||
let count = *txindex_to_input_count_iter
|
||||
.next_at(txindex)
|
||||
.unwrap()
|
||||
.1
|
||||
.into_inner();
|
||||
.into_owned();
|
||||
let range = first_index..first_index + count;
|
||||
range.into_iter().fold(Sats::ZERO, |total, inputindex| {
|
||||
total
|
||||
@@ -224,7 +226,7 @@ impl Vecs {
|
||||
.next_at(inputindex)
|
||||
.unwrap()
|
||||
.1
|
||||
.into_inner()
|
||||
.into_owned()
|
||||
})
|
||||
})
|
||||
},
|
||||
@@ -237,7 +239,8 @@ impl Vecs {
|
||||
// true,
|
||||
// version + VERSION + Version::ZERO,
|
||||
// format,
|
||||
// StorableVecGeneatorOptions::default()
|
||||
// computation,
|
||||
// StorableVecGeneatorOptions::default()
|
||||
// .add_average()
|
||||
// .add_sum()
|
||||
// .add_cumulative(),
|
||||
@@ -260,12 +263,12 @@ impl Vecs {
|
||||
txindex_to_first_outputindex_iter
|
||||
.next_at(txindex)
|
||||
.map(|(_, first_index)| {
|
||||
let first_index = usize::from(first_index.into_inner());
|
||||
let first_index = usize::from(first_index.into_owned());
|
||||
let count = *txindex_to_output_count_iter
|
||||
.next_at(txindex)
|
||||
.unwrap()
|
||||
.1
|
||||
.into_inner();
|
||||
.into_owned();
|
||||
let range = first_index..first_index + count;
|
||||
range.into_iter().fold(Sats::ZERO, |total, outputindex| {
|
||||
total
|
||||
@@ -273,7 +276,7 @@ impl Vecs {
|
||||
.next_at(outputindex)
|
||||
.unwrap()
|
||||
.1
|
||||
.into_inner()
|
||||
.into_owned()
|
||||
})
|
||||
})
|
||||
},
|
||||
@@ -286,7 +289,8 @@ impl Vecs {
|
||||
// true,
|
||||
// version + VERSION + Version::ZERO,
|
||||
// format,
|
||||
// StorableVecGeneatorOptions::default()
|
||||
// computation,
|
||||
// StorableVecGeneatorOptions::default()
|
||||
// .add_average()
|
||||
// .add_sum()
|
||||
// .add_cumulative(),
|
||||
@@ -303,12 +307,12 @@ impl Vecs {
|
||||
|txindex: TxIndex, input_iter, output_iter| {
|
||||
let txindex = txindex.unwrap_to_usize();
|
||||
input_iter.next_at(txindex).and_then(|(_, value)| {
|
||||
let input = value.into_inner();
|
||||
let input = value.into_owned();
|
||||
if input.is_zero() {
|
||||
return Some(Sats::ZERO);
|
||||
}
|
||||
output_iter.next_at(txindex).map(|(_, value)| {
|
||||
let output = value.into_inner();
|
||||
let output = value.into_owned();
|
||||
input.checked_sub(output).unwrap()
|
||||
})
|
||||
})
|
||||
@@ -326,9 +330,9 @@ impl Vecs {
|
||||
|txindex: TxIndex, fee_iter, vsize_iter| {
|
||||
let txindex = txindex.unwrap_to_usize();
|
||||
fee_iter.next_at(txindex).and_then(|(_, value)| {
|
||||
let fee = value.into_inner();
|
||||
let fee = value.into_owned();
|
||||
vsize_iter.next_at(txindex).map(|(_, value)| {
|
||||
let vsize = value.into_inner();
|
||||
let vsize = value.into_owned();
|
||||
Feerate::from((fee, vsize))
|
||||
})
|
||||
})
|
||||
@@ -339,10 +343,12 @@ impl Vecs {
|
||||
indexes_to_tx_count: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"tx_count",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default()
|
||||
.add_average()
|
||||
.add_minmax()
|
||||
.add_percentiles()
|
||||
@@ -352,10 +358,12 @@ impl Vecs {
|
||||
indexes_to_input_count: ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
"input_count",
|
||||
false,
|
||||
Source::None,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default()
|
||||
.add_average()
|
||||
.add_minmax()
|
||||
.add_percentiles()
|
||||
@@ -365,10 +373,12 @@ impl Vecs {
|
||||
indexes_to_output_count: ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
"output_count",
|
||||
false,
|
||||
Source::None,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default()
|
||||
.add_average()
|
||||
.add_minmax()
|
||||
.add_percentiles()
|
||||
@@ -378,43 +388,43 @@ impl Vecs {
|
||||
indexes_to_tx_v1: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"tx_v1",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_sum()
|
||||
.add_cumulative(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_sum().add_cumulative(),
|
||||
)?,
|
||||
indexes_to_tx_v2: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"tx_v2",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_sum()
|
||||
.add_cumulative(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_sum().add_cumulative(),
|
||||
)?,
|
||||
indexes_to_tx_v3: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"tx_v3",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_sum()
|
||||
.add_cumulative(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_sum().add_cumulative(),
|
||||
)?,
|
||||
indexes_to_fee: ComputedValueVecsFromTxindex::forced_import(
|
||||
path,
|
||||
"fee",
|
||||
indexes,
|
||||
Some(txindex_to_fee.boxed_clone()),
|
||||
Source::Vec(txindex_to_fee.boxed_clone()),
|
||||
version + VERSION + Version::ZERO,
|
||||
computation,
|
||||
format,
|
||||
fetched,
|
||||
StorableVecGeneatorOptions::default()
|
||||
VecBuilderOptions::default()
|
||||
.add_sum()
|
||||
.add_cumulative()
|
||||
.add_percentiles()
|
||||
@@ -424,10 +434,12 @@ impl Vecs {
|
||||
indexes_to_feerate: ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
"feerate",
|
||||
false,
|
||||
Source::None,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default()
|
||||
.add_percentiles()
|
||||
.add_minmax()
|
||||
.add_average(),
|
||||
@@ -435,10 +447,12 @@ impl Vecs {
|
||||
indexes_to_tx_vsize: ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
"tx_vsize",
|
||||
false,
|
||||
Source::None,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default()
|
||||
.add_percentiles()
|
||||
.add_minmax()
|
||||
.add_average(),
|
||||
@@ -446,10 +460,12 @@ impl Vecs {
|
||||
indexes_to_tx_weight: ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
"tx_weight",
|
||||
false,
|
||||
Source::None,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default()
|
||||
.add_percentiles()
|
||||
.add_minmax()
|
||||
.add_average(),
|
||||
@@ -457,49 +473,55 @@ impl Vecs {
|
||||
indexes_to_subsidy: ComputedValueVecsFromHeight::forced_import(
|
||||
path,
|
||||
"subsidy",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
computation,
|
||||
VecBuilderOptions::default()
|
||||
.add_percentiles()
|
||||
.add_sum()
|
||||
.add_cumulative()
|
||||
.add_minmax()
|
||||
.add_average(),
|
||||
compute_dollars,
|
||||
indexes,
|
||||
)?,
|
||||
indexes_to_coinbase: ComputedValueVecsFromHeight::forced_import(
|
||||
path,
|
||||
"coinbase",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
computation,
|
||||
VecBuilderOptions::default()
|
||||
.add_sum()
|
||||
.add_cumulative()
|
||||
.add_percentiles()
|
||||
.add_minmax()
|
||||
.add_average(),
|
||||
compute_dollars,
|
||||
indexes,
|
||||
)?,
|
||||
indexes_to_unclaimed_rewards: ComputedValueVecsFromHeight::forced_import(
|
||||
path,
|
||||
"unclaimed_rewards",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_sum()
|
||||
.add_cumulative(),
|
||||
computation,
|
||||
VecBuilderOptions::default().add_sum().add_cumulative(),
|
||||
compute_dollars,
|
||||
indexes,
|
||||
)?,
|
||||
indexes_to_p2a_count: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"p2a_count",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default()
|
||||
.add_average()
|
||||
.add_minmax()
|
||||
.add_percentiles()
|
||||
@@ -509,10 +531,12 @@ impl Vecs {
|
||||
indexes_to_p2ms_count: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"p2ms_count",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default()
|
||||
.add_average()
|
||||
.add_minmax()
|
||||
.add_percentiles()
|
||||
@@ -522,10 +546,12 @@ impl Vecs {
|
||||
indexes_to_p2pk33_count: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"p2pk33_count",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default()
|
||||
.add_average()
|
||||
.add_minmax()
|
||||
.add_percentiles()
|
||||
@@ -535,10 +561,12 @@ impl Vecs {
|
||||
indexes_to_p2pk65_count: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"p2pk65_count",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default()
|
||||
.add_average()
|
||||
.add_minmax()
|
||||
.add_percentiles()
|
||||
@@ -548,10 +576,12 @@ impl Vecs {
|
||||
indexes_to_p2pkh_count: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"p2pkh_count",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default()
|
||||
.add_average()
|
||||
.add_minmax()
|
||||
.add_percentiles()
|
||||
@@ -561,10 +591,12 @@ impl Vecs {
|
||||
indexes_to_p2sh_count: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"p2sh_count",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default()
|
||||
.add_average()
|
||||
.add_minmax()
|
||||
.add_percentiles()
|
||||
@@ -574,10 +606,12 @@ impl Vecs {
|
||||
indexes_to_p2tr_count: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"p2tr_count",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default()
|
||||
.add_average()
|
||||
.add_minmax()
|
||||
.add_percentiles()
|
||||
@@ -587,10 +621,12 @@ impl Vecs {
|
||||
indexes_to_p2wpkh_count: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"p2wpkh_count",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default()
|
||||
.add_average()
|
||||
.add_minmax()
|
||||
.add_percentiles()
|
||||
@@ -600,10 +636,12 @@ impl Vecs {
|
||||
indexes_to_p2wsh_count: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"p2wsh_count",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default()
|
||||
.add_average()
|
||||
.add_minmax()
|
||||
.add_percentiles()
|
||||
@@ -613,10 +651,12 @@ impl Vecs {
|
||||
indexes_to_opreturn_count: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"opreturn_count",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default()
|
||||
.add_average()
|
||||
.add_minmax()
|
||||
.add_percentiles()
|
||||
@@ -626,10 +666,12 @@ impl Vecs {
|
||||
indexes_to_unknownoutput_count: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"unknownoutput_count",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default()
|
||||
.add_average()
|
||||
.add_minmax()
|
||||
.add_percentiles()
|
||||
@@ -639,10 +681,12 @@ impl Vecs {
|
||||
indexes_to_emptyoutput_count: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"emptyoutput_count",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default()
|
||||
.add_average()
|
||||
.add_minmax()
|
||||
.add_percentiles()
|
||||
@@ -652,10 +696,12 @@ impl Vecs {
|
||||
indexes_to_exact_utxo_count: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"exact_utxo_count",
|
||||
true,
|
||||
Source::Compute,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
computation,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
txindex_to_is_coinbase,
|
||||
inputindex_to_value,
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
mod error;
|
||||
mod value;
|
||||
|
||||
pub use error::*;
|
||||
pub use value::*;
|
||||
@@ -1,39 +0,0 @@
|
||||
use std::{fmt::Debug, ops::Deref};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Value<'a, T> {
|
||||
Ref(&'a T),
|
||||
Owned(T),
|
||||
}
|
||||
|
||||
impl<T> Value<'_, T>
|
||||
where
|
||||
T: Sized + Debug + Clone,
|
||||
{
|
||||
pub fn into_inner(self) -> T {
|
||||
match self {
|
||||
Self::Ref(t) => t.to_owned(),
|
||||
Self::Owned(t) => t,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T> Deref for Value<'_, T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self {
|
||||
Self::Ref(t) => t,
|
||||
Self::Owned(t) => t,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T> AsRef<T> for Value<'_, T>
|
||||
where
|
||||
T: Sized + Debug + Clone,
|
||||
{
|
||||
fn as_ref(&self) -> &T {
|
||||
match self {
|
||||
Self::Ref(t) => t,
|
||||
Self::Owned(t) => t,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
use super::{ByAmountRange, ByGreatEqualAmount, ByLowerThanAmount, GroupFilter};
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct AddressGroups<T> {
|
||||
pub ge_amount: ByGreatEqualAmount<T>,
|
||||
pub amount_range: ByAmountRange<T>,
|
||||
pub lt_amount: ByLowerThanAmount<T>,
|
||||
}
|
||||
|
||||
impl<T> AddressGroups<T> {
|
||||
pub fn as_mut_vecs(&mut self) -> Vec<&mut T> {
|
||||
self.ge_amount
|
||||
.as_mut_vec()
|
||||
.into_iter()
|
||||
.chain(self.amount_range.as_mut_vec())
|
||||
.chain(self.lt_amount.as_mut_vec())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub fn as_mut_separate_vecs(&mut self) -> Vec<&mut T> {
|
||||
self.amount_range
|
||||
.as_mut_vec()
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub fn as_mut_overlapping_vecs(&mut self) -> Vec<&mut T> {
|
||||
self.lt_amount
|
||||
.as_mut_vec()
|
||||
.into_iter()
|
||||
.chain(self.ge_amount.as_mut_vec())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AddressGroups<(GroupFilter, T)> {
|
||||
pub fn vecs(&self) -> Vec<&T> {
|
||||
self.amount_range
|
||||
.vecs()
|
||||
.into_iter()
|
||||
.chain(self.lt_amount.vecs())
|
||||
.chain(self.ge_amount.vecs())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<AddressGroups<T>> for AddressGroups<(GroupFilter, T)> {
|
||||
fn from(value: AddressGroups<T>) -> Self {
|
||||
Self {
|
||||
amount_range: ByAmountRange::from(value.amount_range),
|
||||
lt_amount: ByLowerThanAmount::from(value.lt_amount),
|
||||
ge_amount: ByGreatEqualAmount::from(value.ge_amount),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
use std::{
|
||||
mem,
|
||||
ops::{Add, AddAssign},
|
||||
};
|
||||
|
||||
use super::GroupFilter;
|
||||
use crate::OutputType;
|
||||
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct ByAddressType<T> {
|
||||
pub p2pk65: T,
|
||||
pub p2pk33: T,
|
||||
pub p2pkh: T,
|
||||
pub p2sh: T,
|
||||
pub p2wpkh: T,
|
||||
pub p2wsh: T,
|
||||
pub p2tr: T,
|
||||
pub p2a: T,
|
||||
}
|
||||
|
||||
impl<T> ByAddressType<T> {
|
||||
pub fn get(&self, address_type: OutputType) -> Option<&T> {
|
||||
match address_type {
|
||||
OutputType::P2PK65 => Some(&self.p2pk65),
|
||||
OutputType::P2PK33 => Some(&self.p2pk33),
|
||||
OutputType::P2PKH => Some(&self.p2pkh),
|
||||
OutputType::P2SH => Some(&self.p2sh),
|
||||
OutputType::P2WPKH => Some(&self.p2wpkh),
|
||||
OutputType::P2WSH => Some(&self.p2wsh),
|
||||
OutputType::P2TR => Some(&self.p2tr),
|
||||
OutputType::P2A => Some(&self.p2a),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, address_type: OutputType) -> Option<&mut T> {
|
||||
match address_type {
|
||||
OutputType::P2PK65 => Some(&mut self.p2pk65),
|
||||
OutputType::P2PK33 => Some(&mut self.p2pk33),
|
||||
OutputType::P2PKH => Some(&mut self.p2pkh),
|
||||
OutputType::P2SH => Some(&mut self.p2sh),
|
||||
OutputType::P2WPKH => Some(&mut self.p2wpkh),
|
||||
OutputType::P2WSH => Some(&mut self.p2wsh),
|
||||
OutputType::P2TR => Some(&mut self.p2tr),
|
||||
OutputType::P2A => Some(&mut self.p2a),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_mut_vec(&mut self) -> [&mut T; 8] {
|
||||
[
|
||||
&mut self.p2pk65,
|
||||
&mut self.p2pk33,
|
||||
&mut self.p2pkh,
|
||||
&mut self.p2sh,
|
||||
&mut self.p2wpkh,
|
||||
&mut self.p2wsh,
|
||||
&mut self.p2tr,
|
||||
&mut self.p2a,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn as_typed_vec(&self) -> [(OutputType, &T); 8] {
|
||||
[
|
||||
(OutputType::P2PK65, &self.p2pk65),
|
||||
(OutputType::P2PK33, &self.p2pk33),
|
||||
(OutputType::P2PKH, &self.p2pkh),
|
||||
(OutputType::P2SH, &self.p2sh),
|
||||
(OutputType::P2WPKH, &self.p2wpkh),
|
||||
(OutputType::P2WSH, &self.p2wsh),
|
||||
(OutputType::P2TR, &self.p2tr),
|
||||
(OutputType::P2A, &self.p2a),
|
||||
]
|
||||
}
|
||||
|
||||
pub fn as_mut_typed_vec(&mut self) -> [(OutputType, &mut T); 8] {
|
||||
[
|
||||
(OutputType::P2PK65, &mut self.p2pk65),
|
||||
(OutputType::P2PK33, &mut self.p2pk33),
|
||||
(OutputType::P2PKH, &mut self.p2pkh),
|
||||
(OutputType::P2SH, &mut self.p2sh),
|
||||
(OutputType::P2WPKH, &mut self.p2wpkh),
|
||||
(OutputType::P2WSH, &mut self.p2wsh),
|
||||
(OutputType::P2TR, &mut self.p2tr),
|
||||
(OutputType::P2A, &mut self.p2a),
|
||||
]
|
||||
}
|
||||
|
||||
pub fn into_typed_vec(&mut self) -> [(OutputType, T); 8]
|
||||
where
|
||||
T: Default,
|
||||
{
|
||||
[
|
||||
(OutputType::P2PK65, mem::take(&mut self.p2pk65)),
|
||||
(OutputType::P2PK33, mem::take(&mut self.p2pk33)),
|
||||
(OutputType::P2PKH, mem::take(&mut self.p2pkh)),
|
||||
(OutputType::P2SH, mem::take(&mut self.p2sh)),
|
||||
(OutputType::P2WPKH, mem::take(&mut self.p2wpkh)),
|
||||
(OutputType::P2WSH, mem::take(&mut self.p2wsh)),
|
||||
(OutputType::P2TR, mem::take(&mut self.p2tr)),
|
||||
(OutputType::P2A, mem::take(&mut self.p2a)),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ByAddressType<(GroupFilter, T)> {
|
||||
pub fn vecs(&self) -> [&T; 8] {
|
||||
[
|
||||
&self.p2pk65.1,
|
||||
&self.p2pk33.1,
|
||||
&self.p2pkh.1,
|
||||
&self.p2sh.1,
|
||||
&self.p2wpkh.1,
|
||||
&self.p2wsh.1,
|
||||
&self.p2tr.1,
|
||||
&self.p2a.1,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<ByAddressType<T>> for ByAddressType<(GroupFilter, T)> {
|
||||
fn from(value: ByAddressType<T>) -> Self {
|
||||
Self {
|
||||
p2pk65: (GroupFilter::Type(OutputType::P2PK65), value.p2pk65),
|
||||
p2pk33: (GroupFilter::Type(OutputType::P2PK33), value.p2pk33),
|
||||
p2pkh: (GroupFilter::Type(OutputType::P2PKH), value.p2pkh),
|
||||
p2sh: (GroupFilter::Type(OutputType::P2SH), value.p2sh),
|
||||
p2wpkh: (GroupFilter::Type(OutputType::P2WPKH), value.p2wpkh),
|
||||
p2wsh: (GroupFilter::Type(OutputType::P2WSH), value.p2wsh),
|
||||
p2tr: (GroupFilter::Type(OutputType::P2TR), value.p2tr),
|
||||
p2a: (GroupFilter::Type(OutputType::P2A), value.p2a),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Add for ByAddressType<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,
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AddAssign for ByAddressType<T>
|
||||
where
|
||||
T: AddAssign,
|
||||
{
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.p2pk65 += rhs.p2pk65;
|
||||
self.p2pk33 += rhs.p2pk33;
|
||||
self.p2pkh += rhs.p2pkh;
|
||||
self.p2sh += rhs.p2sh;
|
||||
self.p2wpkh += rhs.p2wpkh;
|
||||
self.p2wsh += rhs.p2wsh;
|
||||
self.p2tr += rhs.p2tr;
|
||||
self.p2a += rhs.p2a;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
use super::GroupFilter;
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct ByAgeRange<T> {
|
||||
pub up_to_1d: T,
|
||||
pub _1d_to_1w: T,
|
||||
pub _1w_to_1m: T,
|
||||
pub _1m_to_2m: T,
|
||||
pub _2m_to_3m: T,
|
||||
pub _3m_to_4m: T,
|
||||
pub _4m_to_5m: T,
|
||||
pub _5m_to_6m: T,
|
||||
pub _6m_to_1y: T,
|
||||
pub _1y_to_2y: T,
|
||||
pub _2y_to_3y: T,
|
||||
pub _3y_to_4y: T,
|
||||
pub _4y_to_5y: T,
|
||||
pub _5y_to_6y: T,
|
||||
pub _6y_to_7y: T,
|
||||
pub _7y_to_8y: T,
|
||||
pub _8y_to_10y: T,
|
||||
pub _10y_to_12y: T,
|
||||
pub _12y_to_15y: T,
|
||||
pub from_15y: T,
|
||||
}
|
||||
|
||||
impl<T> From<ByAgeRange<T>> for ByAgeRange<(GroupFilter, T)> {
|
||||
fn from(value: ByAgeRange<T>) -> Self {
|
||||
Self {
|
||||
up_to_1d: (GroupFilter::LowerThan(1), value.up_to_1d),
|
||||
_1d_to_1w: (GroupFilter::Range(1..7), value._1d_to_1w),
|
||||
_1w_to_1m: (GroupFilter::Range(7..30), value._1w_to_1m),
|
||||
_1m_to_2m: (GroupFilter::Range(30..2 * 30), value._1m_to_2m),
|
||||
_2m_to_3m: (GroupFilter::Range(2 * 30..3 * 30), value._2m_to_3m),
|
||||
_3m_to_4m: (GroupFilter::Range(3 * 30..4 * 30), value._3m_to_4m),
|
||||
_4m_to_5m: (GroupFilter::Range(4 * 30..5 * 30), value._4m_to_5m),
|
||||
_5m_to_6m: (GroupFilter::Range(5 * 30..6 * 30), value._5m_to_6m),
|
||||
_6m_to_1y: (GroupFilter::Range(6 * 30..365), value._6m_to_1y),
|
||||
_1y_to_2y: (GroupFilter::Range(365..2 * 365), value._1y_to_2y),
|
||||
_2y_to_3y: (GroupFilter::Range(2 * 365..3 * 365), value._2y_to_3y),
|
||||
_3y_to_4y: (GroupFilter::Range(3 * 365..4 * 365), value._3y_to_4y),
|
||||
_4y_to_5y: (GroupFilter::Range(4 * 365..5 * 365), value._4y_to_5y),
|
||||
_5y_to_6y: (GroupFilter::Range(5 * 365..6 * 365), value._5y_to_6y),
|
||||
_6y_to_7y: (GroupFilter::Range(6 * 365..7 * 365), value._6y_to_7y),
|
||||
_7y_to_8y: (GroupFilter::Range(7 * 365..8 * 365), value._7y_to_8y),
|
||||
_8y_to_10y: (GroupFilter::Range(8 * 365..10 * 365), value._8y_to_10y),
|
||||
_10y_to_12y: (GroupFilter::Range(10 * 365..12 * 365), value._10y_to_12y),
|
||||
_12y_to_15y: (GroupFilter::Range(12 * 365..15 * 365), value._12y_to_15y),
|
||||
from_15y: (GroupFilter::GreaterOrEqual(15 * 365), value.from_15y),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ByAgeRange<T> {
|
||||
pub fn as_vec(&mut self) -> [&T; 20] {
|
||||
[
|
||||
&self.up_to_1d,
|
||||
&self._1d_to_1w,
|
||||
&self._1w_to_1m,
|
||||
&self._1m_to_2m,
|
||||
&self._2m_to_3m,
|
||||
&self._3m_to_4m,
|
||||
&self._4m_to_5m,
|
||||
&self._5m_to_6m,
|
||||
&self._6m_to_1y,
|
||||
&self._1y_to_2y,
|
||||
&self._2y_to_3y,
|
||||
&self._3y_to_4y,
|
||||
&self._4y_to_5y,
|
||||
&self._5y_to_6y,
|
||||
&self._6y_to_7y,
|
||||
&self._7y_to_8y,
|
||||
&self._8y_to_10y,
|
||||
&self._10y_to_12y,
|
||||
&self._12y_to_15y,
|
||||
&self.from_15y,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn as_mut_vec(&mut self) -> [&mut T; 20] {
|
||||
[
|
||||
&mut self.up_to_1d,
|
||||
&mut self._1d_to_1w,
|
||||
&mut self._1w_to_1m,
|
||||
&mut self._1m_to_2m,
|
||||
&mut self._2m_to_3m,
|
||||
&mut self._3m_to_4m,
|
||||
&mut self._4m_to_5m,
|
||||
&mut self._5m_to_6m,
|
||||
&mut self._6m_to_1y,
|
||||
&mut self._1y_to_2y,
|
||||
&mut self._2y_to_3y,
|
||||
&mut self._3y_to_4y,
|
||||
&mut self._4y_to_5y,
|
||||
&mut self._5y_to_6y,
|
||||
&mut self._6y_to_7y,
|
||||
&mut self._7y_to_8y,
|
||||
&mut self._8y_to_10y,
|
||||
&mut self._10y_to_12y,
|
||||
&mut self._12y_to_15y,
|
||||
&mut self.from_15y,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ByAgeRange<(GroupFilter, T)> {
|
||||
pub fn vecs(&self) -> [&T; 20] {
|
||||
[
|
||||
&self.up_to_1d.1,
|
||||
&self._1d_to_1w.1,
|
||||
&self._1w_to_1m.1,
|
||||
&self._1m_to_2m.1,
|
||||
&self._2m_to_3m.1,
|
||||
&self._3m_to_4m.1,
|
||||
&self._4m_to_5m.1,
|
||||
&self._5m_to_6m.1,
|
||||
&self._6m_to_1y.1,
|
||||
&self._1y_to_2y.1,
|
||||
&self._2y_to_3y.1,
|
||||
&self._3y_to_4y.1,
|
||||
&self._4y_to_5y.1,
|
||||
&self._5y_to_6y.1,
|
||||
&self._6y_to_7y.1,
|
||||
&self._7y_to_8y.1,
|
||||
&self._8y_to_10y.1,
|
||||
&self._10y_to_12y.1,
|
||||
&self._12y_to_15y.1,
|
||||
&self.from_15y.1,
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
use std::ops::{Add, AddAssign};
|
||||
|
||||
use crate::Sats;
|
||||
|
||||
use super::GroupFilter;
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct ByAmountRange<T> {
|
||||
pub _0sats: T,
|
||||
pub _1sat_to_10sats: T,
|
||||
pub _10sats_to_100sats: T,
|
||||
pub _100sats_to_1k_sats: T,
|
||||
pub _1k_sats_to_10k_sats: T,
|
||||
pub _10k_sats_to_100k_sats: T,
|
||||
pub _100k_sats_to_1m_sats: T,
|
||||
pub _1m_sats_to_10m_sats: T,
|
||||
pub _10m_sats_to_1btc: T,
|
||||
pub _1btc_to_10btc: T,
|
||||
pub _10btc_to_100btc: T,
|
||||
pub _100btc_to_1k_btc: T,
|
||||
pub _1k_btc_to_10k_btc: T,
|
||||
pub _10k_btc_to_100k_btc: T,
|
||||
pub _100k_btc_or_more: T,
|
||||
}
|
||||
|
||||
impl<T> From<ByAmountRange<T>> for ByAmountRange<(GroupFilter, T)> {
|
||||
fn from(value: ByAmountRange<T>) -> Self {
|
||||
#[allow(clippy::inconsistent_digit_grouping)]
|
||||
Self {
|
||||
_0sats: (GroupFilter::LowerThan(Sats::_1.into()), value._0sats),
|
||||
_1sat_to_10sats: (
|
||||
GroupFilter::Range(Sats::_1.into()..Sats::_10.into()),
|
||||
value._1sat_to_10sats,
|
||||
),
|
||||
_10sats_to_100sats: (
|
||||
GroupFilter::Range(Sats::_10.into()..Sats::_100.into()),
|
||||
value._10sats_to_100sats,
|
||||
),
|
||||
_100sats_to_1k_sats: (
|
||||
GroupFilter::Range(Sats::_100.into()..Sats::_1K.into()),
|
||||
value._100sats_to_1k_sats,
|
||||
),
|
||||
_1k_sats_to_10k_sats: (
|
||||
GroupFilter::Range(Sats::_1K.into()..Sats::_10K.into()),
|
||||
value._1k_sats_to_10k_sats,
|
||||
),
|
||||
_10k_sats_to_100k_sats: (
|
||||
GroupFilter::Range(Sats::_10K.into()..Sats::_100K.into()),
|
||||
value._10k_sats_to_100k_sats,
|
||||
),
|
||||
_100k_sats_to_1m_sats: (
|
||||
GroupFilter::Range(Sats::_100K.into()..Sats::_1M.into()),
|
||||
value._100k_sats_to_1m_sats,
|
||||
),
|
||||
_1m_sats_to_10m_sats: (
|
||||
GroupFilter::Range(Sats::_1M.into()..Sats::_10M.into()),
|
||||
value._1m_sats_to_10m_sats,
|
||||
),
|
||||
_10m_sats_to_1btc: (
|
||||
GroupFilter::Range(Sats::_10M.into()..Sats::_1BTC.into()),
|
||||
value._10m_sats_to_1btc,
|
||||
),
|
||||
_1btc_to_10btc: (
|
||||
GroupFilter::Range(Sats::_1BTC.into()..Sats::_10BTC.into()),
|
||||
value._1btc_to_10btc,
|
||||
),
|
||||
_10btc_to_100btc: (
|
||||
GroupFilter::Range(Sats::_10BTC.into()..Sats::_100BTC.into()),
|
||||
value._10btc_to_100btc,
|
||||
),
|
||||
_100btc_to_1k_btc: (
|
||||
GroupFilter::Range(Sats::_100BTC.into()..Sats::_1K_BTC.into()),
|
||||
value._100btc_to_1k_btc,
|
||||
),
|
||||
_1k_btc_to_10k_btc: (
|
||||
GroupFilter::Range(Sats::_1K_BTC.into()..Sats::_10K_BTC.into()),
|
||||
value._1k_btc_to_10k_btc,
|
||||
),
|
||||
_10k_btc_to_100k_btc: (
|
||||
GroupFilter::Range(Sats::_10K_BTC.into()..Sats::_100K_BTC.into()),
|
||||
value._10k_btc_to_100k_btc,
|
||||
),
|
||||
_100k_btc_or_more: (
|
||||
GroupFilter::GreaterOrEqual(Sats::_100K_BTC.into()),
|
||||
value._100k_btc_or_more,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ByAmountRange<T> {
|
||||
#[allow(clippy::inconsistent_digit_grouping)]
|
||||
pub fn get_mut(&mut self, value: Sats) -> &mut T {
|
||||
if value == Sats::ZERO {
|
||||
&mut self._0sats
|
||||
} else if value < Sats::_10 {
|
||||
&mut self._1sat_to_10sats
|
||||
} else if value < Sats::_100 {
|
||||
&mut self._10sats_to_100sats
|
||||
} else if value < Sats::_1K {
|
||||
&mut self._100sats_to_1k_sats
|
||||
} else if value < Sats::_10K {
|
||||
&mut self._1k_sats_to_10k_sats
|
||||
} else if value < Sats::_100K {
|
||||
&mut self._10k_sats_to_100k_sats
|
||||
} else if value < Sats::_1M {
|
||||
&mut self._100k_sats_to_1m_sats
|
||||
} else if value < Sats::_10M {
|
||||
&mut self._1m_sats_to_10m_sats
|
||||
} else if value < Sats::_1BTC {
|
||||
&mut self._10m_sats_to_1btc
|
||||
} else if value < Sats::_10BTC {
|
||||
&mut self._1btc_to_10btc
|
||||
} else if value < Sats::_100BTC {
|
||||
&mut self._10btc_to_100btc
|
||||
} else if value < Sats::_1K_BTC {
|
||||
&mut self._100btc_to_1k_btc
|
||||
} else if value < Sats::_10K_BTC {
|
||||
&mut self._1k_btc_to_10k_btc
|
||||
} else if value < Sats::_100K_BTC {
|
||||
&mut self._10k_btc_to_100k_btc
|
||||
} else {
|
||||
&mut self._100k_btc_or_more
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vec(&self) -> [&T; 15] {
|
||||
[
|
||||
&self._0sats,
|
||||
&self._1sat_to_10sats,
|
||||
&self._10sats_to_100sats,
|
||||
&self._100sats_to_1k_sats,
|
||||
&self._1k_sats_to_10k_sats,
|
||||
&self._10k_sats_to_100k_sats,
|
||||
&self._100k_sats_to_1m_sats,
|
||||
&self._1m_sats_to_10m_sats,
|
||||
&self._10m_sats_to_1btc,
|
||||
&self._1btc_to_10btc,
|
||||
&self._10btc_to_100btc,
|
||||
&self._100btc_to_1k_btc,
|
||||
&self._1k_btc_to_10k_btc,
|
||||
&self._10k_btc_to_100k_btc,
|
||||
&self._100k_btc_or_more,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn as_typed_vec(&self) -> [(Sats, &T); 15] {
|
||||
[
|
||||
(Sats::ZERO, &self._0sats),
|
||||
(Sats::_1, &self._1sat_to_10sats),
|
||||
(Sats::_10, &self._10sats_to_100sats),
|
||||
(Sats::_100, &self._100sats_to_1k_sats),
|
||||
(Sats::_1K, &self._1k_sats_to_10k_sats),
|
||||
(Sats::_10K, &self._10k_sats_to_100k_sats),
|
||||
(Sats::_100K, &self._100k_sats_to_1m_sats),
|
||||
(Sats::_1M, &self._1m_sats_to_10m_sats),
|
||||
(Sats::_10M, &self._10m_sats_to_1btc),
|
||||
(Sats::_1BTC, &self._1btc_to_10btc),
|
||||
(Sats::_10BTC, &self._10btc_to_100btc),
|
||||
(Sats::_100BTC, &self._100btc_to_1k_btc),
|
||||
(Sats::_1K_BTC, &self._1k_btc_to_10k_btc),
|
||||
(Sats::_10K_BTC, &self._10k_btc_to_100k_btc),
|
||||
(Sats::_100K_BTC, &self._100k_btc_or_more),
|
||||
]
|
||||
}
|
||||
|
||||
pub fn as_mut_vec(&mut self) -> [&mut T; 15] {
|
||||
[
|
||||
&mut self._0sats,
|
||||
&mut self._1sat_to_10sats,
|
||||
&mut self._10sats_to_100sats,
|
||||
&mut self._100sats_to_1k_sats,
|
||||
&mut self._1k_sats_to_10k_sats,
|
||||
&mut self._10k_sats_to_100k_sats,
|
||||
&mut self._100k_sats_to_1m_sats,
|
||||
&mut self._1m_sats_to_10m_sats,
|
||||
&mut self._10m_sats_to_1btc,
|
||||
&mut self._1btc_to_10btc,
|
||||
&mut self._10btc_to_100btc,
|
||||
&mut self._100btc_to_1k_btc,
|
||||
&mut self._1k_btc_to_10k_btc,
|
||||
&mut self._10k_btc_to_100k_btc,
|
||||
&mut self._100k_btc_or_more,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ByAmountRange<(GroupFilter, T)> {
|
||||
pub fn vecs(&self) -> [&T; 15] {
|
||||
[
|
||||
&self._0sats.1,
|
||||
&self._1sat_to_10sats.1,
|
||||
&self._10sats_to_100sats.1,
|
||||
&self._100sats_to_1k_sats.1,
|
||||
&self._1k_sats_to_10k_sats.1,
|
||||
&self._10k_sats_to_100k_sats.1,
|
||||
&self._100k_sats_to_1m_sats.1,
|
||||
&self._1m_sats_to_10m_sats.1,
|
||||
&self._10m_sats_to_1btc.1,
|
||||
&self._1btc_to_10btc.1,
|
||||
&self._10btc_to_100btc.1,
|
||||
&self._100btc_to_1k_btc.1,
|
||||
&self._1k_btc_to_10k_btc.1,
|
||||
&self._10k_btc_to_100k_btc.1,
|
||||
&self._100k_btc_or_more.1,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Add for ByAmountRange<T>
|
||||
where
|
||||
T: Add<Output = T>,
|
||||
{
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self {
|
||||
_0sats: self._0sats + rhs._0sats,
|
||||
_1sat_to_10sats: self._1sat_to_10sats + rhs._1sat_to_10sats,
|
||||
_10sats_to_100sats: self._10sats_to_100sats + rhs._10sats_to_100sats,
|
||||
_100sats_to_1k_sats: self._100sats_to_1k_sats + rhs._100sats_to_1k_sats,
|
||||
_1k_sats_to_10k_sats: self._1k_sats_to_10k_sats + rhs._1k_sats_to_10k_sats,
|
||||
_10k_sats_to_100k_sats: self._10k_sats_to_100k_sats + rhs._10k_sats_to_100k_sats,
|
||||
_100k_sats_to_1m_sats: self._100k_sats_to_1m_sats + rhs._100k_sats_to_1m_sats,
|
||||
_1m_sats_to_10m_sats: self._1m_sats_to_10m_sats + rhs._1m_sats_to_10m_sats,
|
||||
_10m_sats_to_1btc: self._10m_sats_to_1btc + rhs._10m_sats_to_1btc,
|
||||
_1btc_to_10btc: self._1btc_to_10btc + rhs._1btc_to_10btc,
|
||||
_10btc_to_100btc: self._10btc_to_100btc + rhs._10btc_to_100btc,
|
||||
_100btc_to_1k_btc: self._100btc_to_1k_btc + rhs._100btc_to_1k_btc,
|
||||
_1k_btc_to_10k_btc: self._1k_btc_to_10k_btc + rhs._1k_btc_to_10k_btc,
|
||||
_10k_btc_to_100k_btc: self._10k_btc_to_100k_btc + rhs._10k_btc_to_100k_btc,
|
||||
_100k_btc_or_more: self._100k_btc_or_more + rhs._100k_btc_or_more,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AddAssign for ByAmountRange<T>
|
||||
where
|
||||
T: AddAssign,
|
||||
{
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self._0sats += rhs._0sats;
|
||||
self._1sat_to_10sats += rhs._1sat_to_10sats;
|
||||
self._10sats_to_100sats += rhs._10sats_to_100sats;
|
||||
self._100sats_to_1k_sats += rhs._100sats_to_1k_sats;
|
||||
self._1k_sats_to_10k_sats += rhs._1k_sats_to_10k_sats;
|
||||
self._10k_sats_to_100k_sats += rhs._10k_sats_to_100k_sats;
|
||||
self._100k_sats_to_1m_sats += rhs._100k_sats_to_1m_sats;
|
||||
self._1m_sats_to_10m_sats += rhs._1m_sats_to_10m_sats;
|
||||
self._10m_sats_to_1btc += rhs._10m_sats_to_1btc;
|
||||
self._1btc_to_10btc += rhs._1btc_to_10btc;
|
||||
self._10btc_to_100btc += rhs._10btc_to_100btc;
|
||||
self._100btc_to_1k_btc += rhs._100btc_to_1k_btc;
|
||||
self._1k_btc_to_10k_btc += rhs._1k_btc_to_10k_btc;
|
||||
self._10k_btc_to_100k_btc += rhs._10k_btc_to_100k_btc;
|
||||
self._100k_btc_or_more += rhs._100k_btc_or_more;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
use brk_core::{HalvingEpoch, Height};
|
||||
use crate::{HalvingEpoch, Height};
|
||||
|
||||
use super::OutputFilter;
|
||||
use super::GroupFilter;
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct OutputsByEpoch<T> {
|
||||
pub struct ByEpoch<T> {
|
||||
pub _0: T,
|
||||
pub _1: T,
|
||||
pub _2: T,
|
||||
@@ -11,19 +11,19 @@ pub struct OutputsByEpoch<T> {
|
||||
pub _4: T,
|
||||
}
|
||||
|
||||
impl<T> From<OutputsByEpoch<T>> for OutputsByEpoch<(OutputFilter, T)> {
|
||||
fn from(value: OutputsByEpoch<T>) -> Self {
|
||||
impl<T> From<ByEpoch<T>> for ByEpoch<(GroupFilter, T)> {
|
||||
fn from(value: ByEpoch<T>) -> Self {
|
||||
Self {
|
||||
_0: (OutputFilter::Epoch(HalvingEpoch::new(0)), value._0),
|
||||
_1: (OutputFilter::Epoch(HalvingEpoch::new(1)), value._1),
|
||||
_2: (OutputFilter::Epoch(HalvingEpoch::new(2)), value._2),
|
||||
_3: (OutputFilter::Epoch(HalvingEpoch::new(3)), value._3),
|
||||
_4: (OutputFilter::Epoch(HalvingEpoch::new(4)), value._4),
|
||||
_0: (GroupFilter::Epoch(HalvingEpoch::new(0)), value._0),
|
||||
_1: (GroupFilter::Epoch(HalvingEpoch::new(1)), value._1),
|
||||
_2: (GroupFilter::Epoch(HalvingEpoch::new(2)), value._2),
|
||||
_3: (GroupFilter::Epoch(HalvingEpoch::new(3)), value._3),
|
||||
_4: (GroupFilter::Epoch(HalvingEpoch::new(4)), value._4),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> OutputsByEpoch<T> {
|
||||
impl<T> ByEpoch<T> {
|
||||
pub fn as_mut_vec(&mut self) -> [&mut T; 5] {
|
||||
[
|
||||
&mut self._0,
|
||||
@@ -52,7 +52,7 @@ impl<T> OutputsByEpoch<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> OutputsByEpoch<(OutputFilter, T)> {
|
||||
impl<T> ByEpoch<(GroupFilter, T)> {
|
||||
pub fn vecs(&self) -> [&T; 5] {
|
||||
[&self._0.1, &self._1.1, &self._2.1, &self._3.1, &self._4.1]
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
use crate::Sats;
|
||||
|
||||
use super::GroupFilter;
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct ByGreatEqualAmount<T> {
|
||||
pub _1sat: T,
|
||||
pub _10sats: T,
|
||||
pub _100sats: T,
|
||||
pub _1k_sats: T,
|
||||
pub _10k_sats: T,
|
||||
pub _100k_sats: T,
|
||||
pub _1m_sats: T,
|
||||
pub _10m_sats: T,
|
||||
pub _1btc: T,
|
||||
pub _10btc: T,
|
||||
pub _100btc: T,
|
||||
pub _1k_btc: T,
|
||||
pub _10k_btc: T,
|
||||
}
|
||||
|
||||
impl<T> ByGreatEqualAmount<T> {
|
||||
pub fn as_mut_vec(&mut self) -> [&mut T; 13] {
|
||||
[
|
||||
&mut self._1sat,
|
||||
&mut self._10sats,
|
||||
&mut self._100sats,
|
||||
&mut self._1k_sats,
|
||||
&mut self._10k_sats,
|
||||
&mut self._100k_sats,
|
||||
&mut self._1m_sats,
|
||||
&mut self._10m_sats,
|
||||
&mut self._1btc,
|
||||
&mut self._10btc,
|
||||
&mut self._100btc,
|
||||
&mut self._1k_btc,
|
||||
&mut self._10k_btc,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ByGreatEqualAmount<(GroupFilter, T)> {
|
||||
pub fn vecs(&self) -> [&T; 13] {
|
||||
[
|
||||
&self._1sat.1,
|
||||
&self._10sats.1,
|
||||
&self._100sats.1,
|
||||
&self._1k_sats.1,
|
||||
&self._10k_sats.1,
|
||||
&self._100k_sats.1,
|
||||
&self._1m_sats.1,
|
||||
&self._10m_sats.1,
|
||||
&self._1btc.1,
|
||||
&self._10btc.1,
|
||||
&self._100btc.1,
|
||||
&self._1k_btc.1,
|
||||
&self._10k_btc.1,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<ByGreatEqualAmount<T>> for ByGreatEqualAmount<(GroupFilter, T)> {
|
||||
fn from(value: ByGreatEqualAmount<T>) -> Self {
|
||||
Self {
|
||||
_1sat: (GroupFilter::GreaterOrEqual(Sats::_1.into()), value._1sat),
|
||||
_10sats: (GroupFilter::GreaterOrEqual(Sats::_10.into()), value._10sats),
|
||||
_100sats: (
|
||||
GroupFilter::GreaterOrEqual(Sats::_100.into()),
|
||||
value._100sats,
|
||||
),
|
||||
_1k_sats: (
|
||||
GroupFilter::GreaterOrEqual(Sats::_1K.into()),
|
||||
value._1k_sats,
|
||||
),
|
||||
_10k_sats: (
|
||||
GroupFilter::GreaterOrEqual(Sats::_10K.into()),
|
||||
value._10k_sats,
|
||||
),
|
||||
_100k_sats: (
|
||||
GroupFilter::GreaterOrEqual(Sats::_100K.into()),
|
||||
value._100k_sats,
|
||||
),
|
||||
_1m_sats: (
|
||||
GroupFilter::GreaterOrEqual(Sats::_1M.into()),
|
||||
value._1m_sats,
|
||||
),
|
||||
_10m_sats: (
|
||||
GroupFilter::GreaterOrEqual(Sats::_10M.into()),
|
||||
value._10m_sats,
|
||||
),
|
||||
_1btc: (GroupFilter::GreaterOrEqual(Sats::_1BTC.into()), value._1btc),
|
||||
_10btc: (
|
||||
GroupFilter::GreaterOrEqual(Sats::_10BTC.into()),
|
||||
value._10btc,
|
||||
),
|
||||
_100btc: (
|
||||
GroupFilter::GreaterOrEqual(Sats::_100BTC.into()),
|
||||
value._100btc,
|
||||
),
|
||||
_1k_btc: (
|
||||
GroupFilter::GreaterOrEqual(Sats::_1K_BTC.into()),
|
||||
value._1k_btc,
|
||||
),
|
||||
_10k_btc: (
|
||||
GroupFilter::GreaterOrEqual(Sats::_10K_BTC.into()),
|
||||
value._10k_btc,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
use crate::Sats;
|
||||
|
||||
use super::GroupFilter;
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct ByLowerThanAmount<T> {
|
||||
pub _10sats: T,
|
||||
pub _100sats: T,
|
||||
pub _1k_sats: T,
|
||||
pub _10k_sats: T,
|
||||
pub _100k_sats: T,
|
||||
pub _1m_sats: T,
|
||||
pub _10m_sats: T,
|
||||
pub _1btc: T,
|
||||
pub _10btc: T,
|
||||
pub _100btc: T,
|
||||
pub _1k_btc: T,
|
||||
pub _10k_btc: T,
|
||||
pub _100k_btc: T,
|
||||
}
|
||||
|
||||
impl<T> ByLowerThanAmount<T> {
|
||||
pub fn as_mut_vec(&mut self) -> [&mut T; 13] {
|
||||
[
|
||||
&mut self._10sats,
|
||||
&mut self._100sats,
|
||||
&mut self._1k_sats,
|
||||
&mut self._10k_sats,
|
||||
&mut self._100k_sats,
|
||||
&mut self._1m_sats,
|
||||
&mut self._10m_sats,
|
||||
&mut self._1btc,
|
||||
&mut self._10btc,
|
||||
&mut self._100btc,
|
||||
&mut self._1k_btc,
|
||||
&mut self._10k_btc,
|
||||
&mut self._100k_btc,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ByLowerThanAmount<(GroupFilter, T)> {
|
||||
pub fn vecs(&self) -> [&T; 13] {
|
||||
[
|
||||
&self._10sats.1,
|
||||
&self._100sats.1,
|
||||
&self._1k_sats.1,
|
||||
&self._10k_sats.1,
|
||||
&self._100k_sats.1,
|
||||
&self._1m_sats.1,
|
||||
&self._10m_sats.1,
|
||||
&self._1btc.1,
|
||||
&self._10btc.1,
|
||||
&self._100btc.1,
|
||||
&self._1k_btc.1,
|
||||
&self._10k_btc.1,
|
||||
&self._100k_btc.1,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<ByLowerThanAmount<T>> for ByLowerThanAmount<(GroupFilter, T)> {
|
||||
fn from(value: ByLowerThanAmount<T>) -> Self {
|
||||
Self {
|
||||
_10sats: (GroupFilter::LowerThan(Sats::_10.into()), value._10sats),
|
||||
_100sats: (GroupFilter::LowerThan(Sats::_100.into()), value._100sats),
|
||||
_1k_sats: (GroupFilter::LowerThan(Sats::_1K.into()), value._1k_sats),
|
||||
_10k_sats: (GroupFilter::LowerThan(Sats::_10K.into()), value._10k_sats),
|
||||
_100k_sats: (GroupFilter::LowerThan(Sats::_100K.into()), value._100k_sats),
|
||||
_1m_sats: (GroupFilter::LowerThan(Sats::_1M.into()), value._1m_sats),
|
||||
_10m_sats: (GroupFilter::LowerThan(Sats::_10M.into()), value._10m_sats),
|
||||
_1btc: (GroupFilter::LowerThan(Sats::_1BTC.into()), value._1btc),
|
||||
_10btc: (GroupFilter::LowerThan(Sats::_10BTC.into()), value._10btc),
|
||||
_100btc: (GroupFilter::LowerThan(Sats::_100BTC.into()), value._100btc),
|
||||
_1k_btc: (GroupFilter::LowerThan(Sats::_1K_BTC.into()), value._1k_btc),
|
||||
_10k_btc: (
|
||||
GroupFilter::LowerThan(Sats::_10K_BTC.into()),
|
||||
value._10k_btc,
|
||||
),
|
||||
_100k_btc: (
|
||||
GroupFilter::LowerThan(Sats::_100K_BTC.into()),
|
||||
value._100k_btc,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
use super::GroupFilter;
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct ByMaxAge<T> {
|
||||
pub _1w: T,
|
||||
pub _1m: T,
|
||||
pub _2m: T,
|
||||
pub _3m: T,
|
||||
pub _4m: T,
|
||||
pub _5m: T,
|
||||
pub _6m: T,
|
||||
pub _1y: T,
|
||||
pub _2y: T,
|
||||
pub _3y: T,
|
||||
pub _4y: T,
|
||||
pub _5y: T,
|
||||
pub _6y: T,
|
||||
pub _7y: T,
|
||||
pub _8y: T,
|
||||
pub _10y: T,
|
||||
pub _12y: T,
|
||||
pub _15y: T,
|
||||
}
|
||||
|
||||
impl<T> ByMaxAge<T> {
|
||||
pub fn as_mut_vec(&mut self) -> [&mut T; 18] {
|
||||
[
|
||||
&mut self._1w,
|
||||
&mut self._1m,
|
||||
&mut self._2m,
|
||||
&mut self._3m,
|
||||
&mut self._4m,
|
||||
&mut self._5m,
|
||||
&mut self._6m,
|
||||
&mut self._1y,
|
||||
&mut self._2y,
|
||||
&mut self._3y,
|
||||
&mut self._4y,
|
||||
&mut self._5y,
|
||||
&mut self._6y,
|
||||
&mut self._7y,
|
||||
&mut self._8y,
|
||||
&mut self._10y,
|
||||
&mut self._12y,
|
||||
&mut self._15y,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ByMaxAge<(GroupFilter, T)> {
|
||||
pub fn vecs(&self) -> [&T; 18] {
|
||||
[
|
||||
&self._1w.1,
|
||||
&self._1m.1,
|
||||
&self._2m.1,
|
||||
&self._3m.1,
|
||||
&self._4m.1,
|
||||
&self._5m.1,
|
||||
&self._6m.1,
|
||||
&self._1y.1,
|
||||
&self._2y.1,
|
||||
&self._3y.1,
|
||||
&self._4y.1,
|
||||
&self._5y.1,
|
||||
&self._6y.1,
|
||||
&self._7y.1,
|
||||
&self._8y.1,
|
||||
&self._10y.1,
|
||||
&self._12y.1,
|
||||
&self._15y.1,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<ByMaxAge<T>> for ByMaxAge<(GroupFilter, T)> {
|
||||
fn from(value: ByMaxAge<T>) -> Self {
|
||||
Self {
|
||||
_1w: (GroupFilter::LowerThan(7), value._1w),
|
||||
_1m: (GroupFilter::LowerThan(30), value._1m),
|
||||
_2m: (GroupFilter::LowerThan(2 * 30), value._2m),
|
||||
_3m: (GroupFilter::LowerThan(3 * 30), value._3m),
|
||||
_4m: (GroupFilter::LowerThan(4 * 30), value._4m),
|
||||
_5m: (GroupFilter::LowerThan(5 * 30), value._5m),
|
||||
_6m: (GroupFilter::LowerThan(6 * 30), value._6m),
|
||||
_1y: (GroupFilter::LowerThan(365), value._1y),
|
||||
_2y: (GroupFilter::LowerThan(2 * 365), value._2y),
|
||||
_3y: (GroupFilter::LowerThan(3 * 365), value._3y),
|
||||
_4y: (GroupFilter::LowerThan(4 * 365), value._4y),
|
||||
_5y: (GroupFilter::LowerThan(5 * 365), value._5y),
|
||||
_6y: (GroupFilter::LowerThan(6 * 365), value._6y),
|
||||
_7y: (GroupFilter::LowerThan(7 * 365), value._7y),
|
||||
_8y: (GroupFilter::LowerThan(8 * 365), value._8y),
|
||||
_10y: (GroupFilter::LowerThan(10 * 365), value._10y),
|
||||
_12y: (GroupFilter::LowerThan(12 * 365), value._12y),
|
||||
_15y: (GroupFilter::LowerThan(15 * 365), value._15y),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
use super::GroupFilter;
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct ByMinAge<T> {
|
||||
pub _1d: T,
|
||||
pub _1w: T,
|
||||
pub _1m: T,
|
||||
pub _2m: T,
|
||||
pub _3m: T,
|
||||
pub _4m: T,
|
||||
pub _5m: T,
|
||||
pub _6m: T,
|
||||
pub _1y: T,
|
||||
pub _2y: T,
|
||||
pub _3y: T,
|
||||
pub _4y: T,
|
||||
pub _5y: T,
|
||||
pub _6y: T,
|
||||
pub _7y: T,
|
||||
pub _8y: T,
|
||||
pub _10y: T,
|
||||
pub _12y: T,
|
||||
}
|
||||
|
||||
impl<T> ByMinAge<T> {
|
||||
pub fn as_mut_vec(&mut self) -> [&mut T; 18] {
|
||||
[
|
||||
&mut self._1d,
|
||||
&mut self._1w,
|
||||
&mut self._1m,
|
||||
&mut self._2m,
|
||||
&mut self._3m,
|
||||
&mut self._4m,
|
||||
&mut self._5m,
|
||||
&mut self._6m,
|
||||
&mut self._1y,
|
||||
&mut self._2y,
|
||||
&mut self._3y,
|
||||
&mut self._4y,
|
||||
&mut self._5y,
|
||||
&mut self._6y,
|
||||
&mut self._7y,
|
||||
&mut self._8y,
|
||||
&mut self._10y,
|
||||
&mut self._12y,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ByMinAge<(GroupFilter, T)> {
|
||||
pub fn vecs(&self) -> [&T; 18] {
|
||||
[
|
||||
&self._1d.1,
|
||||
&self._1w.1,
|
||||
&self._1m.1,
|
||||
&self._2m.1,
|
||||
&self._3m.1,
|
||||
&self._4m.1,
|
||||
&self._5m.1,
|
||||
&self._6m.1,
|
||||
&self._1y.1,
|
||||
&self._2y.1,
|
||||
&self._3y.1,
|
||||
&self._4y.1,
|
||||
&self._5y.1,
|
||||
&self._6y.1,
|
||||
&self._7y.1,
|
||||
&self._8y.1,
|
||||
&self._10y.1,
|
||||
&self._12y.1,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<ByMinAge<T>> for ByMinAge<(GroupFilter, T)> {
|
||||
fn from(value: ByMinAge<T>) -> Self {
|
||||
Self {
|
||||
_1d: (GroupFilter::GreaterOrEqual(1), value._1d),
|
||||
_1w: (GroupFilter::GreaterOrEqual(7), value._1w),
|
||||
_1m: (GroupFilter::GreaterOrEqual(30), value._1m),
|
||||
_2m: (GroupFilter::GreaterOrEqual(2 * 30), value._2m),
|
||||
_3m: (GroupFilter::GreaterOrEqual(3 * 30), value._3m),
|
||||
_4m: (GroupFilter::GreaterOrEqual(4 * 30), value._4m),
|
||||
_5m: (GroupFilter::GreaterOrEqual(5 * 30), value._5m),
|
||||
_6m: (GroupFilter::GreaterOrEqual(6 * 30), value._6m),
|
||||
_1y: (GroupFilter::GreaterOrEqual(365), value._1y),
|
||||
_2y: (GroupFilter::GreaterOrEqual(2 * 365), value._2y),
|
||||
_3y: (GroupFilter::GreaterOrEqual(3 * 365), value._3y),
|
||||
_4y: (GroupFilter::GreaterOrEqual(4 * 365), value._4y),
|
||||
_5y: (GroupFilter::GreaterOrEqual(5 * 365), value._5y),
|
||||
_6y: (GroupFilter::GreaterOrEqual(6 * 365), value._6y),
|
||||
_7y: (GroupFilter::GreaterOrEqual(7 * 365), value._7y),
|
||||
_8y: (GroupFilter::GreaterOrEqual(8 * 365), value._8y),
|
||||
_10y: (GroupFilter::GreaterOrEqual(10 * 365), value._10y),
|
||||
_12y: (GroupFilter::GreaterOrEqual(12 * 365), value._12y),
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
-53
@@ -1,11 +1,11 @@
|
||||
use std::ops::{Add, AddAssign};
|
||||
|
||||
use brk_core::OutputType;
|
||||
use crate::OutputType;
|
||||
|
||||
use super::OutputFilter;
|
||||
use super::GroupFilter;
|
||||
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct OutputsBySpendableType<T> {
|
||||
pub struct BySpendableType<T> {
|
||||
pub p2pk65: T,
|
||||
pub p2pk33: T,
|
||||
pub p2pkh: T,
|
||||
@@ -19,24 +19,7 @@ pub struct OutputsBySpendableType<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,
|
||||
// OutputType::Empty => &self.empty,
|
||||
// _ => unreachable!(),
|
||||
// }
|
||||
// }
|
||||
|
||||
impl<T> BySpendableType<T> {
|
||||
pub fn get_mut(&mut self, output_type: OutputType) -> &mut T {
|
||||
match output_type {
|
||||
OutputType::P2PK65 => &mut self.p2pk65,
|
||||
@@ -54,22 +37,6 @@ impl<T> OutputsBySpendableType<T> {
|
||||
}
|
||||
}
|
||||
|
||||
// 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; 11] {
|
||||
[
|
||||
&mut self.p2pk65,
|
||||
@@ -103,7 +70,7 @@ impl<T> OutputsBySpendableType<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> OutputsBySpendableType<(OutputFilter, T)> {
|
||||
impl<T> BySpendableType<(GroupFilter, T)> {
|
||||
pub fn vecs(&self) -> [&T; 11] {
|
||||
[
|
||||
&self.p2pk65.1,
|
||||
@@ -121,25 +88,25 @@ impl<T> OutputsBySpendableType<(OutputFilter, T)> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<OutputsBySpendableType<T>> for OutputsBySpendableType<(OutputFilter, T)> {
|
||||
fn from(value: OutputsBySpendableType<T>) -> Self {
|
||||
impl<T> From<BySpendableType<T>> for BySpendableType<(GroupFilter, T)> {
|
||||
fn from(value: BySpendableType<T>) -> Self {
|
||||
Self {
|
||||
p2pk65: (OutputFilter::Type(OutputType::P2PK65), value.p2pk65),
|
||||
p2pk33: (OutputFilter::Type(OutputType::P2PK33), value.p2pk33),
|
||||
p2pkh: (OutputFilter::Type(OutputType::P2PKH), value.p2pkh),
|
||||
p2ms: (OutputFilter::Type(OutputType::P2MS), value.p2ms),
|
||||
p2sh: (OutputFilter::Type(OutputType::P2SH), value.p2sh),
|
||||
p2wpkh: (OutputFilter::Type(OutputType::P2WPKH), value.p2wpkh),
|
||||
p2wsh: (OutputFilter::Type(OutputType::P2WSH), value.p2wsh),
|
||||
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),
|
||||
p2pk65: (GroupFilter::Type(OutputType::P2PK65), value.p2pk65),
|
||||
p2pk33: (GroupFilter::Type(OutputType::P2PK33), value.p2pk33),
|
||||
p2pkh: (GroupFilter::Type(OutputType::P2PKH), value.p2pkh),
|
||||
p2ms: (GroupFilter::Type(OutputType::P2MS), value.p2ms),
|
||||
p2sh: (GroupFilter::Type(OutputType::P2SH), value.p2sh),
|
||||
p2wpkh: (GroupFilter::Type(OutputType::P2WPKH), value.p2wpkh),
|
||||
p2wsh: (GroupFilter::Type(OutputType::P2WSH), value.p2wsh),
|
||||
p2tr: (GroupFilter::Type(OutputType::P2TR), value.p2tr),
|
||||
p2a: (GroupFilter::Type(OutputType::P2A), value.p2a),
|
||||
unknown: (GroupFilter::Type(OutputType::Unknown), value.unknown),
|
||||
empty: (GroupFilter::Type(OutputType::Empty), value.empty),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Add for OutputsBySpendableType<T>
|
||||
impl<T> Add for BySpendableType<T>
|
||||
where
|
||||
T: Add<Output = T>,
|
||||
{
|
||||
@@ -161,7 +128,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AddAssign for OutputsBySpendableType<T>
|
||||
impl<T> AddAssign for BySpendableType<T>
|
||||
where
|
||||
T: AddAssign,
|
||||
{
|
||||
@@ -0,0 +1,28 @@
|
||||
use super::GroupFilter;
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct ByTerm<T> {
|
||||
pub short: T,
|
||||
pub long: T,
|
||||
}
|
||||
|
||||
impl<T> ByTerm<T> {
|
||||
pub fn as_mut_vec(&mut self) -> [&mut T; 2] {
|
||||
[&mut self.short, &mut self.long]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ByTerm<(GroupFilter, T)> {
|
||||
pub fn vecs(&self) -> [&T; 2] {
|
||||
[&self.short.1, &self.long.1]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<ByTerm<T>> for ByTerm<(GroupFilter, T)> {
|
||||
fn from(value: ByTerm<T>) -> Self {
|
||||
Self {
|
||||
short: (GroupFilter::LowerThan(5 * 30), value.short),
|
||||
long: (GroupFilter::GreaterOrEqual(5 * 30), value.long),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
use std::ops::{Add, AddAssign};
|
||||
|
||||
use brk_core::OutputType;
|
||||
use crate::OutputType;
|
||||
|
||||
use super::{OutputsBySpendableType, OutputsByUnspendableType};
|
||||
use super::{BySpendableType, ByUnspendableType};
|
||||
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct OutputsByType<T> {
|
||||
pub spendable: OutputsBySpendableType<T>,
|
||||
pub unspendable: OutputsByUnspendableType<T>,
|
||||
pub struct GroupedByType<T> {
|
||||
pub spendable: BySpendableType<T>,
|
||||
pub unspendable: ByUnspendableType<T>,
|
||||
}
|
||||
|
||||
impl<T> OutputsByType<T> {
|
||||
impl<T> GroupedByType<T> {
|
||||
pub fn get(&self, output_type: OutputType) -> &T {
|
||||
match output_type {
|
||||
OutputType::P2PK65 => &self.spendable.p2pk65,
|
||||
@@ -44,25 +44,9 @@ impl<T> OutputsByType<T> {
|
||||
OutputType::OpReturn => &mut self.unspendable.opreturn,
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// .as_mut_vec()
|
||||
// .into_iter()
|
||||
// .chain(self.unspendable.as_mut_vec())
|
||||
// .collect::<Vec<_>>()
|
||||
// }
|
||||
}
|
||||
|
||||
impl<T> Add for OutputsByType<T>
|
||||
impl<T> Add for GroupedByType<T>
|
||||
where
|
||||
T: Add<Output = T>,
|
||||
{
|
||||
@@ -75,7 +59,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AddAssign for OutputsByType<T>
|
||||
impl<T> AddAssign for GroupedByType<T>
|
||||
where
|
||||
T: AddAssign,
|
||||
{
|
||||
+4
-4
@@ -1,17 +1,17 @@
|
||||
use std::ops::{Add, AddAssign};
|
||||
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct OutputsByUnspendableType<T> {
|
||||
pub struct ByUnspendableType<T> {
|
||||
pub opreturn: T,
|
||||
}
|
||||
|
||||
impl<T> OutputsByUnspendableType<T> {
|
||||
impl<T> ByUnspendableType<T> {
|
||||
pub fn as_vec(&self) -> [&T; 1] {
|
||||
[&self.opreturn]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Add for OutputsByUnspendableType<T>
|
||||
impl<T> Add for ByUnspendableType<T>
|
||||
where
|
||||
T: Add<Output = T>,
|
||||
{
|
||||
@@ -23,7 +23,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AddAssign for OutputsByUnspendableType<T>
|
||||
impl<T> AddAssign for ByUnspendableType<T>
|
||||
where
|
||||
T: AddAssign,
|
||||
{
|
||||
@@ -1,5 +1,5 @@
|
||||
#[derive(Default, Clone)]
|
||||
pub struct OutputsByValue<T> {
|
||||
pub struct GroupedByValue<T> {
|
||||
pub up_to_1cent: T,
|
||||
pub from_1c_to_10c: T,
|
||||
pub from_10c_to_1d: T,
|
||||
@@ -16,7 +16,7 @@ pub struct OutputsByValue<T> {
|
||||
// ...
|
||||
}
|
||||
|
||||
impl<T> OutputsByValue<T> {
|
||||
impl<T> GroupedByValue<T> {
|
||||
pub fn as_mut_vec(&mut self) -> Vec<&mut T> {
|
||||
vec![
|
||||
&mut self.up_to_1cent,
|
||||
@@ -0,0 +1,51 @@
|
||||
use std::ops::Range;
|
||||
|
||||
use crate::{HalvingEpoch, OutputType};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum GroupFilter {
|
||||
All,
|
||||
LowerThan(usize),
|
||||
Range(Range<usize>),
|
||||
GreaterOrEqual(usize),
|
||||
Epoch(HalvingEpoch),
|
||||
Type(OutputType),
|
||||
}
|
||||
|
||||
impl GroupFilter {
|
||||
pub fn contains(&self, value: usize) -> bool {
|
||||
match self {
|
||||
GroupFilter::All => true,
|
||||
GroupFilter::LowerThan(max) => *max > value,
|
||||
GroupFilter::GreaterOrEqual(min) => *min <= value,
|
||||
GroupFilter::Range(r) => r.contains(&value),
|
||||
GroupFilter::Epoch(_) => false,
|
||||
GroupFilter::Type(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn includes(&self, other: &GroupFilter) -> bool {
|
||||
match self {
|
||||
GroupFilter::All => true,
|
||||
GroupFilter::LowerThan(max) => match other {
|
||||
GroupFilter::All => false,
|
||||
GroupFilter::LowerThan(max2) => max >= max2,
|
||||
GroupFilter::Range(range) => range.end <= *max,
|
||||
GroupFilter::GreaterOrEqual(_) => false,
|
||||
GroupFilter::Epoch(_) => false,
|
||||
GroupFilter::Type(_) => false,
|
||||
},
|
||||
GroupFilter::GreaterOrEqual(min) => match other {
|
||||
GroupFilter::All => false,
|
||||
GroupFilter::LowerThan(_) => false,
|
||||
GroupFilter::Range(range) => range.start >= *min,
|
||||
GroupFilter::GreaterOrEqual(min2) => min <= min2,
|
||||
GroupFilter::Epoch(_) => false,
|
||||
GroupFilter::Type(_) => false,
|
||||
},
|
||||
GroupFilter::Range(_) => false,
|
||||
GroupFilter::Epoch(_) => false,
|
||||
GroupFilter::Type(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
mod address;
|
||||
mod by_address_type;
|
||||
mod by_age_range;
|
||||
mod by_amount_range;
|
||||
mod by_epoch;
|
||||
mod by_ge_amount;
|
||||
mod by_lt_amount;
|
||||
mod by_max_age;
|
||||
mod by_min_age;
|
||||
mod by_spendable_type;
|
||||
mod by_term;
|
||||
mod by_type;
|
||||
mod by_unspendable_type;
|
||||
mod filter;
|
||||
mod utxo;
|
||||
|
||||
pub use address::*;
|
||||
pub use by_address_type::*;
|
||||
pub use by_age_range::*;
|
||||
pub use by_amount_range::*;
|
||||
pub use by_epoch::*;
|
||||
pub use by_ge_amount::*;
|
||||
pub use by_lt_amount::*;
|
||||
pub use by_max_age::*;
|
||||
pub use by_min_age::*;
|
||||
pub use by_spendable_type::*;
|
||||
pub use by_term::*;
|
||||
pub use by_type::*;
|
||||
pub use by_unspendable_type::*;
|
||||
pub use filter::*;
|
||||
pub use utxo::*;
|
||||
@@ -0,0 +1,90 @@
|
||||
use crate::{
|
||||
ByAgeRange, ByAmountRange, ByEpoch, ByGreatEqualAmount, ByLowerThanAmount, ByMaxAge, ByMinAge,
|
||||
BySpendableType, ByTerm, GroupFilter,
|
||||
};
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct UTXOGroups<T> {
|
||||
pub all: T,
|
||||
pub age_range: ByAgeRange<T>,
|
||||
pub epoch: ByEpoch<T>,
|
||||
pub min_age: ByMinAge<T>,
|
||||
pub ge_amount: ByGreatEqualAmount<T>,
|
||||
pub amount_range: ByAmountRange<T>,
|
||||
pub term: ByTerm<T>,
|
||||
pub _type: BySpendableType<T>,
|
||||
pub max_age: ByMaxAge<T>,
|
||||
pub lt_amount: ByLowerThanAmount<T>,
|
||||
}
|
||||
|
||||
impl<T> UTXOGroups<T> {
|
||||
pub fn as_mut_vecs(&mut self) -> Vec<&mut T> {
|
||||
[&mut self.all]
|
||||
.into_iter()
|
||||
.chain(self.term.as_mut_vec())
|
||||
.chain(self.max_age.as_mut_vec())
|
||||
.chain(self.min_age.as_mut_vec())
|
||||
.chain(self.ge_amount.as_mut_vec())
|
||||
.chain(self.age_range.as_mut_vec())
|
||||
.chain(self.epoch.as_mut_vec())
|
||||
.chain(self.amount_range.as_mut_vec())
|
||||
.chain(self.lt_amount.as_mut_vec())
|
||||
.chain(self._type.as_mut_vec())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub fn as_mut_separate_vecs(&mut self) -> Vec<&mut T> {
|
||||
self.age_range
|
||||
.as_mut_vec()
|
||||
.into_iter()
|
||||
.chain(self.epoch.as_mut_vec())
|
||||
.chain(self.amount_range.as_mut_vec())
|
||||
.chain(self._type.as_mut_vec())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub fn as_mut_overlapping_vecs(&mut self) -> Vec<&mut T> {
|
||||
[&mut self.all]
|
||||
.into_iter()
|
||||
.chain(self.term.as_mut_vec())
|
||||
.chain(self.max_age.as_mut_vec())
|
||||
.chain(self.min_age.as_mut_vec())
|
||||
.chain(self.lt_amount.as_mut_vec())
|
||||
.chain(self.ge_amount.as_mut_vec())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> UTXOGroups<(GroupFilter, T)> {
|
||||
pub fn vecs(&self) -> Vec<&T> {
|
||||
[&self.all.1]
|
||||
.into_iter()
|
||||
.chain(self.term.vecs())
|
||||
.chain(self.max_age.vecs())
|
||||
.chain(self.min_age.vecs())
|
||||
.chain(self.age_range.vecs())
|
||||
.chain(self.epoch.vecs())
|
||||
.chain(self.amount_range.vecs())
|
||||
.chain(self._type.vecs())
|
||||
.chain(self.lt_amount.vecs())
|
||||
.chain(self.ge_amount.vecs())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<UTXOGroups<T>> for UTXOGroups<(GroupFilter, T)> {
|
||||
fn from(value: UTXOGroups<T>) -> Self {
|
||||
Self {
|
||||
all: (GroupFilter::All, value.all),
|
||||
term: ByTerm::from(value.term),
|
||||
max_age: ByMaxAge::from(value.max_age),
|
||||
min_age: ByMinAge::from(value.min_age),
|
||||
age_range: ByAgeRange::from(value.age_range),
|
||||
epoch: ByEpoch::from(value.epoch),
|
||||
amount_range: ByAmountRange::from(value.amount_range),
|
||||
lt_amount: ByLowerThanAmount::from(value.lt_amount),
|
||||
ge_amount: ByGreatEqualAmount::from(value.ge_amount),
|
||||
_type: BySpendableType::from(value._type),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
#![doc = include_str!("../README.md")]
|
||||
|
||||
mod enums;
|
||||
mod error;
|
||||
mod groups;
|
||||
mod structs;
|
||||
mod traits;
|
||||
mod utils;
|
||||
|
||||
pub use enums::*;
|
||||
pub use error::*;
|
||||
pub use groups::*;
|
||||
pub use structs::*;
|
||||
pub use traits::*;
|
||||
pub use utils::*;
|
||||
|
||||
@@ -162,7 +162,7 @@ impl fmt::Display for P2PKHBytes {
|
||||
.push_opcode(opcodes::all::OP_CHECKSIG)
|
||||
.into_script();
|
||||
let address = Address::from_script(&script, Network::Bitcoin).unwrap();
|
||||
write!(f, "{}", address)
|
||||
write!(f, "{address}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ impl fmt::Display for P2SHBytes {
|
||||
.push_opcode(opcodes::all::OP_EQUAL)
|
||||
.into_script();
|
||||
let address = Address::from_script(&script, Network::Bitcoin).unwrap();
|
||||
write!(f, "{}", address)
|
||||
write!(f, "{address}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ impl fmt::Display for P2WPKHBytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let script = Builder::new().push_int(0).push_slice(*self.0).into_script();
|
||||
let address = Address::from_script(&script, Network::Bitcoin).unwrap();
|
||||
write!(f, "{}", address)
|
||||
write!(f, "{address}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,7 +244,7 @@ impl fmt::Display for P2WSHBytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let script = Builder::new().push_int(0).push_slice(*self.0).into_script();
|
||||
let address = Address::from_script(&script, Network::Bitcoin).unwrap();
|
||||
write!(f, "{}", address)
|
||||
write!(f, "{address}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ impl fmt::Display for P2TRBytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let script = Builder::new().push_int(1).push_slice(*self.0).into_script();
|
||||
let address = Address::from_script(&script, Network::Bitcoin).unwrap();
|
||||
write!(f, "{}", address)
|
||||
write!(f, "{address}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,7 +296,7 @@ impl fmt::Display for P2ABytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let script = Builder::new().push_int(1).push_slice(*self.0).into_script();
|
||||
let address = Address::from_script(&script, Network::Bitcoin).unwrap();
|
||||
write!(f, "{}", address)
|
||||
write!(f, "{address}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
use byteview::ByteView;
|
||||
use zerocopy::{FromBytes, IntoBytes};
|
||||
|
||||
use crate::{Bitcoin, CheckedSub, Dollars, EmptyAddressData, Error, Result, Sats};
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct AddressData {
|
||||
pub sent: Sats,
|
||||
pub received: Sats,
|
||||
pub realized_cap: Dollars,
|
||||
pub outputs_len: u32,
|
||||
}
|
||||
|
||||
impl AddressData {
|
||||
pub fn amount(&self) -> Sats {
|
||||
(u64::from(self.received) - u64::from(self.sent)).into()
|
||||
}
|
||||
|
||||
pub fn realized_price(&self) -> Dollars {
|
||||
(self.realized_cap / Bitcoin::from(self.amount())).round_to_4_digits()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_0_sats(&self) -> bool {
|
||||
self.amount() == Sats::ZERO
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_0_utxos(&self) -> bool {
|
||||
self.outputs_len == 0
|
||||
}
|
||||
|
||||
pub fn receive(&mut self, amount: Sats, price: Option<Dollars>) {
|
||||
self.received += amount;
|
||||
self.outputs_len += 1;
|
||||
if let Some(price) = price {
|
||||
self.realized_cap += price * amount;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(&mut self, amount: Sats, previous_price: Option<Dollars>) -> Result<()> {
|
||||
if self.amount() < amount {
|
||||
return Err(Error::String("Previous_amount smaller than sent amount"));
|
||||
}
|
||||
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();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EmptyAddressData> for AddressData {
|
||||
fn from(value: EmptyAddressData) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
impl From<&EmptyAddressData> for AddressData {
|
||||
fn from(value: &EmptyAddressData) -> Self {
|
||||
Self {
|
||||
sent: value.transfered,
|
||||
received: value.transfered,
|
||||
realized_cap: Dollars::ZERO,
|
||||
outputs_len: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ByteView> for AddressData {
|
||||
fn from(value: ByteView) -> Self {
|
||||
Self {
|
||||
// MUST be same order as impl From<&AddressData> for ByteView
|
||||
sent: Sats::read_from_bytes(&value[..8]).unwrap(),
|
||||
received: Sats::read_from_bytes(&value[8..16]).unwrap(),
|
||||
realized_cap: Dollars::read_from_bytes(&value[16..24]).unwrap(),
|
||||
outputs_len: u32::read_from_bytes(&value[24..]).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<AddressData> for ByteView {
|
||||
fn from(value: AddressData) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
impl From<&AddressData> for ByteView {
|
||||
fn from(value: &AddressData) -> Self {
|
||||
Self::new(
|
||||
&[
|
||||
value.sent.as_bytes(),
|
||||
value.received.as_bytes(),
|
||||
value.realized_cap.as_bytes(),
|
||||
value.outputs_len.as_bytes(),
|
||||
]
|
||||
.concat(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
ops::{Add, Div, Mul},
|
||||
ops::{Add, AddAssign, Div, Mul},
|
||||
};
|
||||
|
||||
use serde::Serialize;
|
||||
@@ -20,6 +20,12 @@ impl Add for Bitcoin {
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for Bitcoin {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
*self = *self + rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul for Bitcoin {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: Self) -> Self::Output {
|
||||
|
||||
@@ -24,10 +24,28 @@ 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 {
|
||||
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;
|
||||
|
||||
let pow = 10.0_f64.powi(log_diff);
|
||||
|
||||
((v as f64 / pow).round() * pow) as i64
|
||||
} else {
|
||||
v
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Dollars> for Cents {
|
||||
|
||||
@@ -31,6 +31,10 @@ impl Date {
|
||||
pub fn day(&self) -> u8 {
|
||||
(self.0 % 1_00) as u8
|
||||
}
|
||||
|
||||
pub fn into_jiff(self) -> Date_ {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Date {
|
||||
|
||||
@@ -3,11 +3,14 @@ use std::{
|
||||
ops::{Add, Rem},
|
||||
};
|
||||
|
||||
use jiff::Span;
|
||||
use serde::Serialize;
|
||||
// use color_eyre::eyre::eyre;
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::{CheckedSub, Error, Printable};
|
||||
use crate::{
|
||||
CheckedSub, DecadeIndex, Error, FromCoarserIndex, MonthIndex, Printable, QuarterIndex,
|
||||
SemesterIndex, WeekIndex, YearIndex,
|
||||
};
|
||||
|
||||
use super::Date;
|
||||
|
||||
@@ -103,3 +106,135 @@ impl Printable for DateIndex {
|
||||
&["d", "date", "dateindex"]
|
||||
}
|
||||
}
|
||||
|
||||
impl FromCoarserIndex<WeekIndex> for DateIndex {
|
||||
fn min_from(coarser: WeekIndex) -> usize {
|
||||
let coarser = usize::from(coarser);
|
||||
if coarser == 0 {
|
||||
0
|
||||
} else if coarser == 1 {
|
||||
1
|
||||
} else {
|
||||
4 + (coarser - 2) * 7
|
||||
}
|
||||
}
|
||||
|
||||
fn max_from_(coarser: WeekIndex) -> usize {
|
||||
let coarser = usize::from(coarser);
|
||||
if coarser == 0 {
|
||||
0
|
||||
} else if coarser == 1 {
|
||||
3
|
||||
} else {
|
||||
3 + (coarser - 1) * 7
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromCoarserIndex<MonthIndex> for DateIndex {
|
||||
fn min_from(coarser: MonthIndex) -> usize {
|
||||
let coarser = u16::from(coarser);
|
||||
if coarser == 0 {
|
||||
0
|
||||
} else {
|
||||
let d = Date::new(2009, 1, 1)
|
||||
.into_jiff()
|
||||
.checked_add(Span::new().months(coarser))
|
||||
.unwrap();
|
||||
DateIndex::try_from(Date::from(d)).unwrap().into()
|
||||
}
|
||||
}
|
||||
|
||||
fn max_from_(coarser: MonthIndex) -> usize {
|
||||
let d = Date::new(2009, 1, 31)
|
||||
.into_jiff()
|
||||
.checked_add(Span::new().months(u16::from(coarser)))
|
||||
.unwrap();
|
||||
DateIndex::try_from(Date::from(d)).unwrap().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromCoarserIndex<QuarterIndex> for DateIndex {
|
||||
fn min_from(coarser: QuarterIndex) -> usize {
|
||||
let coarser = u16::from(coarser);
|
||||
if coarser == 0 {
|
||||
0
|
||||
} else {
|
||||
let d = Date::new(2009, 1, 1)
|
||||
.into_jiff()
|
||||
.checked_add(Span::new().months(3 * coarser))
|
||||
.unwrap();
|
||||
DateIndex::try_from(Date::from(d)).unwrap().into()
|
||||
}
|
||||
}
|
||||
|
||||
fn max_from_(coarser: QuarterIndex) -> usize {
|
||||
let d = Date::new(2009, 3, 31)
|
||||
.into_jiff()
|
||||
.checked_add(Span::new().months(3 * u16::from(coarser)))
|
||||
.unwrap();
|
||||
DateIndex::try_from(Date::from(d)).unwrap().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromCoarserIndex<SemesterIndex> for DateIndex {
|
||||
fn min_from(coarser: SemesterIndex) -> usize {
|
||||
let coarser = u16::from(coarser);
|
||||
if coarser == 0 {
|
||||
0
|
||||
} else {
|
||||
let d = Date::new(2009, 1, 1)
|
||||
.into_jiff()
|
||||
.checked_add(Span::new().months(6 * coarser))
|
||||
.unwrap();
|
||||
DateIndex::try_from(Date::from(d)).unwrap().into()
|
||||
}
|
||||
}
|
||||
|
||||
fn max_from_(coarser: SemesterIndex) -> usize {
|
||||
let d = Date::new(2009, 5, 31)
|
||||
.into_jiff()
|
||||
.checked_add(Span::new().months(1 + 6 * u16::from(coarser)))
|
||||
.unwrap();
|
||||
DateIndex::try_from(Date::from(d)).unwrap().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromCoarserIndex<YearIndex> for DateIndex {
|
||||
fn min_from(coarser: YearIndex) -> usize {
|
||||
let coarser = u16::from(coarser);
|
||||
if coarser == 0 {
|
||||
0
|
||||
} else {
|
||||
Self::try_from(Date::new(2009 + coarser, 1, 1))
|
||||
.unwrap()
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
fn max_from_(coarser: YearIndex) -> usize {
|
||||
Self::try_from(Date::new(2009 + u16::from(coarser), 12, 31))
|
||||
.unwrap()
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromCoarserIndex<DecadeIndex> for DateIndex {
|
||||
fn min_from(coarser: DecadeIndex) -> usize {
|
||||
let coarser = u16::from(coarser);
|
||||
if coarser == 0 {
|
||||
0
|
||||
} else {
|
||||
Self::try_from(Date::new(2000 + 10 * coarser, 1, 1))
|
||||
.unwrap()
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
fn max_from_(coarser: DecadeIndex) -> usize {
|
||||
let coarser = u16::from(coarser);
|
||||
Self::try_from(Date::new(2009 + (10 * coarser), 12, 31))
|
||||
.unwrap()
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use std::{fmt::Debug, ops::Add};
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
ops::{Add, AddAssign, Div},
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
@@ -31,6 +34,18 @@ impl From<u8> for DecadeIndex {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DecadeIndex> for u8 {
|
||||
fn from(value: DecadeIndex) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DecadeIndex> for u16 {
|
||||
fn from(value: DecadeIndex) -> Self {
|
||||
value.0 as u16
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for DecadeIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u8)
|
||||
@@ -51,6 +66,27 @@ impl Add<usize> for DecadeIndex {
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<DecadeIndex> for DecadeIndex {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self::from(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for DecadeIndex {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
*self = Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for DecadeIndex {
|
||||
type Output = Self;
|
||||
fn div(self, _: usize) -> Self::Output {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DateIndex> for DecadeIndex {
|
||||
fn from(value: DateIndex) -> Self {
|
||||
Self::from(Date::from(value))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user