Compare commits

...

56 Commits

Author SHA1 Message Date
nym21 e9c0121a18 release: v0.0.107 2025-09-13 18:27:45 +02:00
nym21 01aa425f81 global: chain + cointime datasets 2025-09-13 18:26:28 +02:00
nym21 38d5c7dff6 computer: add tx annualized volume + tx velocity + rename _in_usd/_in_btc to _usd/_btc 2025-09-13 00:29:34 +02:00
nym21 e3b4b9b618 computer: some cleanup 2025-09-12 12:07:04 +02:00
nym21 a5951c58f3 global: add sent volume 2025-09-12 12:00:03 +02:00
nym21 504d6eaa9f cargo: update 2025-09-11 22:53:16 +02:00
nym21 6253fa30ef global: more mining related datasets 2025-09-11 18:45:54 +02:00
nym21 47f7cef4f4 global: add hash related datasets 2025-09-11 01:02:29 +02:00
nym21 72bba06e71 global: add mining related datasets 2025-09-10 21:57:15 +02:00
nym21 9b92c5ce38 computer: convert vecs functions to iterators 2025-09-10 16:25:38 +02:00
nym21 dfa077a1c9 computer: simplify compute_all functions 2025-09-09 19:22:56 +02:00
nym21 18fb2e7d4d release: v0.0.106 2025-09-09 17:53:09 +02:00
nym21 a610fd53e2 global: add min max choppiness datasets + fixes 2025-09-09 17:52:45 +02:00
nym21 16abce1f2d release: v0.0.105 2025-09-08 20:16:38 +02:00
nym21 f3b42f34a6 dist: add config back to config.toml 2025-09-08 20:16:21 +02:00
nym21 6483d324de release: v0.0.104 2025-09-08 20:02:18 +02:00
nym21 5ab97050dd ci: udpate dist + release.yml 2025-09-08 20:01:51 +02:00
nym21 17eed70903 release: v0.0.103 2025-09-08 19:24:00 +02:00
nym21 88067c03b7 release: v0.0.102 2025-09-08 19:21:43 +02:00
nym21 7c1e5b913f cargo: update 2025-09-08 19:20:53 +02:00
nym21 0014235e91 global: add price volatility datasets 2025-09-08 18:24:22 +02:00
nym21 a39b7be1d1 release: v0.0.101 2025-09-07 21:55:56 +02:00
nym21 de98c5f706 global: fixes 2025-09-07 21:55:39 +02:00
nym21 10b496e845 release: v0.0.100 2025-09-07 17:14:10 +02:00
nym21 bbe7bf390d crates: upgrade rest 2025-09-07 17:13:57 +02:00
nym21 4777b3400a crates: upgrade seqdb 2025-09-07 17:13:01 +02:00
nym21 acaa70e944 release: v0.0.99 2025-09-07 17:01:58 +02:00
nym21 4049d694f7 global: snapshot + pools + fixes 2025-09-07 17:01:34 +02:00
nym21 e155a3dacf bitview: fix localstorage error 2025-09-06 15:41:16 +02:00
nym21 a224e4c4d8 release: v0.0.98 2025-09-05 14:50:46 +02:00
nym21 edaeda5424 release: v0.0.97 2025-09-05 14:47:35 +02:00
nym21 09d974913d computer: pools part 1 + fetcher: fix url + interface: more ddos protection 2025-09-05 14:47:11 +02:00
nym21 f82edb290a global: add datasets and charts 2025-09-05 10:00:29 +02:00
nym21 3d8b33ae94 release: v0.0.96 2025-09-03 18:21:17 +02:00
nym21 565ecbd436 cargo: update 2025-09-03 18:20:58 +02:00
nym21 3359dfcc29 global: snapshot 2025-09-03 18:17:25 +02:00
nym21 1c2afd14dd global: fixes of Parser::new 2025-09-01 20:34:27 +02:00
nym21 fe5343c1d6 global: tiny snapshot 2025-09-01 20:21:51 +02:00
nym21 08cfefc02a zed: add project settings to improve search 2025-08-31 17:05:28 +02:00
nym21 f6d9332c48 bitview: fix screenshot in ios 2025-08-31 16:17:50 +02:00
nym21 cc6913c854 bitview: initial history support 2025-08-31 14:50:36 +02:00
nym21 8c75fbd0a4 server: fix urls in readme 2025-08-31 12:21:11 +02:00
nym21 0de6d62409 bitview: simplify options tree 2025-08-31 11:07:54 +02:00
nym21 5ba7ce5b7c bitview: small fixes 2025-08-30 12:11:15 +02:00
nym21 e106d30852 global: snapshot 2025-08-29 22:49:26 +02:00
nym21 30affc884b release: v0.0.95 2025-08-28 12:43:49 +02:00
nym21 745717ea49 global: added unrealized relative datasets 2025-08-28 12:43:28 +02:00
nym21 4efd98b758 release: v0.0.94 2025-08-28 00:31:36 +02:00
nym21 36640e3710 global: added datasets 2025-08-28 00:31:14 +02:00
nym21 311c4fd29d website: rename default to bitview 2025-08-27 11:52:22 +02:00
nym21 f50374f983 release: v0.0.93 2025-08-26 23:34:57 +02:00
nym21 82ceb7f021 cargo: update 2025-08-26 23:34:38 +02:00
nym21 0aba3bc1d8 release: v0.0.92 2025-08-26 22:27:16 +02:00
nym21 f6c984ff3c website: add screenshot feature 2025-08-26 22:26:55 +02:00
nym21 4091ab6b6c release: v0.0.91 2025-08-26 08:31:30 +02:00
nym21 fb9fd5b51a global: add datasets and charts + fixes 2025-08-26 08:31:08 +02:00
238 changed files with 17883 additions and 15763 deletions
+1 -1
View File
@@ -64,7 +64,7 @@ jobs:
# we specify bash to get pipefail; it guards against the `curl` command
# failing. otherwise `sh` won't catch that `curl` returned non-0
shell: bash
run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.29.0/cargo-dist-installer.sh | sh"
run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.30.0/cargo-dist-installer.sh | sh"
- name: Cache dist
uses: actions/upload-artifact@v4
with:
+2 -5
View File
@@ -4,7 +4,8 @@
# Builds
target
websites/dist
vecid-to-indexes.js
bridge/
/ids.txt
# Copies
*\ copy*
@@ -12,10 +13,6 @@ vecid-to-indexes.js
# Ignored
_*
# Editors
.vscode
.zed
# Logs
.log
+20
View File
@@ -0,0 +1,20 @@
{
"file_scan_exclusions": [
// default
"**/.git",
"**/.svn",
"**/.hg",
"**/.jj",
"**/CVS",
"**/.DS_Store",
"**/Thumbs.db",
"**/.classpath",
"**/.settings",
// custom
"**/lean-qr/*/index.mjs",
"uFuzzy.mjs",
"lightweight-charts.standalone.production.mjs",
"**/modern-screenshot/*/index.mjs",
"**/solidjs-signals/*/dist/prod.js"
]
}
Generated
+605 -300
View File
File diff suppressed because it is too large Load Diff
+43 -20
View File
@@ -4,16 +4,25 @@ 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.90"
package.version = "0.0.107"
package.homepage = "https://bitcoinresearchkit.org"
package.repository = "https://github.com/bitcoinresearchkit/brk"
package.readme = "README.md"
package.rust-version = "1.89"
[profile.dev]
lto = "thin"
debug = true
codegen-units = 1
opt-level = 3
overflow-checks = true
[profile.release]
lto = "fat"
codegen-units = 1
panic = "abort"
strip = true
overflow-checks = false
[profile.profiling]
inherits = "release"
@@ -22,30 +31,44 @@ debug = true
[profile.dist]
inherits = "release"
[profile.clippy]
inherits = "dev"
lto = "off"
codegen-units = 256
opt-level = 0
incremental = true
debug = false
overflow-checks = false
panic = "abort"
debug-assertions = false
[workspace.dependencies]
allocative = { version = "0.3.4", features = ["parking_lot"] }
allocative_derive = "0.3.3"
axum = "0.8.4"
bitcoin = { version = "0.32.7", features = ["serde"] }
bitcoincore-rpc = "0.19.0"
brk_bundler = { version = "0.0.90", path = "crates/brk_bundler" }
brk_cli = { version = "0.0.90", path = "crates/brk_cli" }
brk_computer = { version = "0.0.90", path = "crates/brk_computer" }
brk_error = { version = "0.0.90", path = "crates/brk_error" }
brk_fetcher = { version = "0.0.90", path = "crates/brk_fetcher" }
brk_indexer = { version = "0.0.90", path = "crates/brk_indexer" }
brk_interface = { version = "0.0.90", path = "crates/brk_interface" }
brk_logger = { version = "0.0.90", path = "crates/brk_logger" }
brk_mcp = { version = "0.0.90", path = "crates/brk_mcp" }
brk_parser = { version = "0.0.90", path = "crates/brk_parser" }
brk_server = { version = "0.0.90", path = "crates/brk_server" }
brk_store = { version = "0.0.90", path = "crates/brk_store" }
brk_structs = { version = "0.0.90", path = "crates/brk_structs" }
brk_bundler = { version = "0.0.107", path = "crates/brk_bundler" }
brk_cli = { version = "0.0.107", path = "crates/brk_cli" }
brk_computer = { version = "0.0.107", path = "crates/brk_computer" }
brk_error = { version = "0.0.107", path = "crates/brk_error" }
brk_fetcher = { version = "0.0.107", path = "crates/brk_fetcher" }
brk_indexer = { version = "0.0.107", path = "crates/brk_indexer" }
brk_interface = { version = "0.0.107", path = "crates/brk_interface" }
brk_logger = { version = "0.0.107", path = "crates/brk_logger" }
brk_mcp = { version = "0.0.107", path = "crates/brk_mcp" }
brk_parser = { version = "0.0.107", path = "crates/brk_parser" }
brk_server = { version = "0.0.107", path = "crates/brk_server" }
brk_store = { version = "0.0.107", path = "crates/brk_store" }
brk_structs = { version = "0.0.107", path = "crates/brk_structs" }
byteview = "=0.6.1"
derive_deref = "1.1.1"
fjall = "2.11.2"
jiff = "0.2.15"
log = "0.4.27"
minreq = { version = "2.14.0", features = ["https", "serde_json"] }
log = "0.4.28"
minreq = { version = "2.14.1", features = ["https", "serde_json"] }
parking_lot = "0.12.4"
quick_cache = "0.6.16"
rayon = "1.11.0"
serde = "1.0.219"
serde_bytes = "0.11.17"
@@ -53,9 +76,9 @@ serde_derive = "1.0.219"
serde_json = { version = "1.0.143", features = ["float_roundtrip"] }
tokio = { version = "1.47.1", features = ["rt-multi-thread"] }
# vecdb = { path = "../seqdb/crates/vecdb", features = ["derive"]}
vecdb = { version = "0.2.4", features = ["derive"]}
zerocopy = "0.8.26"
zerocopy-derive = "0.8.26"
vecdb = { version = "0.2.14", features = ["derive"]}
zerocopy = "0.8.27"
zerocopy-derive = "0.8.27"
[workspace.metadata.release]
shared-version = true
@@ -64,7 +87,7 @@ pre-release-commit-message = "release: v{{version}}"
tag-message = "release: v{{version}}"
[workspace.metadata.dist]
cargo-dist-version = "0.29.0"
cargo-dist-version = "0.30.0"
ci = "github"
allow-dirty = ["ci"]
installers = []
+4 -9
View File
@@ -17,7 +17,7 @@
<a href="https://deps.rs/crate/brk">
<img src="https://deps.rs/crate/brk/latest/status.svg" alt="Dependency status">
</a>
<a href="https://discord.gg/HaR3wpH3nr">
<a href="https://discord.gg/WACpShCB7M">
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
</a>
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
@@ -31,10 +31,9 @@ In other words it's an alternative to [Glassnode](https://glassnode.com), [mempo
The toolkit can be used in various ways to accommodate as many needs as possible:
- **[Website](https://bitcoinresearchkit.org)** \
- **[Website](https://bitview.space)** \
Everyone is welcome to visit the official instance and showcase of the suite's capabilities. \
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: [brekit.org](https://brekit.org) // [kibo.money](https://kibo.money) // [satonomics.xyz](https://satonomics.xyz)
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.
- **[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 ![Datasets variant count](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fbitcoinresearchkit.org%2Fapi%2Fvecs%2Fvec-count&query=%24&style=flat&label=%20&color=white) dataset variants at their disposal. \
Just like the website, it's entirely free, with no authentication or rate-limiting.
@@ -62,7 +61,7 @@ If you'd like to have your own instance hosted for you please contact [hosting@b
- Updates delivered at your convenience
- Direct communication for feature requests and support
- Bitcoin Core or Knots with desired version
- Optional subdomains: `*.bitcoinresearchkit.org`, `*.brekit.org`, `*.kibo.money` and `*.satonomics.xyz`
- Optional subdomains
- Logo featured in the Readme if desired
Pricing: `0.01 BTC / month` *or* `0.1 BTC / year`
@@ -93,7 +92,3 @@ Heartfelt thanks go out to every donor on [Nostr](https://primal.net/p/npub1jagm
## Donate
[`bc1q09 8zsm89 m7kgyz e338vf ejhpdt 92ua9p 3peuve`](bitcoin:bc1q098zsm89m7kgyze338vfejhpdt92ua9p3peuve)
[`lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkxmmww3jkuar8d35kgetj8yuq363hv4`](lightning:lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkxmmww3jkuar8d35kgetj8yuq363hv4)
[Geyser Fund](https://geyser.fund/project/brk)
+3 -16
View File
@@ -10,30 +10,19 @@
- pull latest version and notify is out of date
- _computer_
- **add rollback of states (in stateful)**
- remove configurable format (raw/compressed) and chose sane ones instead
- linear reads: compressed (height/date/... + txindex_to_height + txindex_to_version + ...)
- random reads: raw (outputindex_to_value + ...)
- add prices paid by percentile (percentile cost basis) back
- add costs basis by percentile (percentile cost basis) back
- add support for per index computation
- fix min feerate which is always ZERO due to coinbase transaction
- fix min fee_rate 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
@@ -75,11 +64,9 @@
- miners
- maybe xpubs
- charts
- improve some names and colors
- remove `sum` series when it's a duplicate of the `base` (in subsidy for example)
- improve names and colors
- 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
+7 -7
View File
@@ -64,7 +64,7 @@ brk = { version = "0.0.88", features = ["parser", "indexer", "computer"] }
use brk::{parser, indexer, computer};
// Core data pipeline only
let parser = parser::Parser::new(blocks_dir, output_dir, rpc);
let parser = parser::Parser::new(blocks_dir, Some(output_dir), rpc);
let mut indexer = indexer::Indexer::forced_import(output_dir)?;
let mut computer = computer::Computer::forced_import(output_dir, &indexer, None)?;
```
@@ -81,7 +81,7 @@ use brk::{structs, parser};
// Just parsing and types
let height = structs::Height::new(800_000);
let parser = parser::Parser::new(blocks_dir, output_dir, rpc);
let parser = parser::Parser::new(blocks_dir, Some(output_dir), rpc);
```
## Feature Flags
@@ -113,7 +113,7 @@ use brk::*;
// Full data pipeline setup
let config = cli::Config::load()?;
let rpc = /* Bitcoin Core RPC client */;
let parser = parser::Parser::new(config.blocks_dir, config.output_dir, rpc);
let parser = parser::Parser::new(config.blocks_dir, Some(config.output_dir), rpc);
let mut indexer = indexer::Indexer::forced_import(&config.output_dir)?;
let mut computer = computer::Computer::forced_import(&config.output_dir, &indexer, None)?;
let interface = interface::Interface::build(&indexer, &computer);
@@ -152,15 +152,15 @@ use brk::{structs, parser, error};
// Custom application with BRK components
fn analyze_blocks() -> error::Result<()> {
let parser = parser::Parser::new(blocks_dir, output_dir, rpc);
let parser = parser::Parser::new(blocks_dir, Some(output_dir), rpc);
parser.parse(None, None)
.iter()
.take(1000) // First 1000 blocks
.for_each(|(height, block, hash)| {
println!("Block {}: {} transactions", height, block.txdata.len());
});
Ok(())
}
```
@@ -194,4 +194,4 @@ For specific dependency information, see individual crate READMEs.
---
*This README was generated by Claude Code*
*This README was generated by Claude Code*
+1 -1
View File
@@ -12,7 +12,7 @@ build = "build.rs"
[dependencies]
log = { workspace = true }
notify = "8.2.0"
brk_rolldown = "0.1.4"
brk_rolldown = "0.1.5"
# brk_rolldown = { path = "../../../rolldown/crates/rolldown"}
sugar_path = "1.2.0"
tokio = { workspace = true }
+3 -1
View File
@@ -35,7 +35,9 @@ pub async fn bundle(websites_path: &Path, source_folder: &str, watch: bool) -> i
..Default::default()
});
bundler.write().await.unwrap();
if let Err(error) = bundler.write().await {
error!("{error:?}");
}
let absolute_source_index_path = source_path.join("index.html").absolutize();
let absolute_source_index_path_clone = absolute_source_index_path.clone();
+3 -3
View File
@@ -20,15 +20,15 @@ brk_logger = { workspace = true }
brk_parser = { workspace = true }
brk_server = { workspace = true }
vecdb = { workspace = true }
clap = { version = "4.5.45", features = ["string"] }
clap_derive = "4.5.45"
clap = { version = "4.5.47", features = ["string"] }
clap_derive = "4.5.47"
color-eyre = "0.6.5"
log = { workspace = true }
minreq = { workspace = true }
serde = { workspace = true }
tokio = { workspace = true }
toml = "0.9.5"
zip = { version = "4.5.0", default-features = false, features = ["deflate"] }
zip = { version = "5.1.1", default-features = false, features = ["deflate"] }
[[bin]]
name = "brk"
+98 -55
View File
@@ -1,19 +1,20 @@
use std::{fs, io, path::Path};
use brk_computer::pools;
use brk_interface::{Index, Interface};
use brk_server::VERSION;
use crate::website::Website;
const SCRIPTS: &str = "scripts";
const BRIDGE_PATH: &str = "scripts/bridge";
#[allow(clippy::upper_case_acronyms)]
pub trait Bridge {
fn generate_bridge_file(&self, website: Website, websites_path: &Path) -> io::Result<()>;
fn generate_bridge_files(&self, website: Website, websites_path: &Path) -> io::Result<()>;
}
impl Bridge for Interface<'static> {
fn generate_bridge_file(&self, website: Website, websites_path: &Path) -> io::Result<()> {
fn generate_bridge_files(&self, website: Website, websites_path: &Path) -> io::Result<()> {
if website.is_none() {
return Ok(());
}
@@ -24,88 +25,130 @@ impl Bridge for Interface<'static> {
return Ok(());
}
let path = path.join(SCRIPTS);
let path = path.join(BRIDGE_PATH);
fs::create_dir_all(&path)?;
let path = path.join(Path::new("vecid-to-indexes.js"));
generate_vecs_file(self, &path)?;
generate_pools_file(&path)
}
}
let indexes = Index::all();
fn generate_pools_file(parent: &Path) -> io::Result<()> {
let path = parent.join(Path::new("pools.js"));
let mut contents = format!(
"//
let pools = pools();
let mut contents = "//
// File auto-generated, any modifications will be overwritten
//
"
.to_string();
contents += "
/** @typedef {ReturnType<typeof createPools>} Pools */
/** @typedef {keyof Pools} Pool */
export function createPools() {
return /** @type {const} */ ({
";
let mut sorted_pools: Vec<_> = pools.iter().collect();
sorted_pools.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase()));
contents += &sorted_pools
.iter()
.map(|pool| {
let id = pool.serialized_id();
format!(" {id}: \"{}\",", pool.name)
})
.collect::<Vec<_>>()
.join("\n");
contents += "\n });\n}\n";
fs::write(path, contents)
}
fn generate_vecs_file(interface: &Interface<'static>, parent: &Path) -> io::Result<()> {
let path = parent.join(Path::new("vecs.js"));
let indexes = Index::all();
let mut contents = format!(
"//
// File auto-generated, any modifications will be overwritten
//
export const VERSION = \"v{VERSION}\";
"
);
);
contents += &indexes
contents += &indexes
.iter()
.enumerate()
.map(|(i_of_i, i)| {
// let lowered = i.to_string().to_lowercase();
format!("/** @typedef {{{i_of_i}}} {i} */",)
})
.collect::<Vec<_>>()
.join("\n");
contents += &format!(
"\n\n/** @typedef {{{}}} Index */\n",
indexes
.iter()
.enumerate()
.map(|(i_of_i, i)| {
// let lowered = i.to_string().to_lowercase();
format!("/** @typedef {{{i_of_i}}} {i} */",)
})
.map(|i| i.to_string())
.collect::<Vec<_>>()
.join("\n");
.join(" | ")
);
contents += &format!(
"\n\n/** @typedef {{{}}} Index */\n",
indexes
.iter()
.map(|i| i.to_string())
.collect::<Vec<_>>()
.join(" | ")
);
contents += "
contents += "
/** @typedef {ReturnType<typeof createIndexes>} Indexes */
export function createIndexes() {
return {
return {
";
contents += &indexes
.iter()
.enumerate()
.map(|(i_of_i, i)| {
let lowered = i.to_string().to_lowercase();
format!(" {lowered}: /** @satisfies {{{i}}} */ ({i_of_i}),",)
})
.collect::<Vec<_>>()
.join("\n");
contents += &indexes
.iter()
.enumerate()
.map(|(i_of_i, i)| {
let lowered = i.to_string().to_lowercase();
format!(" {lowered}: /** @satisfies {{{i}}} */ ({i_of_i}),",)
})
.collect::<Vec<_>>()
.join("\n");
contents += " };\n}\n";
contents += " };\n}\n";
contents += "
contents += "
/** @typedef {ReturnType<typeof createVecIdToIndexes>} VecIdToIndexes
/** @typedef {keyof VecIdToIndexes} VecId */
/**
* @returns {Record<any, number[]>}
*/
* @returns {Record<any, number[]>}
*/
export function createVecIdToIndexes() {
return {
return {
";
self.id_to_index_to_vec()
.iter()
.for_each(|(id, index_to_vec)| {
let indexes = index_to_vec
.keys()
.map(|i| (*i as u8).to_string())
// .map(|i| i.to_string())
.collect::<Vec<_>>()
.join(", ");
interface
.id_to_index_to_vec()
.iter()
.for_each(|(id, index_to_vec)| {
let indexes = index_to_vec
.keys()
.map(|i| (*i as u8).to_string())
// .map(|i| i.to_string())
.collect::<Vec<_>>()
.join(", ");
contents += &format!(" \"{id}\": [{indexes}],\n");
});
contents += &format!(" \"{id}\": [{indexes}],\n");
});
contents += " };\n}\n";
contents += " };\n}\n";
fs::write(path, contents)
}
fs::write(path, contents)
}
+1 -2
View File
@@ -6,7 +6,6 @@ use std::{
use bitcoincore_rpc::{self, Auth, Client};
use brk_fetcher::Fetcher;
use clap::Parser;
use clap_derive::Parser;
use color_eyre::eyre::eyre;
use serde::{Deserialize, Deserializer, Serialize};
@@ -284,7 +283,7 @@ Finally, you can run the program with '-h' for help."
}
pub fn website(&self) -> Website {
self.website.unwrap_or(Website::Default)
self.website.unwrap_or(Website::Bitview)
}
pub fn fetch(&self) -> bool {
+5 -2
View File
@@ -13,6 +13,7 @@ use brk_bundler::bundle;
use brk_computer::Computer;
use brk_indexer::Indexer;
use brk_interface::Interface;
use brk_parser::Parser;
use brk_server::{Server, VERSION};
use log::info;
use vecdb::Exit;
@@ -46,7 +47,7 @@ pub fn run() -> color_eyre::Result<()> {
let exit = Exit::new();
exit.set_ctrlc_handler();
let parser = brk_parser::Parser::new(config.blocksdir(), config.brkdir(), rpc);
let parser = Parser::new(config.blocksdir(), Some(config.brkdir()), rpc);
let mut indexer = Indexer::forced_import(&config.brkdir())?;
@@ -106,7 +107,7 @@ pub fn run() -> color_eyre::Result<()> {
downloaded_websites_path
};
interface.generate_bridge_file(website, websites_path.as_path())?;
interface.generate_bridge_files(website, websites_path.as_path())?;
Some(bundle(&websites_path, website.to_folder_name(), true).await?)
} else {
@@ -134,6 +135,8 @@ pub fn run() -> color_eyre::Result<()> {
let starting_indexes =
indexer.index(&parser, rpc, &exit, config.check_collisions()).unwrap();
// dbg!(&starting_indexes);
computer.compute(&indexer, starting_indexes, &exit).unwrap();
info!("Waiting for new blocks...");
+3 -2
View File
@@ -2,9 +2,10 @@ use clap_derive::ValueEnum;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize, ValueEnum)]
#[serde(rename_all = "lowercase")]
pub enum Website {
None,
Default,
Bitview,
Custom,
}
@@ -20,7 +21,7 @@ impl Website {
pub fn to_folder_name(self) -> &'static str {
match self {
Self::Custom => "custom",
Self::Default => "default",
Self::Bitview => "bitview",
Self::None => unreachable!(),
}
}
+7
View File
@@ -10,6 +10,8 @@ rust-version.workspace = true
build = "build.rs"
[dependencies]
allocative = { workspace = true }
allocative_derive = { workspace = true }
bitcoin = { workspace = true }
bitcoincore-rpc = { workspace = true }
brk_structs = { workspace = true }
@@ -17,13 +19,18 @@ brk_error = { workspace = true }
brk_fetcher = { workspace = true }
brk_indexer = { workspace = true }
brk_logger = { workspace = true }
brk_store = { workspace = true }
brk_parser = { workspace = true }
vecdb = { workspace = true }
derive_deref = { workspace = true }
inferno = "0.12.3"
jiff = { workspace = true }
log = { workspace = true }
num_enum = "0.7.4"
pco = "0.4.6"
rayon = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
zerocopy = { workspace = true }
zerocopy-derive = { workspace = true }
+5 -1
View File
@@ -34,7 +34,11 @@ pub fn main() -> Result<()> {
let outputs_dir = Path::new(&std::env::var("HOME").unwrap()).join(".brk");
// let outputs_dir = Path::new("../../_outputs");
let parser = Parser::new(bitcoin_dir.join("blocks"), outputs_dir.to_path_buf(), rpc);
let parser = Parser::new(
bitcoin_dir.join("blocks"),
Some(outputs_dir.to_path_buf()),
rpc,
);
let mut indexer = Indexer::forced_import(&outputs_dir)?;
+125
View File
@@ -0,0 +1,125 @@
use std::{collections::BTreeMap, path::Path, thread};
use brk_computer::{Computer, pools};
use brk_error::Result;
use brk_fetcher::Fetcher;
use brk_indexer::Indexer;
use brk_structs::{AddressBytes, OutputIndex, OutputType};
use vecdb::{AnyIterableVec, Exit, VecIterator};
fn main() -> Result<()> {
brk_logger::init(Some(Path::new(".log")))?;
let exit = Exit::new();
exit.set_ctrlc_handler();
thread::Builder::new()
.stack_size(256 * 1024 * 1024)
.spawn(move || -> Result<()> {
let outputs_dir = Path::new(&std::env::var("HOME").unwrap()).join(".brk");
let indexer = Indexer::forced_import(&outputs_dir)?;
let fetcher = Fetcher::import(true, None)?;
let computer = Computer::forced_import(&outputs_dir, &indexer, Some(fetcher))?;
let pools = pools();
let mut res: BTreeMap<&'static str, usize> = BTreeMap::default();
let vecs = indexer.vecs;
let stores = indexer.stores;
let mut height_to_first_txindex_iter = vecs.height_to_first_txindex.iter();
let mut txindex_to_first_outputindex_iter = vecs.txindex_to_first_outputindex.iter();
let mut txindex_to_output_count_iter = computer.indexes.txindex_to_output_count.iter();
let mut outputindex_to_outputtype_iter = vecs.outputindex_to_outputtype.iter();
let mut outputindex_to_typeindex_iter = vecs.outputindex_to_typeindex.iter();
let mut p2pk65addressindex_to_p2pk65bytes_iter =
vecs.p2pk65addressindex_to_p2pk65bytes.iter();
let mut p2pk33addressindex_to_p2pk33bytes_iter =
vecs.p2pk33addressindex_to_p2pk33bytes.iter();
let mut p2pkhaddressindex_to_p2pkhbytes_iter =
vecs.p2pkhaddressindex_to_p2pkhbytes.iter();
let mut p2shaddressindex_to_p2shbytes_iter = vecs.p2shaddressindex_to_p2shbytes.iter();
let mut p2wpkhaddressindex_to_p2wpkhbytes_iter =
vecs.p2wpkhaddressindex_to_p2wpkhbytes.iter();
let mut p2wshaddressindex_to_p2wshbytes_iter =
vecs.p2wshaddressindex_to_p2wshbytes.iter();
let mut p2traddressindex_to_p2trbytes_iter = vecs.p2traddressindex_to_p2trbytes.iter();
let mut p2aaddressindex_to_p2abytes_iter = vecs.p2aaddressindex_to_p2abytes.iter();
let unknown = pools.get_unknown();
stores
.height_to_coinbase_tag
.iter()
.for_each(|(height, coinbase_tag)| {
let txindex = height_to_first_txindex_iter.unwrap_get_inner(height);
let outputindex = txindex_to_first_outputindex_iter.unwrap_get_inner(txindex);
let outputcount = txindex_to_output_count_iter.unwrap_get_inner(txindex);
let pool = (*outputindex..(*outputindex + *outputcount))
.map(OutputIndex::from)
.find_map(|outputindex| {
let outputtype =
outputindex_to_outputtype_iter.unwrap_get_inner(outputindex);
let typeindex =
outputindex_to_typeindex_iter.unwrap_get_inner(outputindex);
let address = match outputtype {
OutputType::P2PK65 => Some(AddressBytes::from(
p2pk65addressindex_to_p2pk65bytes_iter
.unwrap_get_inner(typeindex.into()),
)),
OutputType::P2PK33 => Some(AddressBytes::from(
p2pk33addressindex_to_p2pk33bytes_iter
.unwrap_get_inner(typeindex.into()),
)),
OutputType::P2PKH => Some(AddressBytes::from(
p2pkhaddressindex_to_p2pkhbytes_iter
.unwrap_get_inner(typeindex.into()),
)),
OutputType::P2SH => Some(AddressBytes::from(
p2shaddressindex_to_p2shbytes_iter
.unwrap_get_inner(typeindex.into()),
)),
OutputType::P2WPKH => Some(AddressBytes::from(
p2wpkhaddressindex_to_p2wpkhbytes_iter
.unwrap_get_inner(typeindex.into()),
)),
OutputType::P2WSH => Some(AddressBytes::from(
p2wshaddressindex_to_p2wshbytes_iter
.unwrap_get_inner(typeindex.into()),
)),
OutputType::P2TR => Some(AddressBytes::from(
p2traddressindex_to_p2trbytes_iter
.unwrap_get_inner(typeindex.into()),
)),
OutputType::P2A => Some(AddressBytes::from(
p2aaddressindex_to_p2abytes_iter
.unwrap_get_inner(typeindex.into()),
)),
_ => None,
};
address
.and_then(|address| pools.find_from_address(&address.to_string()))
})
.or_else(|| pools.find_from_coinbase_tag(&coinbase_tag))
.unwrap_or(unknown);
*res.entry(pool.name).or_default() += 1;
});
let mut v = res.into_iter().map(|(k, v)| (v, k)).collect::<Vec<_>>();
v.sort_unstable();
println!("{:#?}", v);
println!("{:#?}", v.len());
Ok(())
})?
.join()
.unwrap()
}
-264
View File
@@ -1,264 +0,0 @@
use std::path::Path;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_structs::{
CheckedSub, DifficultyEpoch, HalvingEpoch, Height, StoredU32, StoredU64, Timestamp, Version,
Weight,
};
use vecdb::{AnyCollectableVec, Database, EagerVec, Exit, PAGE_SIZE, VecIterator};
use crate::grouped::Source;
use super::{
Indexes,
grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, VecBuilderOptions},
indexes,
};
const VERSION: Version = Version::ZERO;
#[derive(Clone)]
pub struct Vecs {
db: Database,
pub height_to_interval: EagerVec<Height, Timestamp>,
pub height_to_vbytes: EagerVec<Height, StoredU64>,
pub difficultyepoch_to_timestamp: EagerVec<DifficultyEpoch, Timestamp>,
pub halvingepoch_to_timestamp: EagerVec<HalvingEpoch, Timestamp>,
pub timeindexes_to_timestamp: ComputedVecsFromDateIndex<Timestamp>,
pub indexes_to_block_count: ComputedVecsFromHeight<StoredU32>,
pub indexes_to_block_interval: ComputedVecsFromHeight<Timestamp>,
pub indexes_to_block_size: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_block_vbytes: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_block_weight: ComputedVecsFromHeight<Weight>,
}
impl Vecs {
pub fn forced_import(parent: &Path, version: Version, indexes: &indexes::Vecs) -> Result<Self> {
let db = Database::open(&parent.join("blocks"))?;
db.set_min_len(PAGE_SIZE * 1_000_000)?;
Ok(Self {
height_to_interval: EagerVec::forced_import_compressed(
&db,
"interval",
version + VERSION + Version::ZERO,
)?,
timeindexes_to_timestamp: ComputedVecsFromDateIndex::forced_import(
&db,
"timestamp",
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
VecBuilderOptions::default().add_first(),
)?,
indexes_to_block_interval: ComputedVecsFromHeight::forced_import(
&db,
"block_interval",
Source::None,
version + VERSION + Version::ZERO,
indexes,
VecBuilderOptions::default()
.add_percentiles()
.add_minmax()
.add_average(),
)?,
indexes_to_block_count: ComputedVecsFromHeight::forced_import(
&db,
"block_count",
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
)?,
indexes_to_block_weight: ComputedVecsFromHeight::forced_import(
&db,
"block_weight",
Source::None,
version + VERSION + Version::ZERO,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
)?,
indexes_to_block_size: ComputedVecsFromHeight::forced_import(
&db,
"block_size",
Source::None,
version + VERSION + Version::ZERO,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
)?,
height_to_vbytes: EagerVec::forced_import_compressed(
&db,
"vbytes",
version + VERSION + Version::ZERO,
)?,
indexes_to_block_vbytes: ComputedVecsFromHeight::forced_import(
&db,
"block_vbytes",
Source::None,
version + VERSION + Version::ZERO,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
)?,
difficultyepoch_to_timestamp: EagerVec::forced_import_compressed(
&db,
"timestamp",
version + VERSION + Version::ZERO,
)?,
halvingepoch_to_timestamp: EagerVec::forced_import_compressed(
&db,
"timestamp",
version + VERSION + Version::ZERO,
)?,
db,
})
}
pub fn compute(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.compute_(indexer, indexes, starting_indexes, exit)?;
self.db.flush_then_punch()?;
Ok(())
}
fn compute_(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.timeindexes_to_timestamp.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, indexes, starting_indexes, exit| {
vec.compute_transform(
starting_indexes.dateindex,
&indexes.dateindex_to_date,
|(di, d, ..)| (di, Timestamp::from(d)),
exit,
)?;
Ok(())
},
)?;
self.indexes_to_block_count.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|v, indexer, _, starting_indexes, exit| {
v.compute_range(
starting_indexes.height,
&indexer.vecs.height_to_weight,
|h| (h, StoredU32::from(1_u32)),
exit,
)?;
Ok(())
},
)?;
let mut height_to_timestamp_iter = indexer.vecs.height_to_timestamp.iter();
self.height_to_interval.compute_transform(
starting_indexes.height,
&indexer.vecs.height_to_timestamp,
|(height, timestamp, ..)| {
let interval = height.decremented().map_or(Timestamp::ZERO, |prev_h| {
let prev_timestamp = height_to_timestamp_iter.unwrap_get_inner(prev_h);
timestamp
.checked_sub(prev_timestamp)
.unwrap_or(Timestamp::ZERO)
});
(height, interval)
},
exit,
)?;
self.indexes_to_block_interval.compute_rest(
indexes,
starting_indexes,
exit,
Some(&self.height_to_interval),
)?;
self.indexes_to_block_weight.compute_rest(
indexes,
starting_indexes,
exit,
Some(&indexer.vecs.height_to_weight),
)?;
self.indexes_to_block_size.compute_rest(
indexes,
starting_indexes,
exit,
Some(&indexer.vecs.height_to_total_size),
)?;
self.height_to_vbytes.compute_transform(
starting_indexes.height,
&indexer.vecs.height_to_weight,
|(h, w, ..)| {
(
h,
StoredU64::from(bitcoin::Weight::from(w).to_vbytes_floor()),
)
},
exit,
)?;
self.indexes_to_block_vbytes.compute_rest(
indexes,
starting_indexes,
exit,
Some(&self.height_to_vbytes),
)?;
let mut height_to_timestamp_iter = indexer.vecs.height_to_timestamp.iter();
self.difficultyepoch_to_timestamp.compute_transform(
starting_indexes.difficultyepoch,
&indexes.difficultyepoch_to_first_height,
|(i, h, ..)| (i, height_to_timestamp_iter.unwrap_get_inner(h)),
exit,
)?;
self.halvingepoch_to_timestamp.compute_transform(
starting_indexes.halvingepoch,
&indexes.halvingepoch_to_first_height,
|(i, h, ..)| (i, height_to_timestamp_iter.unwrap_get_inner(h)),
exit,
)?;
Ok(())
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
[
vec![
&self.height_to_interval as &dyn AnyCollectableVec,
&self.height_to_vbytes,
&self.difficultyepoch_to_timestamp,
&self.halvingepoch_to_timestamp,
],
self.timeindexes_to_timestamp.vecs(),
self.indexes_to_block_count.vecs(),
self.indexes_to_block_interval.vecs(),
self.indexes_to_block_size.vecs(),
self.indexes_to_block_vbytes.vecs(),
self.indexes_to_block_weight.vecs(),
]
.into_iter()
.flatten()
.collect::<Vec<_>>()
}
}
File diff suppressed because it is too large Load Diff
+229 -199
View File
@@ -1,21 +1,20 @@
use std::path::Path;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_structs::{Bitcoin, CheckedSub, Dollars, StoredF64, Version};
use brk_structs::{Bitcoin, CheckedSub, Dollars, StoredF32, StoredF64, Version};
use vecdb::{AnyCollectableVec, Database, Exit, PAGE_SIZE, VecIterator};
use crate::grouped::ComputedVecsFromDateIndex;
use super::{
Indexes,
Indexes, chain,
grouped::{
ComputedRatioVecsFromDateIndex, ComputedValueVecsFromHeight, ComputedVecsFromHeight,
Source, VecBuilderOptions,
},
indexes, price, stateful, transactions,
indexes, price, stateful,
};
const VERSION: Version = Version::ZERO;
#[derive(Clone)]
pub struct Vecs {
db: Database,
@@ -43,27 +42,32 @@ pub struct Vecs {
pub indexes_to_cointime_price: ComputedVecsFromHeight<Dollars>,
pub indexes_to_cointime_cap: ComputedVecsFromHeight<Dollars>,
pub indexes_to_cointime_price_ratio: ComputedRatioVecsFromDateIndex,
// pub indexes_to_thermo_cap_relative_to_investor_cap: ComputedValueVecsFromHeight,
pub indexes_to_cointime_adj_inflation_rate: ComputedVecsFromDateIndex<StoredF32>,
pub indexes_to_cointime_adj_tx_btc_velocity: ComputedVecsFromDateIndex<StoredF64>,
pub indexes_to_cointime_adj_tx_usd_velocity: ComputedVecsFromDateIndex<StoredF64>,
// pub indexes_to_thermo_cap_rel_to_investor_cap: ComputedValueVecsFromHeight,
}
impl Vecs {
pub fn forced_import(
parent: &Path,
version: Version,
parent_path: &Path,
parent_version: Version,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
) -> Result<Self> {
let db = Database::open(&parent.join("cointime"))?;
let db = Database::open(&parent_path.join("cointime"))?;
db.set_min_len(PAGE_SIZE * 1_000_000)?;
let compute_dollars = price.is_some();
Ok(Self {
let version = parent_version + Version::ZERO;
let this = Self {
indexes_to_coinblocks_created: ComputedVecsFromHeight::forced_import(
&db,
"coinblocks_created",
Source::Compute,
version + VERSION + Version::ZERO,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
)?,
@@ -71,7 +75,7 @@ impl Vecs {
&db,
"coinblocks_stored",
Source::Compute,
version + VERSION + Version::ZERO,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
)?,
@@ -79,7 +83,7 @@ impl Vecs {
&db,
"liveliness",
Source::Compute,
version + VERSION + Version::ZERO,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
@@ -87,7 +91,7 @@ impl Vecs {
&db,
"vaultedness",
Source::Compute,
version + VERSION + Version::ZERO,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
@@ -95,7 +99,7 @@ impl Vecs {
&db,
"activity_to_vaultedness_ratio",
Source::Compute,
version + VERSION + Version::ZERO,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
@@ -103,7 +107,7 @@ impl Vecs {
&db,
"vaulted_supply",
Source::Compute,
version + VERSION + Version::ONE,
version + Version::ONE,
VecBuilderOptions::default().add_last(),
compute_dollars,
indexes,
@@ -112,7 +116,7 @@ impl Vecs {
&db,
"active_supply",
Source::Compute,
version + VERSION + Version::ONE,
version + Version::ONE,
VecBuilderOptions::default().add_last(),
compute_dollars,
indexes,
@@ -121,7 +125,7 @@ impl Vecs {
&db,
"thermo_cap",
Source::Compute,
version + VERSION + Version::ONE,
version + Version::ONE,
indexes,
VecBuilderOptions::default().add_last(),
)?,
@@ -129,7 +133,7 @@ impl Vecs {
&db,
"investor_cap",
Source::Compute,
version + VERSION + Version::ONE,
version + Version::ONE,
indexes,
VecBuilderOptions::default().add_last(),
)?,
@@ -137,7 +141,7 @@ impl Vecs {
&db,
"vaulted_cap",
Source::Compute,
version + VERSION + Version::ONE,
version + Version::ONE,
indexes,
VecBuilderOptions::default().add_last(),
)?,
@@ -145,7 +149,7 @@ impl Vecs {
&db,
"active_cap",
Source::Compute,
version + VERSION + Version::ONE,
version + Version::ONE,
indexes,
VecBuilderOptions::default().add_last(),
)?,
@@ -153,7 +157,7 @@ impl Vecs {
&db,
"vaulted_price",
Source::Compute,
version + VERSION + Version::ZERO,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
@@ -161,7 +165,7 @@ impl Vecs {
&db,
"vaulted_price",
Source::None,
version + VERSION + Version::ZERO,
version + Version::ZERO,
indexes,
true,
)?,
@@ -169,7 +173,7 @@ impl Vecs {
&db,
"active_price",
Source::Compute,
version + VERSION + Version::ZERO,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
@@ -177,7 +181,7 @@ impl Vecs {
&db,
"active_price",
Source::None,
version + VERSION + Version::ZERO,
version + Version::ZERO,
indexes,
true,
)?,
@@ -185,7 +189,7 @@ impl Vecs {
&db,
"true_market_mean",
Source::Compute,
version + VERSION + Version::ZERO,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
@@ -193,7 +197,7 @@ impl Vecs {
&db,
"true_market_mean",
Source::None,
version + VERSION + Version::ZERO,
version + Version::ZERO,
indexes,
true,
)?,
@@ -201,7 +205,7 @@ impl Vecs {
&db,
"cointime_value_destroyed",
Source::Compute,
version + VERSION + Version::ZERO,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
)?,
@@ -209,7 +213,7 @@ impl Vecs {
&db,
"cointime_value_created",
Source::Compute,
version + VERSION + Version::ZERO,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
)?,
@@ -217,7 +221,7 @@ impl Vecs {
&db,
"cointime_value_stored",
Source::Compute,
version + VERSION + Version::ZERO,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
)?,
@@ -225,7 +229,7 @@ impl Vecs {
&db,
"cointime_price",
Source::Compute,
version + VERSION + Version::ZERO,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
@@ -233,7 +237,7 @@ impl Vecs {
&db,
"cointime_cap",
Source::Compute,
version + VERSION + Version::ZERO,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
@@ -241,35 +245,58 @@ impl Vecs {
&db,
"cointime_price",
Source::None,
version + VERSION + Version::ZERO,
version + Version::ZERO,
indexes,
true,
)?,
indexes_to_cointime_adj_inflation_rate: ComputedVecsFromDateIndex::forced_import(
&db,
"cointime_adj_inflation_rate",
Source::Compute,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_cointime_adj_tx_btc_velocity: ComputedVecsFromDateIndex::forced_import(
&db,
"cointime_adj_tx_btc_velocity",
Source::Compute,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_cointime_adj_tx_usd_velocity: ComputedVecsFromDateIndex::forced_import(
&db,
"cointime_adj_tx_usd_velocity",
Source::Compute,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
db,
})
};
this.db.retain_regions(
this.iter_any_collectable()
.flat_map(|v| v.region_names())
.collect(),
)?;
Ok(this)
}
#[allow(clippy::too_many_arguments)]
pub fn compute(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
price: Option<&price::Vecs>,
transactions: &transactions::Vecs,
chain: &chain::Vecs,
stateful: &stateful::Vecs,
exit: &Exit,
) -> Result<()> {
self.compute_(
indexer,
indexes,
starting_indexes,
price,
transactions,
stateful,
exit,
)?;
self.compute_(indexes, starting_indexes, price, chain, stateful, exit)?;
self.db.flush_then_punch()?;
Ok(())
}
@@ -277,22 +304,17 @@ impl Vecs {
#[allow(clippy::too_many_arguments)]
fn compute_(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
price: Option<&price::Vecs>,
transactions: &transactions::Vecs,
chain: &chain::Vecs,
stateful: &stateful::Vecs,
exit: &Exit,
) -> Result<()> {
let circulating_supply = &stateful.utxo_cohorts.all.1.height_to_supply;
self.indexes_to_coinblocks_created.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
self.indexes_to_coinblocks_created
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_transform(
starting_indexes.height,
circulating_supply,
@@ -300,18 +322,13 @@ impl Vecs {
exit,
)?;
Ok(())
},
)?;
})?;
let indexes_to_coinblocks_destroyed =
&stateful.utxo_cohorts.all.1.indexes_to_coinblocks_destroyed;
self.indexes_to_coinblocks_stored.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
self.indexes_to_coinblocks_stored
.compute_all(indexes, starting_indexes, exit, |vec| {
let mut coinblocks_destroyed_iter = indexes_to_coinblocks_destroyed
.height
.as_ref()
@@ -327,15 +344,10 @@ impl Vecs {
exit,
)?;
Ok(())
},
)?;
})?;
self.indexes_to_liveliness.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
self.indexes_to_liveliness
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_divide(
starting_indexes.height,
indexes_to_coinblocks_destroyed
@@ -347,16 +359,11 @@ impl Vecs {
exit,
)?;
Ok(())
},
)?;
})?;
let liveliness = &self.indexes_to_liveliness;
self.indexes_to_vaultedness.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
self.indexes_to_vaultedness
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_transform(
starting_indexes.height,
liveliness.height.as_ref().unwrap(),
@@ -364,16 +371,14 @@ impl Vecs {
exit,
)?;
Ok(())
},
)?;
})?;
let vaultedness = &self.indexes_to_vaultedness;
self.indexes_to_activity_to_vaultedness_ratio.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
|vec| {
vec.compute_divide(
starting_indexes.height,
liveliness.height.as_ref().unwrap(),
@@ -385,12 +390,11 @@ impl Vecs {
)?;
self.indexes_to_vaulted_supply.compute_all(
indexer,
indexes,
price,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
|vec| {
vec.compute_multiply(
starting_indexes.height,
circulating_supply,
@@ -402,12 +406,11 @@ impl Vecs {
)?;
self.indexes_to_active_supply.compute_all(
indexer,
indexes,
price,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
|vec| {
vec.compute_multiply(
starting_indexes.height,
circulating_supply,
@@ -418,6 +421,32 @@ impl Vecs {
},
)?;
self.indexes_to_cointime_adj_inflation_rate
.compute_all(starting_indexes, exit, |v| {
v.compute_multiply(
starting_indexes.dateindex,
self.indexes_to_activity_to_vaultedness_ratio
.dateindex
.unwrap_last(),
chain.indexes_to_inflation_rate.dateindex.as_ref().unwrap(),
exit,
)?;
Ok(())
})?;
self.indexes_to_cointime_adj_tx_btc_velocity
.compute_all(starting_indexes, exit, |v| {
v.compute_multiply(
starting_indexes.dateindex,
self.indexes_to_activity_to_vaultedness_ratio
.dateindex
.unwrap_last(),
chain.indexes_to_tx_btc_velocity.dateindex.as_ref().unwrap(),
exit,
)?;
Ok(())
})?;
if let Some(price) = price {
let realized_cap = stateful
.utxo_cohorts
@@ -438,15 +467,11 @@ impl Vecs {
.as_ref()
.unwrap();
self.indexes_to_thermo_cap.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
self.indexes_to_thermo_cap
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_transform(
starting_indexes.height,
transactions
chain
.indexes_to_subsidy
.dollars
.as_ref()
@@ -457,15 +482,10 @@ impl Vecs {
exit,
)?;
Ok(())
},
)?;
})?;
self.indexes_to_investor_cap.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
self.indexes_to_investor_cap
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_subtract(
starting_indexes.height,
realized_cap,
@@ -473,15 +493,10 @@ impl Vecs {
exit,
)?;
Ok(())
},
)?;
})?;
self.indexes_to_vaulted_cap.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
self.indexes_to_vaulted_cap
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_divide(
starting_indexes.height,
realized_cap,
@@ -489,15 +504,10 @@ impl Vecs {
exit,
)?;
Ok(())
},
)?;
})?;
self.indexes_to_active_cap.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
self.indexes_to_active_cap
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_multiply(
starting_indexes.height,
realized_cap,
@@ -505,15 +515,10 @@ impl Vecs {
exit,
)?;
Ok(())
},
)?;
})?;
self.indexes_to_vaulted_price.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
self.indexes_to_vaulted_price
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_divide(
starting_indexes.height,
realized_price,
@@ -521,24 +526,17 @@ impl Vecs {
exit,
)?;
Ok(())
},
)?;
})?;
self.indexes_to_vaulted_price_ratio.compute_rest(
indexer,
indexes,
price,
starting_indexes,
exit,
Some(self.indexes_to_vaulted_price.dateindex.unwrap_last()),
)?;
self.indexes_to_active_price.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
self.indexes_to_active_price
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_multiply(
starting_indexes.height,
realized_price,
@@ -546,12 +544,9 @@ impl Vecs {
exit,
)?;
Ok(())
},
)?;
})?;
self.indexes_to_active_price_ratio.compute_rest(
indexer,
indexes,
price,
starting_indexes,
exit,
@@ -559,11 +554,10 @@ impl Vecs {
)?;
self.indexes_to_true_market_mean.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
|vec| {
vec.compute_divide(
starting_indexes.height,
self.indexes_to_investor_cap.height.as_ref().unwrap(),
@@ -579,8 +573,6 @@ impl Vecs {
)?;
self.indexes_to_true_market_mean_ratio.compute_rest(
indexer,
indexes,
price,
starting_indexes,
exit,
@@ -588,16 +580,15 @@ impl Vecs {
)?;
self.indexes_to_cointime_value_destroyed.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
|vec| {
// TODO: Another example when the callback should be applied to each index, instead of to base then merging from more granular to less
// The price taken won't be correct for time based indexes
vec.compute_multiply(
starting_indexes.height,
&price.chainindexes_to_close.height,
&price.chainindexes_to_price_close.height,
indexes_to_coinblocks_destroyed.height.as_ref().unwrap(),
exit,
)?;
@@ -606,14 +597,13 @@ impl Vecs {
)?;
self.indexes_to_cointime_value_created.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
|vec| {
vec.compute_multiply(
starting_indexes.height,
&price.chainindexes_to_close.height,
&price.chainindexes_to_price_close.height,
self.indexes_to_coinblocks_created.height.as_ref().unwrap(),
exit,
)?;
@@ -622,14 +612,13 @@ impl Vecs {
)?;
self.indexes_to_cointime_value_stored.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
|vec| {
vec.compute_multiply(
starting_indexes.height,
&price.chainindexes_to_close.height,
&price.chainindexes_to_price_close.height,
self.indexes_to_coinblocks_stored.height.as_ref().unwrap(),
exit,
)?;
@@ -637,12 +626,8 @@ impl Vecs {
},
)?;
self.indexes_to_cointime_price.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
self.indexes_to_cointime_price
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_divide(
starting_indexes.height,
self.indexes_to_cointime_value_destroyed
@@ -654,15 +639,10 @@ impl Vecs {
exit,
)?;
Ok(())
},
)?;
})?;
self.indexes_to_cointime_cap.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
self.indexes_to_cointime_cap
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_multiply(
starting_indexes.height,
self.indexes_to_cointime_price.height.as_ref().unwrap(),
@@ -670,50 +650,100 @@ impl Vecs {
exit,
)?;
Ok(())
},
)?;
})?;
self.indexes_to_cointime_price_ratio.compute_rest(
indexer,
indexes,
price,
starting_indexes,
exit,
Some(self.indexes_to_cointime_price.dateindex.unwrap_last()),
)?;
self.indexes_to_cointime_adj_tx_usd_velocity.compute_all(
starting_indexes,
exit,
|v| {
v.compute_multiply(
starting_indexes.dateindex,
self.indexes_to_activity_to_vaultedness_ratio
.dateindex
.unwrap_last(),
chain.indexes_to_tx_usd_velocity.dateindex.as_ref().unwrap(),
exit,
)?;
Ok(())
},
)?;
}
Ok(())
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
[
self.indexes_to_coinblocks_created.vecs(),
self.indexes_to_coinblocks_stored.vecs(),
self.indexes_to_liveliness.vecs(),
self.indexes_to_vaultedness.vecs(),
self.indexes_to_activity_to_vaultedness_ratio.vecs(),
self.indexes_to_vaulted_supply.vecs(),
self.indexes_to_active_supply.vecs(),
self.indexes_to_thermo_cap.vecs(),
self.indexes_to_investor_cap.vecs(),
self.indexes_to_vaulted_cap.vecs(),
self.indexes_to_active_cap.vecs(),
self.indexes_to_vaulted_price.vecs(),
self.indexes_to_vaulted_price_ratio.vecs(),
self.indexes_to_active_price.vecs(),
self.indexes_to_active_price_ratio.vecs(),
self.indexes_to_true_market_mean.vecs(),
self.indexes_to_true_market_mean_ratio.vecs(),
self.indexes_to_cointime_price.vecs(),
self.indexes_to_cointime_cap.vecs(),
self.indexes_to_cointime_price_ratio.vecs(),
self.indexes_to_cointime_value_destroyed.vecs(),
self.indexes_to_cointime_value_created.vecs(),
self.indexes_to_cointime_value_stored.vecs(),
]
.into_iter()
.flatten()
.collect::<Vec<_>>()
pub fn iter_any_collectable(&self) -> impl Iterator<Item = &dyn AnyCollectableVec> {
let mut iter: Box<dyn Iterator<Item = &dyn AnyCollectableVec>> =
Box::new(std::iter::empty());
iter = Box::new(
iter.chain(
self.indexes_to_cointime_adj_inflation_rate
.iter_any_collectable(),
),
);
iter = Box::new(
iter.chain(
self.indexes_to_cointime_adj_tx_btc_velocity
.iter_any_collectable(),
),
);
iter = Box::new(
iter.chain(
self.indexes_to_cointime_adj_tx_usd_velocity
.iter_any_collectable(),
),
);
iter = Box::new(iter.chain(self.indexes_to_coinblocks_created.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_coinblocks_stored.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_liveliness.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_vaultedness.iter_any_collectable()));
iter = Box::new(
iter.chain(
self.indexes_to_activity_to_vaultedness_ratio
.iter_any_collectable(),
),
);
iter = Box::new(iter.chain(self.indexes_to_vaulted_supply.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_active_supply.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_thermo_cap.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_investor_cap.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_vaulted_cap.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_active_cap.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_vaulted_price.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_vaulted_price_ratio.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_active_price.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_active_price_ratio.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_true_market_mean.iter_any_collectable()));
iter = Box::new(
iter.chain(
self.indexes_to_true_market_mean_ratio
.iter_any_collectable(),
),
);
iter = Box::new(iter.chain(self.indexes_to_cointime_price.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_cointime_cap.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_cointime_price_ratio.iter_any_collectable()));
iter = Box::new(
iter.chain(
self.indexes_to_cointime_value_destroyed
.iter_any_collectable(),
),
);
iter = Box::new(
iter.chain(
self.indexes_to_cointime_value_created
.iter_any_collectable(),
),
);
iter = Box::new(iter.chain(self.indexes_to_cointime_value_stored.iter_any_collectable()));
iter
}
}
+97 -187
View File
@@ -1,8 +1,7 @@
use std::path::Path;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_structs::{StoredI16, StoredU16, Version};
use brk_structs::{StoredF32, StoredI16, StoredU16, Version};
use vecdb::{AnyCollectableVec, AnyVec, Database, Exit};
use crate::grouped::Source;
@@ -24,8 +23,11 @@ pub struct Vecs {
pub constant_2: ComputedVecsFromHeight<StoredU16>,
pub constant_3: ComputedVecsFromHeight<StoredU16>,
pub constant_4: ComputedVecsFromHeight<StoredU16>,
pub constant_38_2: ComputedVecsFromHeight<StoredF32>,
pub constant_50: ComputedVecsFromHeight<StoredU16>,
pub constant_61_8: ComputedVecsFromHeight<StoredF32>,
pub constant_100: ComputedVecsFromHeight<StoredU16>,
pub constant_600: ComputedVecsFromHeight<StoredU16>,
pub constant_minus_1: ComputedVecsFromHeight<StoredI16>,
pub constant_minus_2: ComputedVecsFromHeight<StoredI16>,
pub constant_minus_3: ComputedVecsFromHeight<StoredI16>,
@@ -36,7 +38,7 @@ impl Vecs {
pub fn forced_import(parent: &Path, version: Version, indexes: &indexes::Vecs) -> Result<Self> {
let db = Database::open(&parent.join("constants"))?;
Ok(Self {
let this = Self {
constant_0: ComputedVecsFromHeight::forced_import(
&db,
"constant_0",
@@ -77,6 +79,14 @@ impl Vecs {
indexes,
VecBuilderOptions::default().add_last(),
)?,
constant_38_2: ComputedVecsFromHeight::forced_import(
&db,
"constant_38_2",
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
constant_50: ComputedVecsFromHeight::forced_import(
&db,
"constant_50",
@@ -85,6 +95,14 @@ impl Vecs {
indexes,
VecBuilderOptions::default().add_last(),
)?,
constant_61_8: ComputedVecsFromHeight::forced_import(
&db,
"constant_61_8",
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
constant_100: ComputedVecsFromHeight::forced_import(
&db,
"constant_100",
@@ -93,6 +111,14 @@ impl Vecs {
indexes,
VecBuilderOptions::default().add_last(),
)?,
constant_600: ComputedVecsFromHeight::forced_import(
&db,
"constant_600",
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
constant_minus_1: ComputedVecsFromHeight::forced_import(
&db,
"constant_minus_1",
@@ -127,234 +153,118 @@ impl Vecs {
)?,
db,
})
};
this.db.retain_regions(
this.iter_any_collectable()
.flat_map(|v| v.region_names())
.collect(),
)?;
Ok(this)
}
pub fn compute(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.compute_(indexer, indexes, starting_indexes, exit)?;
self.compute_(indexes, starting_indexes, exit)?;
self.db.flush_then_punch()?;
Ok(())
}
fn compute_(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.constant_0.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, indexes, starting_indexes, exit| {
[
(&mut self.constant_0, 0),
(&mut self.constant_1, 1),
(&mut self.constant_2, 2),
(&mut self.constant_3, 3),
(&mut self.constant_4, 4),
(&mut self.constant_50, 50),
(&mut self.constant_100, 100),
(&mut self.constant_600, 600),
]
.into_iter()
.try_for_each(|(vec, value)| {
vec.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_to(
starting_indexes.height,
indexes.height_to_date.len(),
indexes.height_to_date.version(),
|i| (i, StoredU16::new(0)),
|i| (i, StoredU16::new(value)),
exit,
)?;
Ok(())
},
)?;
})
})?;
self.constant_1.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, indexes, starting_indexes, exit| {
[
(&mut self.constant_minus_1, -1),
(&mut self.constant_minus_2, -2),
(&mut self.constant_minus_3, 3),
(&mut self.constant_minus_4, 4),
]
.into_iter()
.try_for_each(|(vec, value)| {
vec.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_to(
starting_indexes.height,
indexes.height_to_date.len(),
indexes.height_to_date.version(),
|i| (i, StoredU16::new(1)),
|i| (i, StoredI16::new(value)),
exit,
)?;
Ok(())
},
)?;
})
})?;
self.constant_2.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, indexes, starting_indexes, exit| {
[
(&mut self.constant_38_2, 38.2),
(&mut self.constant_61_8, 61.8),
]
.into_iter()
.try_for_each(|(vec, value)| {
vec.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_to(
starting_indexes.height,
indexes.height_to_date.len(),
indexes.height_to_date.version(),
|i| (i, StoredU16::new(2)),
|i| (i, StoredF32::from(value)),
exit,
)?;
Ok(())
},
)?;
self.constant_3.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, indexes, starting_indexes, exit| {
vec.compute_to(
starting_indexes.height,
indexes.height_to_date.len(),
indexes.height_to_date.version(),
|i| (i, StoredU16::new(3)),
exit,
)?;
Ok(())
},
)?;
self.constant_4.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, indexes, starting_indexes, exit| {
vec.compute_to(
starting_indexes.height,
indexes.height_to_date.len(),
indexes.height_to_date.version(),
|i| (i, StoredU16::new(4)),
exit,
)?;
Ok(())
},
)?;
self.constant_50.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, indexes, starting_indexes, exit| {
vec.compute_to(
starting_indexes.height,
indexes.height_to_date.len(),
indexes.height_to_date.version(),
|i| (i, StoredU16::new(50)),
exit,
)?;
Ok(())
},
)?;
self.constant_100.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, indexes, starting_indexes, exit| {
vec.compute_to(
starting_indexes.height,
indexes.height_to_date.len(),
indexes.height_to_date.version(),
|i| (i, StoredU16::new(100)),
exit,
)?;
Ok(())
},
)?;
self.constant_minus_1.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, indexes, starting_indexes, exit| {
vec.compute_to(
starting_indexes.height,
indexes.height_to_date.len(),
indexes.height_to_date.version(),
|i| (i, StoredI16::new(-1)),
exit,
)?;
Ok(())
},
)?;
self.constant_minus_2.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, indexes, starting_indexes, exit| {
vec.compute_to(
starting_indexes.height,
indexes.height_to_date.len(),
indexes.height_to_date.version(),
|i| (i, StoredI16::new(-2)),
exit,
)?;
Ok(())
},
)?;
self.constant_minus_3.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, indexes, starting_indexes, exit| {
vec.compute_to(
starting_indexes.height,
indexes.height_to_date.len(),
indexes.height_to_date.version(),
|i| (i, StoredI16::new(-3)),
exit,
)?;
Ok(())
},
)?;
self.constant_minus_4.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, indexes, starting_indexes, exit| {
vec.compute_to(
starting_indexes.height,
indexes.height_to_date.len(),
indexes.height_to_date.version(),
|i| (i, StoredI16::new(-4)),
exit,
)?;
Ok(())
},
)?;
})
})?;
Ok(())
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
[
self.constant_0.vecs(),
self.constant_1.vecs(),
self.constant_2.vecs(),
self.constant_3.vecs(),
self.constant_4.vecs(),
self.constant_50.vecs(),
self.constant_100.vecs(),
self.constant_minus_1.vecs(),
self.constant_minus_2.vecs(),
self.constant_minus_3.vecs(),
self.constant_minus_4.vecs(),
]
.into_iter()
.flatten()
.collect::<Vec<_>>()
pub fn iter_any_collectable(&self) -> impl Iterator<Item = &dyn AnyCollectableVec> {
let mut iter: Box<dyn Iterator<Item = &dyn AnyCollectableVec>> =
Box::new(std::iter::empty());
iter = Box::new(iter.chain(self.constant_0.iter_any_collectable()));
iter = Box::new(iter.chain(self.constant_1.iter_any_collectable()));
iter = Box::new(iter.chain(self.constant_2.iter_any_collectable()));
iter = Box::new(iter.chain(self.constant_3.iter_any_collectable()));
iter = Box::new(iter.chain(self.constant_4.iter_any_collectable()));
iter = Box::new(iter.chain(self.constant_38_2.iter_any_collectable()));
iter = Box::new(iter.chain(self.constant_50.iter_any_collectable()));
iter = Box::new(iter.chain(self.constant_61_8.iter_any_collectable()));
iter = Box::new(iter.chain(self.constant_100.iter_any_collectable()));
iter = Box::new(iter.chain(self.constant_600.iter_any_collectable()));
iter = Box::new(iter.chain(self.constant_minus_1.iter_any_collectable()));
iter = Box::new(iter.chain(self.constant_minus_2.iter_any_collectable()));
iter = Box::new(iter.chain(self.constant_minus_3.iter_any_collectable()));
iter = Box::new(iter.chain(self.constant_minus_4.iter_any_collectable()));
iter
}
}
+30 -20
View File
@@ -16,30 +16,38 @@ pub struct Vecs {
db: Database,
fetcher: Fetcher,
pub dateindex_to_ohlc_in_cents: RawVec<DateIndex, OHLCCents>,
pub height_to_ohlc_in_cents: RawVec<Height, OHLCCents>,
pub dateindex_to_price_ohlc_in_cents: RawVec<DateIndex, OHLCCents>,
pub height_to_price_ohlc_in_cents: RawVec<Height, OHLCCents>,
}
impl Vecs {
pub fn forced_import(parent: &Path, fetcher: Fetcher, version: Version) -> Result<Self> {
let db = Database::open(&parent.join("fetched"))?;
Ok(Self {
let this = Self {
fetcher,
dateindex_to_ohlc_in_cents: RawVec::forced_import(
dateindex_to_price_ohlc_in_cents: RawVec::forced_import(
&db,
"ohlc_in_cents",
"price_ohlc_in_cents",
version + Version::ZERO,
)?,
height_to_ohlc_in_cents: RawVec::forced_import(
height_to_price_ohlc_in_cents: RawVec::forced_import(
&db,
"ohlc_in_cents",
"price_ohlc_in_cents",
version + Version::ZERO,
)?,
db,
})
};
this.db.retain_regions(
this.iter_any_collectable()
.flat_map(|v| v.region_names())
.collect(),
)?;
Ok(this)
}
pub fn compute(
@@ -64,12 +72,12 @@ impl Vecs {
let height_to_timestamp = &indexer.vecs.height_to_timestamp;
let index = starting_indexes
.height
.min(Height::from(self.height_to_ohlc_in_cents.len()));
.min(Height::from(self.height_to_price_ohlc_in_cents.len()));
height_to_timestamp
.iter_at(index)
.try_for_each(|(i, v)| -> Result<()> {
let v = v.into_owned();
self.height_to_ohlc_in_cents.forced_push_at(
self.height_to_price_ohlc_in_cents.forced_push_at(
i,
self.fetcher
.get_height(
@@ -84,11 +92,11 @@ impl Vecs {
)?;
Ok(())
})?;
self.height_to_ohlc_in_cents.safe_flush(exit)?;
self.height_to_price_ohlc_in_cents.safe_flush(exit)?;
let index = starting_indexes
.dateindex
.min(DateIndex::from(self.dateindex_to_ohlc_in_cents.len()));
.min(DateIndex::from(self.dateindex_to_price_ohlc_in_cents.len()));
let mut prev = None;
indexes
.dateindex_to_date
@@ -98,7 +106,7 @@ impl Vecs {
if prev.is_none() {
let i = i.unwrap_to_usize();
prev.replace(if i > 0 {
self.dateindex_to_ohlc_in_cents
self.dateindex_to_price_ohlc_in_cents
.into_iter()
.unwrap_get_inner_(i - 1)
} else {
@@ -106,7 +114,8 @@ impl Vecs {
});
}
let ohlc = if i.unwrap_to_usize() + 100 >= self.dateindex_to_ohlc_in_cents.len()
let ohlc = if i.unwrap_to_usize() + 100
>= self.dateindex_to_price_ohlc_in_cents.len()
&& let Ok(mut ohlc) = self.fetcher.get_date(d)
{
let prev_open = *prev.as_ref().unwrap().close;
@@ -120,20 +129,21 @@ impl Vecs {
prev.replace(ohlc.clone());
self.dateindex_to_ohlc_in_cents
self.dateindex_to_price_ohlc_in_cents
.forced_push_at(i, ohlc, exit)?;
Ok(())
})?;
self.dateindex_to_ohlc_in_cents.safe_flush(exit)?;
self.dateindex_to_price_ohlc_in_cents.safe_flush(exit)?;
Ok(())
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
vec![
&self.dateindex_to_ohlc_in_cents as &dyn AnyCollectableVec,
&self.height_to_ohlc_in_cents,
pub fn iter_any_collectable(&self) -> impl Iterator<Item = &dyn AnyCollectableVec> {
[
&self.dateindex_to_price_ohlc_in_cents as &dyn AnyCollectableVec,
&self.height_to_price_ohlc_in_cents,
]
.into_iter()
}
}
@@ -1,473 +0,0 @@
use brk_error::Result;
use brk_structs::Version;
use vecdb::{
AnyBoxedIterableVec, AnyCloneableIterableVec, AnyCollectableVec, AnyIterableVec, Computation,
ComputedVec, ComputedVecFrom2, Database, Exit, Format, FromCoarserIndex, StoredIndex,
};
use crate::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(
db: &Database,
name: &str,
version: Version,
format: Format,
computation: Computation,
source: Option<AnyBoxedIterableVec<S1I, T>>,
source_extra: &EagerVecBuilder<S1I, T>,
len_source: AnyBoxedIterableVec<I, S2T>,
options: ComputedVecBuilderOptions,
) -> 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,
db,
&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,
db,
name,
version + VERSION + Version::ZERO,
format,
source_extra.last.as_ref().map_or_else(
|| {
source
.as_ref()
.unwrap_or_else(|| {
dbg!(db, 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,
db,
&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,
db,
&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,
db,
&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,
db,
&(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,
db,
&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()
}
}
}
+184 -134
View File
@@ -1,3 +1,4 @@
use allocative::Allocative;
use brk_error::{Error, Result};
use brk_structs::{CheckedSub, StoredU64, Version};
use vecdb::{
@@ -9,7 +10,7 @@ use crate::utils::get_percentile;
use super::ComputedType;
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Allocative)]
pub struct EagerVecBuilder<I, T>
where
I: StoredIndex,
@@ -19,11 +20,11 @@ where
pub average: Option<Box<EagerVec<I, T>>>,
pub sum: Option<Box<EagerVec<I, T>>>,
pub max: Option<Box<EagerVec<I, T>>>,
pub _90p: Option<Box<EagerVec<I, T>>>,
pub _75p: Option<Box<EagerVec<I, T>>>,
pub pct90: Option<Box<EagerVec<I, T>>>,
pub pct75: Option<Box<EagerVec<I, T>>>,
pub median: Option<Box<EagerVec<I, T>>>,
pub _25p: Option<Box<EagerVec<I, T>>>,
pub _10p: Option<Box<EagerVec<I, T>>>,
pub pct25: Option<Box<EagerVec<I, T>>>,
pub pct10: Option<Box<EagerVec<I, T>>>,
pub min: Option<Box<EagerVec<I, T>>>,
pub last: Option<Box<EagerVec<I, T>>>,
pub cumulative: Option<Box<EagerVec<I, T>>>,
@@ -118,7 +119,7 @@ where
Box::new(
EagerVec::forced_import(
db,
&maybe_suffix("average"),
&maybe_suffix("avg"),
version + VERSION + Version::ZERO,
format,
)
@@ -151,44 +152,44 @@ where
.unwrap(),
)
}),
_90p: options._90p.then(|| {
pct90: options.pct90.then(|| {
Box::new(
EagerVec::forced_import(
db,
&maybe_suffix("90p"),
&maybe_suffix("pct90"),
version + VERSION + Version::ZERO,
format,
)
.unwrap(),
)
}),
_75p: options._75p.then(|| {
pct75: options.pct75.then(|| {
Box::new(
EagerVec::forced_import(
db,
&maybe_suffix("75p"),
&maybe_suffix("pct75"),
version + VERSION + Version::ZERO,
format,
)
.unwrap(),
)
}),
_25p: options._25p.then(|| {
pct25: options.pct25.then(|| {
Box::new(
EagerVec::forced_import(
db,
&maybe_suffix("25p"),
&maybe_suffix("pct25"),
version + VERSION + Version::ZERO,
format,
)
.unwrap(),
)
}),
_10p: options._10p.then(|| {
pct10: options.pct10.then(|| {
Box::new(
EagerVec::forced_import(
db,
&maybe_suffix("10p"),
&maybe_suffix("pct10"),
version + VERSION + Version::ZERO,
format,
)
@@ -292,11 +293,11 @@ where
let needs_average_sum_or_cumulative =
needs_sum_or_cumulative || self.average.is_some();
let needs_sorted = self.max.is_some()
|| self._90p.is_some()
|| self._75p.is_some()
|| self.pct90.is_some()
|| self.pct75.is_some()
|| self.median.is_some()
|| self._25p.is_some()
|| self._10p.is_some()
|| self.pct25.is_some()
|| self.pct10.is_some()
|| self.min.is_some();
let needs_values = needs_sorted || needs_average_sum_or_cumulative;
@@ -333,24 +334,24 @@ where
)?;
}
if let Some(_90p) = self._90p.as_mut() {
_90p.forced_push_at(index, get_percentile(&values, 0.90), exit)?;
if let Some(pct90) = self.pct90.as_mut() {
pct90.forced_push_at(index, get_percentile(&values, 0.90), exit)?;
}
if let Some(_75p) = self._75p.as_mut() {
_75p.forced_push_at(index, get_percentile(&values, 0.75), exit)?;
if let Some(pct75) = self.pct75.as_mut() {
pct75.forced_push_at(index, get_percentile(&values, 0.75), exit)?;
}
if let Some(median) = self.median.as_mut() {
median.forced_push_at(index, get_percentile(&values, 0.50), exit)?;
}
if let Some(_25p) = self._25p.as_mut() {
_25p.forced_push_at(index, get_percentile(&values, 0.25), exit)?;
if let Some(pct25) = self.pct25.as_mut() {
pct25.forced_push_at(index, get_percentile(&values, 0.25), exit)?;
}
if let Some(_10p) = self._10p.as_mut() {
_10p.forced_push_at(index, get_percentile(&values, 0.10), exit)?;
if let Some(pct10) = self.pct10.as_mut() {
pct10.forced_push_at(index, get_percentile(&values, 0.10), exit)?;
}
if let Some(min) = self.min.as_mut() {
@@ -401,11 +402,11 @@ where
where
I2: StoredIndex + StoredRaw + CheckedSub<I2>,
{
if self._90p.is_some()
|| self._75p.is_some()
if self.pct90.is_some()
|| self.pct75.is_some()
|| self.median.is_some()
|| self._25p.is_some()
|| self._10p.is_some()
|| self.pct25.is_some()
|| self.pct10.is_some()
{
panic!("unsupported");
}
@@ -540,7 +541,7 @@ where
pub fn starting_index(&self, max_from: I) -> I {
max_from.min(I::from(
self.vecs().into_iter().map(|v| v.len()).min().unwrap(),
self.iter_any_collectable().map(|v| v.len()).min().unwrap(),
))
}
@@ -558,24 +559,24 @@ where
self.max.as_ref().unwrap()
}
#[allow(unused)]
pub fn unwrap_90p(&self) -> &EagerVec<I, T> {
self._90p.as_ref().unwrap()
pub fn unwrap_pct90(&self) -> &EagerVec<I, T> {
self.pct90.as_ref().unwrap()
}
#[allow(unused)]
pub fn unwrap_75p(&self) -> &EagerVec<I, T> {
self._75p.as_ref().unwrap()
pub fn unwrap_pct75(&self) -> &EagerVec<I, T> {
self.pct75.as_ref().unwrap()
}
#[allow(unused)]
pub fn unwrap_median(&self) -> &EagerVec<I, T> {
self.median.as_ref().unwrap()
}
#[allow(unused)]
pub fn unwrap_25p(&self) -> &EagerVec<I, T> {
self._25p.as_ref().unwrap()
pub fn unwrap_pct25(&self) -> &EagerVec<I, T> {
self.pct25.as_ref().unwrap()
}
#[allow(unused)]
pub fn unwrap_10p(&self) -> &EagerVec<I, T> {
self._10p.as_ref().unwrap()
pub fn unwrap_pct10(&self) -> &EagerVec<I, T> {
self.pct10.as_ref().unwrap()
}
pub fn unwrap_min(&self) -> &EagerVec<I, T> {
self.min.as_ref().unwrap()
@@ -588,47 +589,96 @@ where
self.cumulative.as_ref().unwrap()
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
let mut v: Vec<&dyn AnyCollectableVec> = vec![];
pub fn iter_any_collectable(&self) -> impl Iterator<Item = &dyn AnyCollectableVec> {
let mut iter: Box<dyn Iterator<Item = &dyn AnyCollectableVec>> =
Box::new(std::iter::empty());
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(median) = self.median.as_ref() {
v.push(median.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());
}
if let Some(_90p) = self._90p.as_ref() {
v.push(_90p.as_ref());
}
if let Some(_75p) = self._75p.as_ref() {
v.push(_75p.as_ref());
}
if let Some(_25p) = self._25p.as_ref() {
v.push(_25p.as_ref());
}
if let Some(_10p) = self._10p.as_ref() {
v.push(_10p.as_ref());
}
iter = Box::new(
iter.chain(
self.first
.as_ref()
.map(|x| x.as_ref() as &dyn AnyCollectableVec),
),
);
iter = Box::new(
iter.chain(
self.last
.as_ref()
.map(|x| x.as_ref() as &dyn AnyCollectableVec),
),
);
iter = Box::new(
iter.chain(
self.min
.as_ref()
.map(|x| x.as_ref() as &dyn AnyCollectableVec),
),
);
iter = Box::new(
iter.chain(
self.max
.as_ref()
.map(|x| x.as_ref() as &dyn AnyCollectableVec),
),
);
iter = Box::new(
iter.chain(
self.median
.as_ref()
.map(|x| x.as_ref() as &dyn AnyCollectableVec),
),
);
iter = Box::new(
iter.chain(
self.average
.as_ref()
.map(|x| x.as_ref() as &dyn AnyCollectableVec),
),
);
iter = Box::new(
iter.chain(
self.sum
.as_ref()
.map(|x| x.as_ref() as &dyn AnyCollectableVec),
),
);
iter = Box::new(
iter.chain(
self.cumulative
.as_ref()
.map(|x| x.as_ref() as &dyn AnyCollectableVec),
),
);
iter = Box::new(
iter.chain(
self.pct90
.as_ref()
.map(|x| x.as_ref() as &dyn AnyCollectableVec),
),
);
iter = Box::new(
iter.chain(
self.pct75
.as_ref()
.map(|x| x.as_ref() as &dyn AnyCollectableVec),
),
);
iter = Box::new(
iter.chain(
self.pct25
.as_ref()
.map(|x| x.as_ref() as &dyn AnyCollectableVec),
),
);
iter = Box::new(
iter.chain(
self.pct10
.as_ref()
.map(|x| x.as_ref() as &dyn AnyCollectableVec),
),
);
v
iter
}
pub fn safe_flush(&mut self, exit: &Exit) -> Result<()> {
@@ -656,17 +706,17 @@ where
if let Some(cumulative) = self.cumulative.as_mut() {
cumulative.safe_flush(exit)?;
}
if let Some(_90p) = self._90p.as_mut() {
_90p.safe_flush(exit)?;
if let Some(pct90) = self.pct90.as_mut() {
pct90.safe_flush(exit)?;
}
if let Some(_75p) = self._75p.as_mut() {
_75p.safe_flush(exit)?;
if let Some(pct75) = self.pct75.as_mut() {
pct75.safe_flush(exit)?;
}
if let Some(_25p) = self._25p.as_mut() {
_25p.safe_flush(exit)?;
if let Some(pct25) = self.pct25.as_mut() {
pct25.safe_flush(exit)?;
}
if let Some(_10p) = self._10p.as_mut() {
_10p.safe_flush(exit)?;
if let Some(pct10) = self.pct10.as_mut() {
pct10.safe_flush(exit)?;
}
Ok(())
@@ -697,17 +747,17 @@ where
if let Some(cumulative) = self.cumulative.as_mut() {
cumulative.validate_computed_version_or_reset(Version::ZERO + version)?;
}
if let Some(_90p) = self._90p.as_mut() {
_90p.validate_computed_version_or_reset(Version::ZERO + version)?;
if let Some(pct90) = self.pct90.as_mut() {
pct90.validate_computed_version_or_reset(Version::ZERO + version)?;
}
if let Some(_75p) = self._75p.as_mut() {
_75p.validate_computed_version_or_reset(Version::ZERO + version)?;
if let Some(pct75) = self.pct75.as_mut() {
pct75.validate_computed_version_or_reset(Version::ZERO + version)?;
}
if let Some(_25p) = self._25p.as_mut() {
_25p.validate_computed_version_or_reset(Version::ZERO + version)?;
if let Some(pct25) = self.pct25.as_mut() {
pct25.validate_computed_version_or_reset(Version::ZERO + version)?;
}
if let Some(_10p) = self._10p.as_mut() {
_10p.validate_computed_version_or_reset(Version::ZERO + version)?;
if let Some(pct10) = self.pct10.as_mut() {
pct10.validate_computed_version_or_reset(Version::ZERO + version)?;
}
Ok(())
@@ -719,11 +769,11 @@ pub struct VecBuilderOptions {
average: bool,
sum: bool,
max: bool,
_90p: bool,
_75p: bool,
pct90: bool,
pct75: bool,
median: bool,
_25p: bool,
_10p: bool,
pct25: bool,
pct10: bool,
min: bool,
first: bool,
last: bool,
@@ -743,24 +793,24 @@ impl VecBuilderOptions {
self.max
}
pub fn _90p(&self) -> bool {
self._90p
pub fn pct90(&self) -> bool {
self.pct90
}
pub fn _75p(&self) -> bool {
self._75p
pub fn pct75(&self) -> bool {
self.pct75
}
pub fn median(&self) -> bool {
self.median
}
pub fn _25p(&self) -> bool {
self._25p
pub fn pct25(&self) -> bool {
self.pct25
}
pub fn _10p(&self) -> bool {
self._10p
pub fn pct10(&self) -> bool {
self.pct10
}
pub fn min(&self) -> bool {
@@ -816,26 +866,26 @@ impl VecBuilderOptions {
}
#[allow(unused)]
pub fn add_90p(mut self) -> Self {
self._90p = true;
pub fn add_pct90(mut self) -> Self {
self.pct90 = true;
self
}
#[allow(unused)]
pub fn add_75p(mut self) -> Self {
self._75p = true;
pub fn add_pct75(mut self) -> Self {
self.pct75 = true;
self
}
#[allow(unused)]
pub fn add_25p(mut self) -> Self {
self._25p = true;
pub fn add_pct25(mut self) -> Self {
self.pct25 = true;
self
}
#[allow(unused)]
pub fn add_10p(mut self) -> Self {
self._10p = true;
pub fn add_pct10(mut self) -> Self {
self.pct10 = true;
self
}
@@ -875,26 +925,26 @@ impl VecBuilderOptions {
}
#[allow(unused)]
pub fn rm_90p(mut self) -> Self {
self._90p = false;
pub fn rm_pct90(mut self) -> Self {
self.pct90 = false;
self
}
#[allow(unused)]
pub fn rm_75p(mut self) -> Self {
self._75p = false;
pub fn rm_pct75(mut self) -> Self {
self.pct75 = false;
self
}
#[allow(unused)]
pub fn rm_25p(mut self) -> Self {
self._25p = false;
pub fn rm_pct25(mut self) -> Self {
self.pct25 = false;
self
}
#[allow(unused)]
pub fn rm_10p(mut self) -> Self {
self._10p = false;
pub fn rm_pct10(mut self) -> Self {
self.pct10 = false;
self
}
@@ -911,20 +961,20 @@ impl VecBuilderOptions {
}
pub fn add_percentiles(mut self) -> Self {
self._90p = true;
self._75p = true;
self.pct90 = true;
self.pct75 = true;
self.median = true;
self._25p = true;
self._10p = true;
self.pct25 = true;
self.pct10 = true;
self
}
pub fn remove_percentiles(mut self) -> Self {
self._90p = false;
self._75p = false;
self.pct90 = false;
self.pct75 = false;
self.median = false;
self._25p = false;
self._10p = false;
self.pct25 = false;
self.pct10 = false;
self
}
@@ -933,11 +983,11 @@ impl VecBuilderOptions {
self.average,
self.sum,
self.max,
self._90p,
self._75p,
self.pct90,
self.pct75,
self.median,
self._25p,
self._10p,
self.pct25,
self.pct10,
self.min,
self.first,
self.last,
+57 -27
View File
@@ -1,3 +1,4 @@
use allocative::Allocative;
use brk_structs::Version;
use vecdb::{
AnyBoxedIterableVec, AnyCloneableIterableVec, AnyCollectableVec, FromCoarserIndex,
@@ -9,7 +10,7 @@ use crate::grouped::{EagerVecBuilder, VecBuilderOptions};
use super::ComputedType;
#[allow(clippy::type_complexity)]
#[derive(Clone)]
#[derive(Clone, Allocative)]
pub struct LazyVecBuilder<I, T, S1I, S2T>
where
I: StoredIndex,
@@ -142,7 +143,7 @@ where
}),
average: options.average.then(|| {
Box::new(LazyVecFrom2::init(
&maybe_suffix("average"),
&maybe_suffix("avg"),
version + VERSION + Version::ZERO,
source_extra
.average
@@ -216,7 +217,7 @@ where
pub fn starting_index(&self, max_from: I) -> I {
max_from.min(I::from(
self.vecs().into_iter().map(|v| v.len()).min().unwrap(),
self.iter_any_collectable().map(|v| v.len()).min().unwrap(),
))
}
@@ -244,32 +245,61 @@ where
self.cumulative.as_ref().unwrap()
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
let mut v: Vec<&dyn AnyCollectableVec> = vec![];
pub fn iter_any_collectable(&self) -> impl Iterator<Item = &dyn AnyCollectableVec> {
let mut iter: Box<dyn Iterator<Item = &dyn AnyCollectableVec>> =
Box::new(std::iter::empty());
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());
}
iter = Box::new(
iter.chain(
self.first
.as_ref()
.map(|x| x.as_ref() as &dyn AnyCollectableVec),
),
);
iter = Box::new(
iter.chain(
self.last
.as_ref()
.map(|x| x.as_ref() as &dyn AnyCollectableVec),
),
);
iter = Box::new(
iter.chain(
self.min
.as_ref()
.map(|x| x.as_ref() as &dyn AnyCollectableVec),
),
);
iter = Box::new(
iter.chain(
self.max
.as_ref()
.map(|x| x.as_ref() as &dyn AnyCollectableVec),
),
);
iter = Box::new(
iter.chain(
self.average
.as_ref()
.map(|x| x.as_ref() as &dyn AnyCollectableVec),
),
);
iter = Box::new(
iter.chain(
self.sum
.as_ref()
.map(|x| x.as_ref() as &dyn AnyCollectableVec),
),
);
iter = Box::new(
iter.chain(
self.cumulative
.as_ref()
.map(|x| x.as_ref() as &dyn AnyCollectableVec),
),
);
v
iter
}
}
@@ -1,6 +1,6 @@
use allocative::Allocative;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_structs::{
DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, Version, WeekIndex, YearIndex,
};
@@ -10,7 +10,7 @@ use crate::{Indexes, grouped::LazyVecBuilder, indexes};
use super::{ComputedType, EagerVecBuilder, Source, VecBuilderOptions};
#[derive(Clone)]
#[derive(Clone, Allocative)]
pub struct ComputedVecsFromDateIndex<T>
where
T: ComputedType + PartialOrd,
@@ -111,28 +111,14 @@ where
pub fn compute_all<F>(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
mut compute: F,
) -> Result<()>
where
F: FnMut(
&mut EagerVec<DateIndex, T>,
&Indexer,
&indexes::Vecs,
&Indexes,
&Exit,
) -> Result<()>,
F: FnMut(&mut EagerVec<DateIndex, T>) -> Result<()>,
{
compute(
self.dateindex.as_mut().unwrap(),
indexer,
indexes,
starting_indexes,
exit,
)?;
compute(self.dateindex.as_mut().unwrap())?;
let dateindex: Option<&EagerVec<DateIndex, T>> = None;
self.compute_rest(starting_indexes, exit, dateindex)
@@ -157,21 +143,22 @@ where
Ok(())
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
[
pub fn iter_any_collectable(&self) -> impl Iterator<Item = &dyn AnyCollectableVec> {
let mut iter: Box<dyn Iterator<Item = &dyn AnyCollectableVec>> = Box::new(
self.dateindex
.as_ref()
.map_or(vec![], |v| vec![v as &dyn AnyCollectableVec]),
self.dateindex_extra.vecs(),
self.weekindex.vecs(),
self.monthindex.vecs(),
self.quarterindex.vecs(),
self.semesterindex.vecs(),
self.yearindex.vecs(),
self.decadeindex.vecs(),
]
.into_iter()
.flatten()
.collect::<Vec<_>>()
.map(|x| x as &dyn AnyCollectableVec)
.into_iter(),
);
iter = Box::new(iter.chain(self.dateindex_extra.iter_any_collectable()));
iter = Box::new(iter.chain(self.weekindex.iter_any_collectable()));
iter = Box::new(iter.chain(self.monthindex.iter_any_collectable()));
iter = Box::new(iter.chain(self.quarterindex.iter_any_collectable()));
iter = Box::new(iter.chain(self.semesterindex.iter_any_collectable()));
iter = Box::new(iter.chain(self.yearindex.iter_any_collectable()));
iter = Box::new(iter.chain(self.decadeindex.iter_any_collectable()));
iter
}
}
+21 -28
View File
@@ -1,6 +1,6 @@
use allocative::Allocative;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_structs::{
DateIndex, DecadeIndex, DifficultyEpoch, Height, MonthIndex, QuarterIndex, SemesterIndex,
Version, WeekIndex, YearIndex,
@@ -15,7 +15,7 @@ use crate::{
use super::{ComputedType, EagerVecBuilder, VecBuilderOptions};
#[derive(Clone)]
#[derive(Clone, Allocative)]
pub struct ComputedVecsFromHeight<T>
where
T: ComputedType + PartialOrd,
@@ -133,22 +133,15 @@ where
pub fn compute_all<F>(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
mut compute: F,
) -> Result<()>
where
F: FnMut(&mut EagerVec<Height, T>, &Indexer, &indexes::Vecs, &Indexes, &Exit) -> Result<()>,
F: FnMut(&mut EagerVec<Height, T>) -> Result<()>,
{
compute(
self.height.as_mut().unwrap(),
indexer,
indexes,
starting_indexes,
exit,
)?;
compute(self.height.as_mut().unwrap())?;
let height: Option<&EagerVec<Height, T>> = None;
self.compute_rest(indexes, starting_indexes, exit, height)
@@ -206,24 +199,24 @@ where
Ok(())
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
[
pub fn iter_any_collectable(&self) -> impl Iterator<Item = &dyn AnyCollectableVec> {
let mut iter: Box<dyn Iterator<Item = &dyn AnyCollectableVec>> = Box::new(
self.height
.as_ref()
.map_or(vec![], |v| vec![v as &dyn AnyCollectableVec]),
self.height_extra.vecs(),
self.dateindex.vecs(),
self.weekindex.vecs(),
self.difficultyepoch.vecs(),
self.monthindex.vecs(),
self.quarterindex.vecs(),
self.semesterindex.vecs(),
self.yearindex.vecs(),
// self.halvingepoch.vecs(),
self.decadeindex.vecs(),
]
.into_iter()
.flatten()
.collect::<Vec<_>>()
.map(|x| x as &dyn AnyCollectableVec)
.into_iter(),
);
iter = Box::new(iter.chain(self.height_extra.iter_any_collectable()));
iter = Box::new(iter.chain(self.dateindex.iter_any_collectable()));
iter = Box::new(iter.chain(self.weekindex.iter_any_collectable()));
iter = Box::new(iter.chain(self.difficultyepoch.iter_any_collectable()));
iter = Box::new(iter.chain(self.monthindex.iter_any_collectable()));
iter = Box::new(iter.chain(self.quarterindex.iter_any_collectable()));
iter = Box::new(iter.chain(self.semesterindex.iter_any_collectable()));
iter = Box::new(iter.chain(self.yearindex.iter_any_collectable()));
iter = Box::new(iter.chain(self.decadeindex.iter_any_collectable()));
iter
}
}
@@ -1,6 +1,5 @@
use brk_error::Result;
use brk_indexer::Indexer;
use brk_structs::{DifficultyEpoch, Height, Version};
use vecdb::{AnyCollectableVec, Database, EagerVec, Exit};
@@ -59,16 +58,15 @@ where
pub fn compute<F>(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
mut compute: F,
) -> Result<()>
where
F: FnMut(&mut EagerVec<Height, T>, &Indexer, &indexes::Vecs, &Indexes, &Exit) -> Result<()>,
F: FnMut(&mut EagerVec<Height, T>) -> Result<()>,
{
compute(&mut self.height, indexer, indexes, starting_indexes, exit)?;
compute(&mut self.height)?;
self.height_extra
.extend(starting_indexes.height, &self.height, exit)?;
@@ -84,15 +82,10 @@ where
Ok(())
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
[
vec![&self.height as &dyn AnyCollectableVec],
self.height_extra.vecs(),
self.difficultyepoch.vecs(),
// self.halvingepoch.vecs(),
]
.into_iter()
.flatten()
.collect::<Vec<_>>()
pub fn iter_any_collectable(&self) -> impl Iterator<Item = &dyn AnyCollectableVec> {
[&self.height as &dyn AnyCollectableVec]
.into_iter()
.chain(self.height_extra.iter_any_collectable())
.chain(self.difficultyepoch.iter_any_collectable())
}
}
+44 -43
View File
@@ -1,3 +1,4 @@
use allocative::Allocative;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_structs::{
@@ -17,7 +18,7 @@ use crate::{
use super::{ComputedType, EagerVecBuilder, VecBuilderOptions};
#[derive(Clone)]
#[derive(Clone, Allocative)]
pub struct ComputedVecsFromTxindex<T>
where
T: ComputedType + PartialOrd,
@@ -225,25 +226,25 @@ where
Ok(())
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
[
pub fn iter_any_collectable(&self) -> impl Iterator<Item = &dyn AnyCollectableVec> {
let mut iter: Box<dyn Iterator<Item = &dyn AnyCollectableVec>> = Box::new(
self.txindex
.as_ref()
.map_or(vec![], |v| vec![v.as_ref() as &dyn AnyCollectableVec]),
self.height.vecs(),
self.dateindex.vecs(),
self.weekindex.vecs(),
self.difficultyepoch.vecs(),
self.monthindex.vecs(),
self.quarterindex.vecs(),
self.semesterindex.vecs(),
self.yearindex.vecs(),
// self.halvingepoch.vecs(),
self.decadeindex.vecs(),
]
.into_iter()
.flatten()
.collect::<Vec<_>>()
.map(|x| x.as_ref() as &dyn AnyCollectableVec)
.into_iter(),
);
iter = Box::new(iter.chain(self.height.iter_any_collectable()));
iter = Box::new(iter.chain(self.dateindex.iter_any_collectable()));
iter = Box::new(iter.chain(self.weekindex.iter_any_collectable()));
iter = Box::new(iter.chain(self.difficultyepoch.iter_any_collectable()));
iter = Box::new(iter.chain(self.monthindex.iter_any_collectable()));
iter = Box::new(iter.chain(self.quarterindex.iter_any_collectable()));
iter = Box::new(iter.chain(self.semesterindex.iter_any_collectable()));
iter = Box::new(iter.chain(self.yearindex.iter_any_collectable()));
iter = Box::new(iter.chain(self.decadeindex.iter_any_collectable()));
iter
}
}
@@ -319,24 +320,24 @@ impl ComputedVecsFromTxindex<Bitcoin> {
exit,
)?;
}
if let Some(_90p) = self.height._90p.as_mut() {
_90p.forced_push_at(
if let Some(pct90) = self.height.pct90.as_mut() {
pct90.forced_push_at(
height,
Bitcoin::from(
sats.height
.unwrap_90p()
.unwrap_pct90()
.into_iter()
.unwrap_get_inner(height),
),
exit,
)?;
}
if let Some(_75p) = self.height._75p.as_mut() {
_75p.forced_push_at(
if let Some(pct75) = self.height.pct75.as_mut() {
pct75.forced_push_at(
height,
Bitcoin::from(
sats.height
.unwrap_75p()
.unwrap_pct75()
.into_iter()
.unwrap_get_inner(height),
),
@@ -355,24 +356,24 @@ impl ComputedVecsFromTxindex<Bitcoin> {
exit,
)?;
}
if let Some(_25p) = self.height._25p.as_mut() {
_25p.forced_push_at(
if let Some(pct25) = self.height.pct25.as_mut() {
pct25.forced_push_at(
height,
Bitcoin::from(
sats.height
.unwrap_25p()
.unwrap_pct25()
.into_iter()
.unwrap_get_inner(height),
),
exit,
)?;
}
if let Some(_10p) = self.height._10p.as_mut() {
_10p.forced_push_at(
if let Some(pct10) = self.height.pct10.as_mut() {
pct10.forced_push_at(
height,
Bitcoin::from(
sats.height
.unwrap_10p()
.unwrap_pct10()
.into_iter()
.unwrap_get_inner(height),
),
@@ -447,7 +448,7 @@ impl ComputedVecsFromTxindex<Dollars> {
let starting_index = self.height.starting_index(starting_indexes.height);
let mut close_iter = price.chainindexes_to_close.height.into_iter();
let mut close_iter = price.chainindexes_to_price_close.height.into_iter();
(starting_index.unwrap_to_usize()..indexer.vecs.height_to_weight.len())
.map(Height::from)
@@ -502,25 +503,25 @@ impl ComputedVecsFromTxindex<Dollars> {
exit,
)?;
}
if let Some(_90p) = self.height._90p.as_mut() {
_90p.forced_push_at(
if let Some(pct90) = self.height.pct90.as_mut() {
pct90.forced_push_at(
height,
price
* bitcoin
.height
.unwrap_90p()
.unwrap_pct90()
.into_iter()
.unwrap_get_inner(height),
exit,
)?;
}
if let Some(_75p) = self.height._75p.as_mut() {
_75p.forced_push_at(
if let Some(pct75) = self.height.pct75.as_mut() {
pct75.forced_push_at(
height,
price
* bitcoin
.height
.unwrap_75p()
.unwrap_pct75()
.into_iter()
.unwrap_get_inner(height),
exit,
@@ -538,25 +539,25 @@ impl ComputedVecsFromTxindex<Dollars> {
exit,
)?;
}
if let Some(_25p) = self.height._25p.as_mut() {
_25p.forced_push_at(
if let Some(pct25) = self.height.pct25.as_mut() {
pct25.forced_push_at(
height,
price
* bitcoin
.height
.unwrap_25p()
.unwrap_pct25()
.into_iter()
.unwrap_get_inner(height),
exit,
)?;
}
if let Some(_10p) = self.height._10p.as_mut() {
_10p.forced_push_at(
if let Some(pct10) = self.height.pct10.as_mut() {
pct10.forced_push_at(
height,
price
* bitcoin
.height
.unwrap_10p()
.unwrap_pct10()
.into_iter()
.unwrap_get_inner(height),
exit,
@@ -1,5 +1,4 @@
use brk_error::Result;
use brk_indexer::Indexer;
use brk_structs::{Date, DateIndex, Dollars, StoredF32, Version};
use vecdb::{
AnyCollectableVec, AnyIterableVec, AnyStoredVec, AnyVec, CollectableVec, Database, EagerVec,
@@ -8,7 +7,9 @@ use vecdb::{
use crate::{
Indexes,
grouped::{ComputedStandardDeviationVecsFromDateIndex, source::Source},
grouped::{
ComputedStandardDeviationVecsFromDateIndex, StandardDeviationVecsOptions, source::Source,
},
indexes, price,
utils::get_percentile,
};
@@ -22,18 +23,18 @@ pub struct ComputedRatioVecsFromDateIndex {
pub ratio: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_1w_sma: Option<ComputedVecsFromDateIndex<StoredF32>>,
pub ratio_1m_sma: Option<ComputedVecsFromDateIndex<StoredF32>>,
pub ratio_p99: Option<ComputedVecsFromDateIndex<StoredF32>>,
pub ratio_p98: Option<ComputedVecsFromDateIndex<StoredF32>>,
pub ratio_p95: Option<ComputedVecsFromDateIndex<StoredF32>>,
pub ratio_p5: Option<ComputedVecsFromDateIndex<StoredF32>>,
pub ratio_p2: Option<ComputedVecsFromDateIndex<StoredF32>>,
pub ratio_p1: Option<ComputedVecsFromDateIndex<StoredF32>>,
pub ratio_p99_as_price: Option<ComputedVecsFromDateIndex<Dollars>>,
pub ratio_p98_as_price: Option<ComputedVecsFromDateIndex<Dollars>>,
pub ratio_p95_as_price: Option<ComputedVecsFromDateIndex<Dollars>>,
pub ratio_p5_as_price: Option<ComputedVecsFromDateIndex<Dollars>>,
pub ratio_p2_as_price: Option<ComputedVecsFromDateIndex<Dollars>>,
pub ratio_p1_as_price: Option<ComputedVecsFromDateIndex<Dollars>>,
pub ratio_pct99: Option<ComputedVecsFromDateIndex<StoredF32>>,
pub ratio_pct98: Option<ComputedVecsFromDateIndex<StoredF32>>,
pub ratio_pct95: Option<ComputedVecsFromDateIndex<StoredF32>>,
pub ratio_pct5: Option<ComputedVecsFromDateIndex<StoredF32>>,
pub ratio_pct2: Option<ComputedVecsFromDateIndex<StoredF32>>,
pub ratio_pct1: Option<ComputedVecsFromDateIndex<StoredF32>>,
pub ratio_pct99_usd: Option<ComputedVecsFromDateIndex<Dollars>>,
pub ratio_pct98_usd: Option<ComputedVecsFromDateIndex<Dollars>>,
pub ratio_pct95_usd: Option<ComputedVecsFromDateIndex<Dollars>>,
pub ratio_pct5_usd: Option<ComputedVecsFromDateIndex<Dollars>>,
pub ratio_pct2_usd: Option<ComputedVecsFromDateIndex<Dollars>>,
pub ratio_pct1_usd: Option<ComputedVecsFromDateIndex<Dollars>>,
pub ratio_sd: Option<ComputedStandardDeviationVecsFromDateIndex>,
pub ratio_4y_sd: Option<ComputedStandardDeviationVecsFromDateIndex>,
@@ -105,6 +106,7 @@ impl ComputedRatioVecsFromDateIndex {
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
StandardDeviationVecsOptions::default().add_all(),
)
.unwrap()
}),
@@ -116,6 +118,7 @@ impl ComputedRatioVecsFromDateIndex {
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
StandardDeviationVecsOptions::default().add_all(),
)
.unwrap()
}),
@@ -127,6 +130,7 @@ impl ComputedRatioVecsFromDateIndex {
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
StandardDeviationVecsOptions::default().add_all(),
)
.unwrap()
}),
@@ -138,13 +142,14 @@ impl ComputedRatioVecsFromDateIndex {
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
StandardDeviationVecsOptions::default().add_all(),
)
.unwrap()
}),
ratio_p99: extended.then(|| {
ratio_pct99: extended.then(|| {
ComputedVecsFromDateIndex::forced_import(
db,
&format!("{name}_ratio_p99"),
&format!("{name}_ratio_pct99"),
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
@@ -152,10 +157,10 @@ impl ComputedRatioVecsFromDateIndex {
)
.unwrap()
}),
ratio_p98: extended.then(|| {
ratio_pct98: extended.then(|| {
ComputedVecsFromDateIndex::forced_import(
db,
&format!("{name}_ratio_p98"),
&format!("{name}_ratio_pct98"),
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
@@ -163,10 +168,10 @@ impl ComputedRatioVecsFromDateIndex {
)
.unwrap()
}),
ratio_p95: extended.then(|| {
ratio_pct95: extended.then(|| {
ComputedVecsFromDateIndex::forced_import(
db,
&format!("{name}_ratio_p95"),
&format!("{name}_ratio_pct95"),
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
@@ -174,10 +179,10 @@ impl ComputedRatioVecsFromDateIndex {
)
.unwrap()
}),
ratio_p5: extended.then(|| {
ratio_pct5: extended.then(|| {
ComputedVecsFromDateIndex::forced_import(
db,
&format!("{name}_ratio_p5"),
&format!("{name}_ratio_pct5"),
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
@@ -185,10 +190,10 @@ impl ComputedRatioVecsFromDateIndex {
)
.unwrap()
}),
ratio_p2: extended.then(|| {
ratio_pct2: extended.then(|| {
ComputedVecsFromDateIndex::forced_import(
db,
&format!("{name}_ratio_p2"),
&format!("{name}_ratio_pct2"),
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
@@ -196,10 +201,10 @@ impl ComputedRatioVecsFromDateIndex {
)
.unwrap()
}),
ratio_p1: extended.then(|| {
ratio_pct1: extended.then(|| {
ComputedVecsFromDateIndex::forced_import(
db,
&format!("{name}_ratio_p1"),
&format!("{name}_ratio_pct1"),
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
@@ -207,10 +212,10 @@ impl ComputedRatioVecsFromDateIndex {
)
.unwrap()
}),
ratio_p99_as_price: extended.then(|| {
ratio_pct99_usd: extended.then(|| {
ComputedVecsFromDateIndex::forced_import(
db,
&format!("{name}_ratio_p99_as_price"),
&format!("{name}_ratio_pct99_usd"),
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
@@ -218,10 +223,10 @@ impl ComputedRatioVecsFromDateIndex {
)
.unwrap()
}),
ratio_p98_as_price: extended.then(|| {
ratio_pct98_usd: extended.then(|| {
ComputedVecsFromDateIndex::forced_import(
db,
&format!("{name}_ratio_p98_as_price"),
&format!("{name}_ratio_pct98_usd"),
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
@@ -229,10 +234,10 @@ impl ComputedRatioVecsFromDateIndex {
)
.unwrap()
}),
ratio_p95_as_price: extended.then(|| {
ratio_pct95_usd: extended.then(|| {
ComputedVecsFromDateIndex::forced_import(
db,
&format!("{name}_ratio_p95_as_price"),
&format!("{name}_ratio_pct95_usd"),
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
@@ -240,10 +245,10 @@ impl ComputedRatioVecsFromDateIndex {
)
.unwrap()
}),
ratio_p5_as_price: extended.then(|| {
ratio_pct5_usd: extended.then(|| {
ComputedVecsFromDateIndex::forced_import(
db,
&format!("{name}_ratio_p5_as_price"),
&format!("{name}_ratio_pct5_usd"),
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
@@ -251,10 +256,10 @@ impl ComputedRatioVecsFromDateIndex {
)
.unwrap()
}),
ratio_p2_as_price: extended.then(|| {
ratio_pct2_usd: extended.then(|| {
ComputedVecsFromDateIndex::forced_import(
db,
&format!("{name}_ratio_p2_as_price"),
&format!("{name}_ratio_pct2_usd"),
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
@@ -262,10 +267,10 @@ impl ComputedRatioVecsFromDateIndex {
)
.unwrap()
}),
ratio_p1_as_price: extended.then(|| {
ratio_pct1_usd: extended.then(|| {
ComputedVecsFromDateIndex::forced_import(
db,
&format!("{name}_ratio_p1_as_price"),
&format!("{name}_ratio_pct1_usd"),
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
@@ -278,79 +283,52 @@ impl ComputedRatioVecsFromDateIndex {
pub fn compute_all<F>(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
price: &price::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
compute: F,
) -> Result<()>
where
F: FnMut(
&mut EagerVec<DateIndex, Dollars>,
&Indexer,
&indexes::Vecs,
&Indexes,
&Exit,
) -> Result<()>,
F: FnMut(&mut EagerVec<DateIndex, Dollars>) -> Result<()>,
{
self.price.as_mut().unwrap().compute_all(
indexer,
indexes,
starting_indexes,
exit,
compute,
)?;
self.price
.as_mut()
.unwrap()
.compute_all(starting_indexes, exit, compute)?;
let date_to_price_opt: Option<&EagerVec<DateIndex, Dollars>> = None;
self.compute_rest(
indexer,
indexes,
price,
starting_indexes,
exit,
date_to_price_opt,
)
self.compute_rest(price, starting_indexes, exit, date_to_price_opt)
}
pub fn compute_rest(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
price: &price::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
date_to_price_opt: Option<&impl AnyIterableVec<DateIndex, Dollars>>,
price_opt: Option<&impl AnyIterableVec<DateIndex, Dollars>>,
) -> Result<()> {
let date_to_price = date_to_price_opt.unwrap_or_else(|| unsafe {
let closes = price.timeindexes_to_price_close.dateindex.as_ref().unwrap();
let price = price_opt.unwrap_or_else(|| unsafe {
std::mem::transmute(&self.price.as_ref().unwrap().dateindex)
});
let closes = price.timeindexes_to_close.dateindex.as_ref().unwrap();
self.ratio.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
let mut price = date_to_price.iter();
v.compute_transform(
starting_indexes.dateindex,
closes,
|(i, close, ..)| {
let price = price.unwrap_get_inner(i);
if price == Dollars::ZERO {
(i, StoredF32::from(1.0))
} else {
(i, StoredF32::from(*close / price))
}
},
exit,
)?;
Ok(())
},
)?;
self.ratio.compute_all(starting_indexes, exit, |v| {
v.compute_transform2(
starting_indexes.dateindex,
closes,
price,
|(i, close, price, ..)| {
if price == Dollars::ZERO {
(i, StoredF32::from(1.0))
} else {
(i, StoredF32::from(*close / price))
}
},
exit,
)?;
Ok(())
})?;
if self.ratio_1w_sma.is_none() {
return Ok(());
@@ -358,12 +336,10 @@ impl ComputedRatioVecsFromDateIndex {
let min_ratio_date = DateIndex::try_from(Date::MIN_RATIO).unwrap();
self.ratio_1w_sma.as_mut().unwrap().compute_all(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
self.ratio_1w_sma
.as_mut()
.unwrap()
.compute_all(starting_indexes, exit, |v| {
v.compute_sma_(
starting_indexes.dateindex,
self.ratio.dateindex.as_ref().unwrap(),
@@ -372,15 +348,12 @@ impl ComputedRatioVecsFromDateIndex {
Some(min_ratio_date),
)?;
Ok(())
},
)?;
})?;
self.ratio_1m_sma.as_mut().unwrap().compute_all(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
self.ratio_1m_sma
.as_mut()
.unwrap()
.compute_all(starting_indexes, exit, |v| {
v.compute_sma_(
starting_indexes.dateindex,
self.ratio.dateindex.as_ref().unwrap(),
@@ -389,8 +362,7 @@ impl ComputedRatioVecsFromDateIndex {
Some(min_ratio_date),
)?;
Ok(())
},
)?;
})?;
let ratio_version = self.ratio.dateindex.as_ref().unwrap().version();
self.mut_ratio_vecs()
@@ -424,42 +396,42 @@ impl ComputedRatioVecsFromDateIndex {
.iter_at(starting_dateindex)
.try_for_each(|(index, ratio)| -> Result<()> {
if index < min_ratio_date {
self.ratio_p5
self.ratio_pct5
.as_mut()
.unwrap()
.dateindex
.as_mut()
.unwrap()
.forced_push_at(index, StoredF32::NAN, exit)?;
self.ratio_p2
self.ratio_pct2
.as_mut()
.unwrap()
.dateindex
.as_mut()
.unwrap()
.forced_push_at(index, StoredF32::NAN, exit)?;
self.ratio_p1
self.ratio_pct1
.as_mut()
.unwrap()
.dateindex
.as_mut()
.unwrap()
.forced_push_at(index, StoredF32::NAN, exit)?;
self.ratio_p95
self.ratio_pct95
.as_mut()
.unwrap()
.dateindex
.as_mut()
.unwrap()
.forced_push_at(index, StoredF32::NAN, exit)?;
self.ratio_p98
self.ratio_pct98
.as_mut()
.unwrap()
.dateindex
.as_mut()
.unwrap()
.forced_push_at(index, StoredF32::NAN, exit)?;
self.ratio_p99
self.ratio_pct99
.as_mut()
.unwrap()
.dateindex
@@ -471,42 +443,42 @@ impl ComputedRatioVecsFromDateIndex {
let pos = sorted.binary_search(&ratio).unwrap_or_else(|pos| pos);
sorted.insert(pos, ratio);
self.ratio_p1
self.ratio_pct1
.as_mut()
.unwrap()
.dateindex
.as_mut()
.unwrap()
.forced_push_at(index, get_percentile(&sorted, 0.01), exit)?;
self.ratio_p2
self.ratio_pct2
.as_mut()
.unwrap()
.dateindex
.as_mut()
.unwrap()
.forced_push_at(index, get_percentile(&sorted, 0.02), exit)?;
self.ratio_p5
self.ratio_pct5
.as_mut()
.unwrap()
.dateindex
.as_mut()
.unwrap()
.forced_push_at(index, get_percentile(&sorted, 0.05), exit)?;
self.ratio_p95
self.ratio_pct95
.as_mut()
.unwrap()
.dateindex
.as_mut()
.unwrap()
.forced_push_at(index, get_percentile(&sorted, 0.95), exit)?;
self.ratio_p98
self.ratio_pct98
.as_mut()
.unwrap()
.dateindex
.as_mut()
.unwrap()
.forced_push_at(index, get_percentile(&sorted, 0.98), exit)?;
self.ratio_p99
self.ratio_pct99
.as_mut()
.unwrap()
.dateindex
@@ -522,49 +494,47 @@ impl ComputedRatioVecsFromDateIndex {
.into_iter()
.try_for_each(|v| v.safe_flush(exit))?;
self.ratio_p1.as_mut().unwrap().compute_rest(
self.ratio_pct1.as_mut().unwrap().compute_rest(
starting_indexes,
exit,
None as Option<&EagerVec<_, _>>,
)?;
self.ratio_p2.as_mut().unwrap().compute_rest(
self.ratio_pct2.as_mut().unwrap().compute_rest(
starting_indexes,
exit,
None as Option<&EagerVec<_, _>>,
)?;
self.ratio_p5.as_mut().unwrap().compute_rest(
self.ratio_pct5.as_mut().unwrap().compute_rest(
starting_indexes,
exit,
None as Option<&EagerVec<_, _>>,
)?;
self.ratio_p95.as_mut().unwrap().compute_rest(
self.ratio_pct95.as_mut().unwrap().compute_rest(
starting_indexes,
exit,
None as Option<&EagerVec<_, _>>,
)?;
self.ratio_p98.as_mut().unwrap().compute_rest(
self.ratio_pct98.as_mut().unwrap().compute_rest(
starting_indexes,
exit,
None as Option<&EagerVec<_, _>>,
)?;
self.ratio_p99.as_mut().unwrap().compute_rest(
self.ratio_pct99.as_mut().unwrap().compute_rest(
starting_indexes,
exit,
None as Option<&EagerVec<_, _>>,
)?;
let date_to_price = date_to_price_opt.unwrap_or_else(|| unsafe {
let date_to_price = price_opt.unwrap_or_else(|| unsafe {
std::mem::transmute(&self.price.as_ref().unwrap().dateindex)
});
self.ratio_p99_as_price.as_mut().unwrap().compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
self.ratio_pct99_usd
.as_mut()
.unwrap()
.compute_all(starting_indexes, exit, |vec| {
let mut iter = self
.ratio_p99
.ratio_pct99
.as_ref()
.unwrap()
.dateindex
@@ -581,67 +551,52 @@ impl ComputedRatioVecsFromDateIndex {
exit,
)?;
Ok(())
},
)?;
})?;
let compute_as_price =
|as_price: Option<&mut ComputedVecsFromDateIndex<Dollars>>,
let compute_usd =
|usd: Option<&mut ComputedVecsFromDateIndex<Dollars>>,
source: Option<&ComputedVecsFromDateIndex<StoredF32>>| {
as_price.unwrap().compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
let mut iter = source.unwrap().dateindex.as_ref().unwrap().into_iter();
vec.compute_transform(
starting_indexes.dateindex,
date_to_price,
|(i, price, ..)| {
let multiplier = iter.unwrap_get_inner(i);
(i, price * multiplier)
},
exit,
)?;
Ok(())
},
)
usd.unwrap().compute_all(starting_indexes, exit, |vec| {
let mut iter = source.unwrap().dateindex.as_ref().unwrap().into_iter();
vec.compute_transform(
starting_indexes.dateindex,
date_to_price,
|(i, price, ..)| {
let multiplier = iter.unwrap_get_inner(i);
(i, price * multiplier)
},
exit,
)?;
Ok(())
})
};
compute_as_price(self.ratio_p1_as_price.as_mut(), self.ratio_p1.as_ref())?;
compute_as_price(self.ratio_p2_as_price.as_mut(), self.ratio_p2.as_ref())?;
compute_as_price(self.ratio_p5_as_price.as_mut(), self.ratio_p5.as_ref())?;
compute_as_price(self.ratio_p95_as_price.as_mut(), self.ratio_p95.as_ref())?;
compute_as_price(self.ratio_p98_as_price.as_mut(), self.ratio_p98.as_ref())?;
compute_as_price(self.ratio_p99_as_price.as_mut(), self.ratio_p99.as_ref())?;
compute_usd(self.ratio_pct1_usd.as_mut(), self.ratio_pct1.as_ref())?;
compute_usd(self.ratio_pct2_usd.as_mut(), self.ratio_pct2.as_ref())?;
compute_usd(self.ratio_pct5_usd.as_mut(), self.ratio_pct5.as_ref())?;
compute_usd(self.ratio_pct95_usd.as_mut(), self.ratio_pct95.as_ref())?;
compute_usd(self.ratio_pct98_usd.as_mut(), self.ratio_pct98.as_ref())?;
compute_usd(self.ratio_pct99_usd.as_mut(), self.ratio_pct99.as_ref())?;
self.ratio_sd.as_mut().unwrap().compute_all(
indexer,
indexes,
starting_indexes,
exit,
self.ratio.dateindex.as_ref().unwrap(),
Some(date_to_price),
)?;
self.ratio_4y_sd.as_mut().unwrap().compute_all(
indexer,
indexes,
starting_indexes,
exit,
self.ratio.dateindex.as_ref().unwrap(),
Some(date_to_price),
)?;
self.ratio_2y_sd.as_mut().unwrap().compute_all(
indexer,
indexes,
starting_indexes,
exit,
self.ratio.dateindex.as_ref().unwrap(),
Some(date_to_price),
)?;
self.ratio_1y_sd.as_mut().unwrap().compute_all(
indexer,
indexes,
starting_indexes,
exit,
self.ratio.dateindex.as_ref().unwrap(),
@@ -653,22 +608,22 @@ impl ComputedRatioVecsFromDateIndex {
fn mut_ratio_vecs(&mut self) -> Vec<&mut EagerVec<DateIndex, StoredF32>> {
[
self.ratio_p1
self.ratio_pct1
.as_mut()
.map_or(vec![], |v| vec![v.dateindex.as_mut().unwrap()]),
self.ratio_p2
self.ratio_pct2
.as_mut()
.map_or(vec![], |v| vec![v.dateindex.as_mut().unwrap()]),
self.ratio_p5
self.ratio_pct5
.as_mut()
.map_or(vec![], |v| vec![v.dateindex.as_mut().unwrap()]),
self.ratio_p95
self.ratio_pct95
.as_mut()
.map_or(vec![], |v| vec![v.dateindex.as_mut().unwrap()]),
self.ratio_p98
self.ratio_pct98
.as_mut()
.map_or(vec![], |v| vec![v.dateindex.as_mut().unwrap()]),
self.ratio_p99
self.ratio_pct99
.as_mut()
.map_or(vec![], |v| vec![v.dateindex.as_mut().unwrap()]),
]
@@ -677,37 +632,132 @@ impl ComputedRatioVecsFromDateIndex {
.collect::<Vec<_>>()
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
[
self.price.as_ref().map_or(vec![], |v| v.vecs()),
self.ratio.vecs(),
self.ratio_1w_sma.as_ref().map_or(vec![], |v| v.vecs()),
self.ratio_1m_sma.as_ref().map_or(vec![], |v| v.vecs()),
self.ratio_sd.as_ref().map_or(vec![], |v| v.vecs()),
self.ratio_1y_sd.as_ref().map_or(vec![], |v| v.vecs()),
self.ratio_2y_sd.as_ref().map_or(vec![], |v| v.vecs()),
self.ratio_4y_sd.as_ref().map_or(vec![], |v| v.vecs()),
self.ratio_p1.as_ref().map_or(vec![], |v| v.vecs()),
self.ratio_p2.as_ref().map_or(vec![], |v| v.vecs()),
self.ratio_p5.as_ref().map_or(vec![], |v| v.vecs()),
self.ratio_p95.as_ref().map_or(vec![], |v| v.vecs()),
self.ratio_p98.as_ref().map_or(vec![], |v| v.vecs()),
self.ratio_p99.as_ref().map_or(vec![], |v| v.vecs()),
self.ratio_p1_as_price.as_ref().map_or(vec![], |v| v.vecs()),
self.ratio_p2_as_price.as_ref().map_or(vec![], |v| v.vecs()),
self.ratio_p5_as_price.as_ref().map_or(vec![], |v| v.vecs()),
self.ratio_p95_as_price
.as_ref()
.map_or(vec![], |v| v.vecs()),
self.ratio_p98_as_price
.as_ref()
.map_or(vec![], |v| v.vecs()),
self.ratio_p99_as_price
.as_ref()
.map_or(vec![], |v| v.vecs()),
]
.into_iter()
.flatten()
.collect::<Vec<_>>()
pub fn iter_any_collectable(&self) -> impl Iterator<Item = &dyn AnyCollectableVec> {
let mut iter: Box<dyn Iterator<Item = &dyn AnyCollectableVec>> =
Box::new(self.price.iter().flat_map(|v| v.iter_any_collectable()));
iter = Box::new(iter.chain(self.ratio.iter_any_collectable()));
iter = Box::new(
iter.chain(
self.ratio_1w_sma
.iter()
.flat_map(|v| v.iter_any_collectable()),
),
);
iter = Box::new(
iter.chain(
self.ratio_1m_sma
.iter()
.flat_map(|v| v.iter_any_collectable()),
),
);
iter = Box::new(iter.chain(self.ratio_sd.iter().flat_map(|v| v.iter_any_collectable())));
iter = Box::new(
iter.chain(
self.ratio_1y_sd
.iter()
.flat_map(|v| v.iter_any_collectable()),
),
);
iter = Box::new(
iter.chain(
self.ratio_2y_sd
.iter()
.flat_map(|v| v.iter_any_collectable()),
),
);
iter = Box::new(
iter.chain(
self.ratio_4y_sd
.iter()
.flat_map(|v| v.iter_any_collectable()),
),
);
iter = Box::new(
iter.chain(
self.ratio_pct1
.iter()
.flat_map(|v| v.iter_any_collectable()),
),
);
iter = Box::new(
iter.chain(
self.ratio_pct2
.iter()
.flat_map(|v| v.iter_any_collectable()),
),
);
iter = Box::new(
iter.chain(
self.ratio_pct5
.iter()
.flat_map(|v| v.iter_any_collectable()),
),
);
iter = Box::new(
iter.chain(
self.ratio_pct95
.iter()
.flat_map(|v| v.iter_any_collectable()),
),
);
iter = Box::new(
iter.chain(
self.ratio_pct98
.iter()
.flat_map(|v| v.iter_any_collectable()),
),
);
iter = Box::new(
iter.chain(
self.ratio_pct99
.iter()
.flat_map(|v| v.iter_any_collectable()),
),
);
iter = Box::new(
iter.chain(
self.ratio_pct1_usd
.iter()
.flat_map(|v| v.iter_any_collectable()),
),
);
iter = Box::new(
iter.chain(
self.ratio_pct2_usd
.iter()
.flat_map(|v| v.iter_any_collectable()),
),
);
iter = Box::new(
iter.chain(
self.ratio_pct5_usd
.iter()
.flat_map(|v| v.iter_any_collectable()),
),
);
iter = Box::new(
iter.chain(
self.ratio_pct95_usd
.iter()
.flat_map(|v| v.iter_any_collectable()),
),
);
iter = Box::new(
iter.chain(
self.ratio_pct98_usd
.iter()
.flat_map(|v| v.iter_any_collectable()),
),
);
iter = Box::new(
iter.chain(
self.ratio_pct99_usd
.iter()
.flat_map(|v| v.iter_any_collectable()),
),
);
iter
}
}
File diff suppressed because it is too large Load Diff
@@ -1,5 +1,4 @@
use brk_error::Result;
use brk_indexer::Indexer;
use brk_structs::{Bitcoin, DateIndex, Dollars, Sats, Version};
use vecdb::{AnyCollectableVec, CollectableVec, Database, EagerVec, Exit, StoredVec};
@@ -43,7 +42,7 @@ impl ComputedValueVecsFromDateIndex {
)?,
bitcoin: ComputedVecsFromDateIndex::forced_import(
db,
&format!("{name}_in_btc"),
&format!("{name}_btc"),
Source::Compute,
version + VERSION,
indexes,
@@ -52,7 +51,7 @@ impl ComputedValueVecsFromDateIndex {
dollars: compute_dollars.then(|| {
ComputedVecsFromDateIndex::forced_import(
db,
&format!("{name}_in_usd"),
&format!("{name}_usd"),
Source::Compute,
version + VERSION,
indexes,
@@ -65,40 +64,24 @@ impl ComputedValueVecsFromDateIndex {
pub fn compute_all<F>(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
exit: &Exit,
mut compute: F,
) -> Result<()>
where
F: FnMut(
&mut EagerVec<DateIndex, Sats>,
&Indexer,
&indexes::Vecs,
&Indexes,
&Exit,
) -> Result<()>,
F: FnMut(&mut EagerVec<DateIndex, Sats>) -> Result<()>,
{
compute(
self.sats.dateindex.as_mut().unwrap(),
indexer,
indexes,
starting_indexes,
exit,
)?;
compute(self.sats.dateindex.as_mut().unwrap())?;
let dateindex: Option<&StoredVec<DateIndex, Sats>> = None;
self.compute_rest(indexer, indexes, price, starting_indexes, exit, dateindex)?;
self.compute_rest(price, starting_indexes, exit, dateindex)?;
Ok(())
}
pub fn compute_rest(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
exit: &Exit,
@@ -108,72 +91,50 @@ impl ComputedValueVecsFromDateIndex {
self.sats
.compute_rest(starting_indexes, exit, Some(dateindex))?;
self.bitcoin.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_from_sats(starting_indexes.dateindex, dateindex, exit)
},
)?;
self.bitcoin.compute_all(starting_indexes, exit, |v| {
v.compute_from_sats(starting_indexes.dateindex, dateindex, exit)
})?;
} else {
let dateindex: Option<&StoredVec<DateIndex, Sats>> = None;
self.sats.compute_rest(starting_indexes, exit, dateindex)?;
self.bitcoin.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_from_sats(
starting_indexes.dateindex,
self.sats.dateindex.as_ref().unwrap(),
exit,
)
},
)?;
self.bitcoin.compute_all(starting_indexes, exit, |v| {
v.compute_from_sats(
starting_indexes.dateindex,
self.sats.dateindex.as_ref().unwrap(),
exit,
)
})?;
}
let dateindex_to_bitcoin = self.bitcoin.dateindex.as_ref().unwrap();
let dateindex_to_close = price
let dateindex_to_price_close = price
.as_ref()
.unwrap()
.timeindexes_to_close
.timeindexes_to_price_close
.dateindex
.as_ref()
.unwrap();
if let Some(dollars) = self.dollars.as_mut() {
dollars.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_from_bitcoin(
starting_indexes.dateindex,
dateindex_to_bitcoin,
dateindex_to_close,
exit,
)
},
)?;
dollars.compute_all(starting_indexes, exit, |v| {
v.compute_from_bitcoin(
starting_indexes.dateindex,
dateindex_to_bitcoin,
dateindex_to_price_close,
exit,
)
})?;
}
Ok(())
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
[
self.sats.vecs(),
self.bitcoin.vecs(),
self.dollars.as_ref().map_or(vec![], |v| v.vecs()),
]
.into_iter()
.flatten()
.collect::<Vec<_>>()
pub fn iter_any_collectable(&self) -> impl Iterator<Item = &dyn AnyCollectableVec> {
std::iter::empty()
.chain(self.sats.iter_any_collectable())
.chain(self.bitcoin.iter_any_collectable())
.chain(self.dollars.iter().flat_map(|v| v.iter_any_collectable()))
}
}
@@ -1,5 +1,5 @@
use allocative::Allocative;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_structs::{Bitcoin, Dollars, Height, Sats, Version};
use vecdb::{AnyCollectableVec, CollectableVec, Database, EagerVec, Exit, StoredVec};
@@ -12,7 +12,7 @@ use crate::{
use super::{ComputedVecsFromHeight, VecBuilderOptions};
#[derive(Clone)]
#[derive(Clone, Allocative)]
pub struct ComputedValueVecsFromHeight {
pub sats: ComputedVecsFromHeight<Sats>,
pub bitcoin: ComputedVecsFromHeight<Bitcoin>,
@@ -43,7 +43,7 @@ impl ComputedValueVecsFromHeight {
)?,
bitcoin: ComputedVecsFromHeight::forced_import(
db,
&format!("{name}_in_btc"),
&format!("{name}_btc"),
Source::Compute,
version + VERSION,
indexes,
@@ -52,7 +52,7 @@ impl ComputedValueVecsFromHeight {
dollars: compute_dollars.then(|| {
ComputedVecsFromHeight::forced_import(
db,
&format!("{name}_in_usd"),
&format!("{name}_usd"),
Source::Compute,
version + VERSION,
indexes,
@@ -65,7 +65,6 @@ impl ComputedValueVecsFromHeight {
pub fn compute_all<F>(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
@@ -73,31 +72,18 @@ impl ComputedValueVecsFromHeight {
mut compute: F,
) -> Result<()>
where
F: FnMut(
&mut EagerVec<Height, Sats>,
&Indexer,
&indexes::Vecs,
&Indexes,
&Exit,
) -> Result<()>,
F: FnMut(&mut EagerVec<Height, Sats>) -> Result<()>,
{
compute(
self.sats.height.as_mut().unwrap(),
indexer,
indexes,
starting_indexes,
exit,
)?;
compute(self.sats.height.as_mut().unwrap())?;
let height: Option<&StoredVec<Height, Sats>> = None;
self.compute_rest(indexer, indexes, price, starting_indexes, exit, height)?;
self.compute_rest(indexes, price, starting_indexes, exit, height)?;
Ok(())
}
pub fn compute_rest(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
@@ -108,67 +94,47 @@ impl ComputedValueVecsFromHeight {
self.sats
.compute_rest(indexes, starting_indexes, exit, Some(height))?;
self.bitcoin.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
self.bitcoin
.compute_all(indexes, starting_indexes, exit, |v| {
v.compute_from_sats(starting_indexes.height, height, exit)
},
)?;
})?;
} else {
let height: Option<&StoredVec<Height, Sats>> = None;
self.sats
.compute_rest(indexes, starting_indexes, exit, height)?;
self.bitcoin.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
self.bitcoin
.compute_all(indexes, starting_indexes, exit, |v| {
v.compute_from_sats(
starting_indexes.height,
self.sats.height.as_ref().unwrap(),
exit,
)
},
)?;
})?;
}
let height_to_bitcoin = self.bitcoin.height.as_ref().unwrap();
let height_to_close = &price.as_ref().unwrap().chainindexes_to_close.height;
let height_to_price_close = &price.as_ref().unwrap().chainindexes_to_price_close.height;
if let Some(dollars) = self.dollars.as_mut() {
dollars.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_from_bitcoin(
starting_indexes.height,
height_to_bitcoin,
height_to_close,
exit,
)
},
)?;
dollars.compute_all(indexes, starting_indexes, exit, |v| {
v.compute_from_bitcoin(
starting_indexes.height,
height_to_bitcoin,
height_to_price_close,
exit,
)
})?;
}
Ok(())
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
[
self.sats.vecs(),
self.bitcoin.vecs(),
self.dollars.as_ref().map_or(vec![], |v| v.vecs()),
]
.into_iter()
.flatten()
.collect::<Vec<_>>()
pub fn iter_any_collectable(&self) -> impl Iterator<Item = &dyn AnyCollectableVec> {
std::iter::empty()
.chain(self.sats.iter_any_collectable())
.chain(self.bitcoin.iter_any_collectable())
.chain(self.dollars.iter().flat_map(|v| v.iter_any_collectable()))
}
}
@@ -1,3 +1,4 @@
use allocative::Allocative;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_structs::{Bitcoin, Close, Dollars, Height, Sats, TxIndex, Version};
@@ -10,7 +11,7 @@ use crate::{Indexes, grouped::Source, indexes, price};
use super::{ComputedVecsFromTxindex, VecBuilderOptions};
#[derive(Clone)]
#[derive(Clone, Allocative)]
pub struct ComputedValueVecsFromTxindex {
pub sats: ComputedVecsFromTxindex<Sats>,
pub bitcoin_txindex: LazyVecFrom1<TxIndex, Bitcoin, TxIndex, Sats>,
@@ -37,8 +38,8 @@ impl ComputedValueVecsFromTxindex {
) -> Result<Self> {
let compute_dollars = price.is_some();
let name_in_btc = format!("{name}_in_btc");
let name_in_usd = format!("{name}_in_usd");
let name_btc = format!("{name}_btc");
let name_usd = format!("{name}_usd");
let sats = ComputedVecsFromTxindex::forced_import(
db,
@@ -52,7 +53,7 @@ impl ComputedValueVecsFromTxindex {
let source_vec = source.vec();
let bitcoin_txindex = LazyVecFrom1::init(
&name_in_btc,
&name_btc,
version + VERSION,
source_vec.map_or_else(|| sats.txindex.as_ref().unwrap().boxed_clone(), |s| s),
|txindex: TxIndex, iter| {
@@ -65,7 +66,7 @@ impl ComputedValueVecsFromTxindex {
let bitcoin = ComputedVecsFromTxindex::forced_import(
db,
&name_in_btc,
&name_btc,
Source::None,
version + VERSION,
indexes,
@@ -74,15 +75,15 @@ impl ComputedValueVecsFromTxindex {
let dollars_txindex = price.map(|price| {
LazyVecFrom3::init(
&name_in_usd,
&name_usd,
version + VERSION,
bitcoin_txindex.boxed_clone(),
indexes.txindex_to_height.boxed_clone(),
price.chainindexes_to_close.height.boxed_clone(),
price.chainindexes_to_price_close.height.boxed_clone(),
|txindex: TxIndex,
txindex_to_btc_iter,
txindex_to_height_iter,
height_to_close_iter| {
height_to_price_close_iter| {
let txindex = txindex.unwrap_to_usize();
txindex_to_btc_iter.next_at(txindex).and_then(|(_, value)| {
let btc = value.into_owned();
@@ -90,7 +91,7 @@ impl ComputedValueVecsFromTxindex {
.next_at(txindex)
.and_then(|(_, value)| {
let height = value.into_owned();
height_to_close_iter
height_to_price_close_iter
.next_at(height.unwrap_to_usize())
.map(|(_, close)| *close.into_owned() * btc)
})
@@ -107,7 +108,7 @@ impl ComputedValueVecsFromTxindex {
dollars: compute_dollars.then(|| {
ComputedVecsFromTxindex::forced_import(
db,
&name_in_usd,
&name_usd,
Source::None,
version + VERSION,
indexes,
@@ -201,18 +202,16 @@ impl ComputedValueVecsFromTxindex {
Ok(())
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
[
self.sats.vecs(),
vec![&self.bitcoin_txindex as &dyn AnyCollectableVec],
self.bitcoin.vecs(),
self.dollars_txindex
.as_ref()
.map_or(vec![], |v| vec![v as &dyn AnyCollectableVec]),
self.dollars.as_ref().map_or(vec![], |v| v.vecs()),
]
.into_iter()
.flatten()
.collect::<Vec<_>>()
pub fn iter_any_collectable(&self) -> impl Iterator<Item = &dyn AnyCollectableVec> {
[&self.bitcoin_txindex as &dyn AnyCollectableVec]
.into_iter()
.chain(self.sats.iter_any_collectable())
.chain(self.bitcoin.iter_any_collectable())
.chain(
self.dollars_txindex
.iter()
.map(|v| v as &dyn AnyCollectableVec),
)
.chain(self.dollars.iter().flat_map(|v| v.iter_any_collectable()))
}
}
+12 -31
View File
@@ -1,12 +1,11 @@
use brk_error::Result;
use brk_indexer::Indexer;
use brk_structs::{Bitcoin, Dollars, Height, Sats, Version};
use vecdb::{AnyCollectableVec, CollectableVec, Database, EagerVec, Exit, Format, StoredVec};
use crate::{
Indexes,
grouped::Source,
indexes, price,
price,
traits::{ComputeFromBitcoin, ComputeFromSats},
};
@@ -35,14 +34,14 @@ impl ComputedHeightValueVecs {
}),
bitcoin: EagerVec::forced_import(
db,
&format!("{name}_in_btc"),
&format!("{name}_btc"),
version + VERSION + Version::ZERO,
format,
)?,
dollars: compute_dollars.then(|| {
EagerVec::forced_import(
db,
&format!("{name}_in_usd"),
&format!("{name}_usd"),
version + VERSION + Version::ZERO,
format,
)
@@ -53,29 +52,15 @@ impl ComputedHeightValueVecs {
pub fn compute_all<F>(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
exit: &Exit,
mut compute: F,
) -> Result<()>
where
F: FnMut(
&mut EagerVec<Height, Sats>,
&Indexer,
&indexes::Vecs,
&Indexes,
&Exit,
) -> Result<()>,
F: FnMut(&mut EagerVec<Height, Sats>) -> Result<()>,
{
compute(
self.sats.as_mut().unwrap(),
indexer,
indexes,
starting_indexes,
exit,
)?;
compute(self.sats.as_mut().unwrap())?;
let height: Option<&StoredVec<Height, Sats>> = None;
self.compute_rest(price, starting_indexes, exit, height)?;
@@ -102,13 +87,13 @@ impl ComputedHeightValueVecs {
}
let height_to_bitcoin = &self.bitcoin;
let height_to_close = &price.as_ref().unwrap().chainindexes_to_close.height;
let height_to_price_close = &price.as_ref().unwrap().chainindexes_to_price_close.height;
if let Some(dollars) = self.dollars.as_mut() {
dollars.compute_from_bitcoin(
starting_indexes.height,
height_to_bitcoin,
height_to_close,
height_to_price_close,
exit,
)?;
}
@@ -116,14 +101,10 @@ impl ComputedHeightValueVecs {
Ok(())
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
[
vec![&self.bitcoin as &dyn AnyCollectableVec],
self.sats.as_ref().map_or(vec![], |v| vec![v]),
self.dollars.as_ref().map_or(vec![], |v| vec![v]),
]
.into_iter()
.flatten()
.collect::<Vec<_>>()
pub fn iter_any_collectable(&self) -> impl Iterator<Item = &dyn AnyCollectableVec> {
[&self.bitcoin as &dyn AnyCollectableVec]
.into_iter()
.chain(self.sats.iter().map(|v| v as &dyn AnyCollectableVec))
.chain(self.dollars.iter().map(|v| v as &dyn AnyCollectableVec))
}
}
+14 -5
View File
@@ -236,7 +236,7 @@ impl Vecs {
|index, _| Some(index),
);
Ok(Self {
let this = Self {
emptyoutputindex_to_emptyoutputindex,
inputindex_to_inputindex,
opreturnindex_to_opreturnindex,
@@ -472,7 +472,15 @@ impl Vecs {
)?,
db,
})
};
this.db.retain_regions(
this.iter_any_collectable()
.flat_map(|v| v.region_names())
.collect(),
)?;
Ok(this)
}
pub fn compute(
@@ -925,9 +933,9 @@ impl Vecs {
})
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
vec![
&self.dateindex_to_date,
pub fn iter_any_collectable(&self) -> impl Iterator<Item = &dyn AnyCollectableVec> {
[
&self.dateindex_to_date as &dyn AnyCollectableVec,
&self.dateindex_to_dateindex,
&self.dateindex_to_first_height,
&self.dateindex_to_height_count,
@@ -988,6 +996,7 @@ impl Vecs {
&self.yearindex_to_yearindex,
&self.outputindex_to_txindex,
]
.into_iter()
}
}
+91 -53
View File
@@ -9,23 +9,23 @@ use brk_structs::Version;
use log::info;
use vecdb::{AnyCollectableVec, Exit, Format};
mod blocks;
mod chain;
mod cointime;
mod constants;
mod fetched;
mod grouped;
mod indexes;
mod market;
mod mining;
mod pools;
mod price;
mod stateful;
mod states;
mod traits;
mod transactions;
mod utils;
use indexes::Indexes;
pub use pools::*;
pub use states::PriceToAmount;
use states::*;
@@ -33,17 +33,16 @@ use states::*;
pub struct Computer {
pub indexes: indexes::Vecs,
pub constants: constants::Vecs,
pub blocks: blocks::Vecs,
pub mining: mining::Vecs,
pub market: market::Vecs,
pub pools: pools::Vecs,
pub price: Option<price::Vecs>,
pub transactions: transactions::Vecs,
pub chain: chain::Vecs,
pub stateful: stateful::Vecs,
pub fetched: Option<fetched::Vecs>,
pub cointime: cointime::Vecs,
}
const VERSION: Version = Version::TWO;
const VERSION: Version = Version::new(4);
impl Computer {
/// Do NOT import multiple times or things will break !!!
@@ -52,6 +51,8 @@ impl Computer {
indexer: &Indexer,
fetcher: Option<Fetcher>,
) -> Result<Self> {
info!("Importing computer...");
let computed_path = outputs_path.join("computed");
let indexes =
@@ -66,8 +67,6 @@ impl Computer {
});
Ok(Self {
blocks: blocks::Vecs::forced_import(&computed_path, VERSION + Version::ZERO, &indexes)?,
mining: mining::Vecs::forced_import(&computed_path, VERSION + Version::ZERO, &indexes)?,
constants: constants::Vecs::forced_import(
&computed_path,
VERSION + Version::ZERO,
@@ -81,13 +80,19 @@ impl Computer {
&indexes,
price.as_ref(),
)?,
transactions: transactions::Vecs::forced_import(
chain: chain::Vecs::forced_import(
&computed_path,
VERSION + Version::ZERO,
indexer,
&indexes,
price.as_ref(),
)?,
pools: pools::Vecs::forced_import(
&computed_path,
VERSION + Version::ZERO,
&indexes,
price.as_ref(),
)?,
cointime: cointime::Vecs::forced_import(
&computed_path,
VERSION + Version::ZERO,
@@ -111,15 +116,7 @@ impl Computer {
info!("Computing constants...");
self.constants
.compute(indexer, &self.indexes, &starting_indexes, exit)?;
info!("Computing blocks...");
self.blocks
.compute(indexer, &self.indexes, &starting_indexes, exit)?;
info!("Computing mining...");
self.mining
.compute(indexer, &self.indexes, &starting_indexes, exit)?;
.compute(&self.indexes, &starting_indexes, exit)?;
if let Some(fetched) = self.fetched.as_mut() {
info!("Computing fetched...");
@@ -127,7 +124,6 @@ impl Computer {
info!("Computing prices...");
self.price.as_mut().unwrap().compute(
indexer,
&self.indexes,
&starting_indexes,
fetched,
@@ -135,44 +131,55 @@ impl Computer {
)?;
}
info!("Computing transactions...");
self.transactions.compute(
std::thread::scope(|scope| -> Result<()> {
let chain = scope.spawn(|| -> Result<()> {
info!("Computing chain...");
self.chain.compute(
indexer,
&self.indexes,
&starting_indexes,
self.price.as_ref(),
exit,
)?;
Ok(())
});
if let Some(price) = self.price.as_ref() {
info!("Computing market...");
self.market.compute(price, &starting_indexes, exit)?;
}
chain.join().unwrap()?;
Ok(())
})?;
self.pools.compute(
indexer,
&self.indexes,
&starting_indexes,
&self.chain,
self.price.as_ref(),
exit,
)?;
if let Some(price) = self.price.as_ref() {
info!("Computing market...");
self.market.compute(
indexer,
&self.indexes,
price,
&mut self.transactions,
&starting_indexes,
exit,
)?;
}
// return Ok(());
info!("Computing stateful...");
self.stateful.compute(
indexer,
&self.indexes,
&self.transactions,
&self.chain,
self.price.as_ref(),
&self.market,
&mut starting_indexes,
exit,
)?;
info!("Computing cointime...");
self.cointime.compute(
indexer,
&self.indexes,
&starting_indexes,
self.price.as_ref(),
&self.transactions,
&self.chain,
&self.stateful,
exit,
)?;
@@ -180,25 +187,56 @@ impl Computer {
Ok(())
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
[
self.constants.vecs(),
self.indexes.vecs(),
self.blocks.vecs(),
self.mining.vecs(),
self.market.vecs(),
self.transactions.vecs(),
self.stateful.vecs(),
self.cointime.vecs(),
self.fetched.as_ref().map_or(vec![], |v| v.vecs()),
self.price.as_ref().map_or(vec![], |v| v.vecs()),
]
.into_iter()
.flatten()
.collect::<Vec<_>>()
pub fn iter_any_collectable(&self) -> impl Iterator<Item = &dyn AnyCollectableVec> {
let mut iter: Box<dyn Iterator<Item = &dyn AnyCollectableVec>> =
Box::new(self.fetched.iter().flat_map(|v| v.iter_any_collectable()));
iter = Box::new(iter.chain(self.price.iter().flat_map(|v| v.iter_any_collectable())));
iter = Box::new(iter.chain(self.pools.iter_any_collectable()));
iter = Box::new(iter.chain(self.constants.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes.iter_any_collectable()));
iter = Box::new(iter.chain(self.market.iter_any_collectable()));
iter = Box::new(iter.chain(self.chain.iter_any_collectable()));
iter = Box::new(iter.chain(self.stateful.iter_any_collectable()));
iter = Box::new(iter.chain(self.cointime.iter_any_collectable()));
iter
}
pub fn static_clone(&self) -> &'static Self {
Box::leak(Box::new(self.clone()))
}
}
// pub fn generate_allocation_files(monitored: &pools::Vecs) -> Result<()> {
// info!("Generating Allocative files...");
// let mut flamegraph = allocative::FlameGraphBuilder::default();
// flamegraph.visit_root(monitored);
// let output = flamegraph.finish();
// let folder = format!(
// "at-{}",
// jiff::Timestamp::now().strftime("%Y-%m-%d_%Hh%Mm%Ss"),
// );
// let path = std::path::PathBuf::from(&format!("./target/flamegraph/{folder}"));
// std::fs::create_dir_all(&path)?;
// // fs::write(path.join("flamegraph.src"), &output.flamegraph())?;
// let mut fg_svg = Vec::new();
// inferno::flamegraph::from_reader(
// &mut inferno::flamegraph::Options::default(),
// output.flamegraph().write().as_bytes(),
// &mut fg_svg,
// )?;
// std::fs::write(path.join("flamegraph.svg"), &fg_svg)?;
// std::fs::write(path.join("warnings.txt"), output.warnings())?;
// info!("Successfully generated Allocative files");
// Ok(())
// }
File diff suppressed because it is too large Load Diff
-151
View File
@@ -1,151 +0,0 @@
use std::path::Path;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_structs::{DifficultyEpoch, HalvingEpoch, StoredF64, Version};
use vecdb::{AnyCollectableVec, Database, Exit, PAGE_SIZE, VecIterator};
use crate::grouped::Source;
use super::{
Indexes,
grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, VecBuilderOptions},
indexes,
};
const VERSION: Version = Version::ZERO;
#[derive(Clone)]
pub struct Vecs {
db: Database,
pub indexes_to_difficulty: ComputedVecsFromHeight<StoredF64>,
pub indexes_to_difficultyepoch: ComputedVecsFromDateIndex<DifficultyEpoch>,
pub indexes_to_halvingepoch: ComputedVecsFromDateIndex<HalvingEpoch>,
}
impl Vecs {
pub fn forced_import(parent: &Path, version: Version, indexes: &indexes::Vecs) -> Result<Self> {
let db = Database::open(&parent.join("mining"))?;
db.set_min_len(PAGE_SIZE * 1_000_000)?;
Ok(Self {
indexes_to_difficulty: ComputedVecsFromHeight::forced_import(
&db,
"difficulty",
Source::None,
version + VERSION + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_difficultyepoch: ComputedVecsFromDateIndex::forced_import(
&db,
"difficultyepoch",
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_halvingepoch: ComputedVecsFromDateIndex::forced_import(
&db,
"halvingepoch",
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
db,
})
}
pub fn compute(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.compute_(indexer, indexes, starting_indexes, exit)?;
self.db.flush_then_punch()?;
Ok(())
}
fn compute_(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
let mut height_to_difficultyepoch_iter = indexes.height_to_difficultyepoch.into_iter();
self.indexes_to_difficultyepoch.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, indexes, starting_indexes, exit| {
let mut height_count_iter = indexes.dateindex_to_height_count.into_iter();
vec.compute_transform(
starting_indexes.dateindex,
&indexes.dateindex_to_first_height,
|(di, height, ..)| {
(
di,
height_to_difficultyepoch_iter.unwrap_get_inner(
height + (*height_count_iter.unwrap_get_inner(di) - 1),
),
)
},
exit,
)?;
Ok(())
},
)?;
let mut height_to_halvingepoch_iter = indexes.height_to_halvingepoch.into_iter();
self.indexes_to_halvingepoch.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, indexes, starting_indexes, exit| {
let mut height_count_iter = indexes.dateindex_to_height_count.into_iter();
vec.compute_transform(
starting_indexes.dateindex,
&indexes.dateindex_to_first_height,
|(di, height, ..)| {
(
di,
height_to_halvingepoch_iter.unwrap_get_inner(
height + (*height_count_iter.unwrap_get_inner(di) - 1),
),
)
},
exit,
)?;
Ok(())
},
)?;
self.indexes_to_difficulty.compute_rest(
indexes,
starting_indexes,
exit,
Some(&indexer.vecs.height_to_difficulty),
)?;
Ok(())
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
[
self.indexes_to_difficulty.vecs(),
self.indexes_to_difficultyepoch.vecs(),
self.indexes_to_halvingepoch.vecs(),
]
.into_iter()
.flatten()
.collect::<Vec<_>>()
}
}
+287
View File
@@ -0,0 +1,287 @@
use allocative::Allocative;
use num_enum::{FromPrimitive, IntoPrimitive};
use serde::{Deserialize, Serialize};
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
// Created from the list in `pools.rs`
// Can be used as index for said list
#[allow(clippy::upper_case_acronyms)]
#[derive(
Debug,
Copy,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Serialize,
Deserialize,
FromPrimitive,
IntoPrimitive,
FromBytes,
IntoBytes,
Immutable,
KnownLayout,
Allocative,
)]
#[serde(rename_all = "lowercase")]
#[repr(u8)]
pub enum PoolId {
#[default]
Unknown,
BlockFills,
UltimusPool,
TerraPool,
Luxor,
OneThash,
BtcCom,
Bitfarms,
HuobiPool,
WayiCn,
CanoePool,
BtcTop,
BitcoinCom,
Pool175btc,
GbMiners,
AXbt,
AsicMiner,
BitMinter,
BitcoinRussia,
BtcServ,
SimplecoinUs,
BtcGuild,
Eligius,
OzCoin,
EclipseMc,
MaxBtc,
TripleMining,
CoinLab,
Pool50btc,
GhashIo,
StMiningCorp,
Bitparking,
Mmpool,
Polmine,
KncMiner,
Bitalo,
F2Pool,
Hhtt,
MegaBigPower,
MtRed,
NmcBit,
YourbtcNet,
GiveMeCoins,
BraiinsPool,
AntPool,
MultiCoinCo,
BcpoolIo,
Cointerra,
KanoPool,
SoloCk,
CkPool,
NiceHash,
BitClub,
BitcoinAffiliateNetwork,
Btcc,
BwPool,
ExxBw,
Bitsolo,
BitFury,
TwentyOneInc,
DigitalBtc,
EightBaochi,
MyBtcCoinPool,
TbDice,
HashPool,
Nexious,
BravoMining,
HotPool,
OkExPool,
BcMonster,
OneHash,
Bixin,
TatmasPool,
ViaBtc,
ConnectBtc,
BatPool,
Waterhole,
DcExploration,
Dcex,
BtPool,
FiftyEightCoin,
BitcoinIndia,
ShawnP0wers,
PHashIo,
RigPool,
HaoZhuZhu,
SevenPool,
MiningKings,
HashBx,
DPool,
Rawpool,
Haominer,
Helix,
BitcoinUkraine,
Poolin,
SecretSuperstar,
TigerpoolNet,
SigmapoolCom,
OkpoolTop,
Hummerpool,
Tangpool,
BytePool,
SpiderPool,
NovaBlock,
MiningCity,
BinancePool,
Minerium,
LubianCom,
Okkong,
AaoPool,
EmcdPool,
FoundryUsa,
SbiCrypto,
ArkPool,
PureBtcCom,
MaraPool,
KuCoinPool,
EntrustCharityPool,
OkMiner,
Titan,
PegaPool,
BtcNuggets,
CloudHashing,
DigitalXMintsy,
Telco214,
BtcPoolParty,
Multipool,
TransactionCoinMining,
BtcDig,
TrickysBtcPool,
BtcMp,
Eobot,
Unomp,
Patels,
GoGreenLight,
EkanemBtc,
Canoe,
Tiger,
OneM1x,
Zulupool,
SecPool,
Ocean,
WhitePool,
Wk057,
FutureBitApolloSolo,
CarbonNegative,
PortlandHodl,
Phoenix,
Neopool,
MaxiPool,
BitFuFuPool,
LuckyPool,
MiningDutch,
PublicPool,
MiningSquared,
InnopolisTech,
BtcLab,
Parasite,
Dummy158,
Dummy159,
Dummy160,
Dummy161,
Dummy162,
Dummy163,
Dummy164,
Dummy165,
Dummy166,
Dummy167,
Dummy168,
Dummy169,
Dummy170,
Dummy171,
Dummy172,
Dummy173,
Dummy174,
Dummy175,
Dummy176,
Dummy177,
Dummy178,
Dummy179,
Dummy180,
Dummy181,
Dummy182,
Dummy183,
Dummy184,
Dummy185,
Dummy186,
Dummy187,
Dummy188,
Dummy189,
Dummy190,
Dummy191,
Dummy192,
Dummy193,
Dummy194,
Dummy195,
Dummy196,
Dummy197,
Dummy198,
Dummy199,
Dummy200,
Dummy201,
Dummy202,
Dummy203,
Dummy204,
Dummy205,
Dummy206,
Dummy207,
Dummy208,
Dummy209,
Dummy210,
Dummy211,
Dummy212,
Dummy213,
Dummy214,
Dummy215,
Dummy216,
Dummy217,
Dummy218,
Dummy219,
Dummy220,
Dummy221,
Dummy222,
Dummy223,
Dummy224,
Dummy225,
Dummy226,
Dummy227,
Dummy228,
Dummy229,
Dummy230,
Dummy231,
Dummy232,
Dummy233,
Dummy234,
Dummy235,
Dummy236,
Dummy237,
Dummy238,
Dummy239,
Dummy240,
Dummy241,
Dummy242,
Dummy243,
Dummy244,
Dummy245,
Dummy246,
Dummy247,
Dummy248,
Dummy249,
Dummy250,
Dummy251,
Dummy252,
Dummy253,
Dummy254,
Dummy255,
}
+235
View File
@@ -0,0 +1,235 @@
use std::{collections::BTreeMap, path::Path};
use allocative::Allocative;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_store::AnyStore;
use brk_structs::{AddressBytes, Height, OutputIndex, OutputType};
use rayon::prelude::*;
use vecdb::{
AnyCollectableVec, AnyIterableVec, AnyStoredVec, AnyVec, Database, Exit, GenericStoredVec,
PAGE_SIZE, RawVec, StoredIndex, VecIterator, Version,
};
mod id;
mod pool;
#[allow(clippy::module_inception)]
mod pools;
mod vecs;
pub use id::*;
pub use pool::*;
pub use pools::*;
use crate::{
chain,
indexes::{self, Indexes},
price,
};
#[derive(Clone, Allocative)]
pub struct Vecs {
db: Database,
pools: &'static Pools,
height_to_pool: RawVec<Height, PoolId>,
vecs: BTreeMap<PoolId, vecs::Vecs>,
}
impl Vecs {
pub fn forced_import(
parent_path: &Path,
parent_version: Version,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
) -> Result<Self> {
let db = Database::open(&parent_path.join("pools"))?;
db.set_min_len(PAGE_SIZE * 1_000_000)?;
let pools = pools();
let version = parent_version + Version::new(3) + Version::new(pools.len() as u64);
let this = Self {
height_to_pool: RawVec::forced_import(&db, "pool", version + Version::ZERO)?,
vecs: pools
.iter()
.map(|pool| {
vecs::Vecs::forced_import(
&db,
pool.id,
pools,
version + Version::ZERO,
indexes,
price,
)
.map(|vecs| (pool.id, vecs))
})
.collect::<Result<BTreeMap<_, _>>>()?,
pools,
db,
};
this.db.retain_regions(
this.iter_any_collectable()
.flat_map(|v| v.region_names())
.collect(),
)?;
Ok(this)
}
pub fn compute(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
chain: &chain::Vecs,
price: Option<&price::Vecs>,
exit: &Exit,
) -> Result<()> {
self.compute_(indexer, indexes, starting_indexes, chain, price, exit)?;
self.db.flush_then_punch()?;
Ok(())
}
fn compute_(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
chain: &chain::Vecs,
price: Option<&price::Vecs>,
exit: &Exit,
) -> Result<()> {
self.compute_height_to_pool(indexer, indexes, starting_indexes, exit)?;
self.vecs.par_iter_mut().try_for_each(|(_, vecs)| {
vecs.compute(
indexes,
starting_indexes,
&self.height_to_pool,
chain,
price,
exit,
)
})?;
Ok(())
}
fn compute_height_to_pool(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.height_to_pool.validate_computed_version_or_reset(
self.height_to_pool.version() + indexer.stores.height_to_coinbase_tag.version(),
)?;
let mut height_to_first_txindex_iter = indexer.vecs.height_to_first_txindex.iter();
let mut txindex_to_first_outputindex_iter =
indexer.vecs.txindex_to_first_outputindex.iter();
let mut txindex_to_output_count_iter = indexes.txindex_to_output_count.iter();
let mut outputindex_to_outputtype_iter = indexer.vecs.outputindex_to_outputtype.iter();
let mut outputindex_to_typeindex_iter = indexer.vecs.outputindex_to_typeindex.iter();
let mut p2pk65addressindex_to_p2pk65bytes_iter =
indexer.vecs.p2pk65addressindex_to_p2pk65bytes.iter();
let mut p2pk33addressindex_to_p2pk33bytes_iter =
indexer.vecs.p2pk33addressindex_to_p2pk33bytes.iter();
let mut p2pkhaddressindex_to_p2pkhbytes_iter =
indexer.vecs.p2pkhaddressindex_to_p2pkhbytes.iter();
let mut p2shaddressindex_to_p2shbytes_iter =
indexer.vecs.p2shaddressindex_to_p2shbytes.iter();
let mut p2wpkhaddressindex_to_p2wpkhbytes_iter =
indexer.vecs.p2wpkhaddressindex_to_p2wpkhbytes.iter();
let mut p2wshaddressindex_to_p2wshbytes_iter =
indexer.vecs.p2wshaddressindex_to_p2wshbytes.iter();
let mut p2traddressindex_to_p2trbytes_iter =
indexer.vecs.p2traddressindex_to_p2trbytes.iter();
let mut p2aaddressindex_to_p2abytes_iter = indexer.vecs.p2aaddressindex_to_p2abytes.iter();
let unknown = self.pools.get_unknown();
let min = starting_indexes
.height
.unwrap_to_usize()
.min(self.height_to_pool.len());
indexer
.stores
.height_to_coinbase_tag
.iter()
.skip(min)
.try_for_each(|(height, coinbase_tag)| -> Result<()> {
let txindex = height_to_first_txindex_iter.unwrap_get_inner(height);
let outputindex = txindex_to_first_outputindex_iter.unwrap_get_inner(txindex);
let outputcount = txindex_to_output_count_iter.unwrap_get_inner(txindex);
let pool = (*outputindex..(*outputindex + *outputcount))
.map(OutputIndex::from)
.find_map(|outputindex| {
let outputtype =
outputindex_to_outputtype_iter.unwrap_get_inner(outputindex);
let typeindex = outputindex_to_typeindex_iter.unwrap_get_inner(outputindex);
let address = match outputtype {
OutputType::P2PK65 => Some(AddressBytes::from(
p2pk65addressindex_to_p2pk65bytes_iter
.unwrap_get_inner(typeindex.into()),
)),
OutputType::P2PK33 => Some(AddressBytes::from(
p2pk33addressindex_to_p2pk33bytes_iter
.unwrap_get_inner(typeindex.into()),
)),
OutputType::P2PKH => Some(AddressBytes::from(
p2pkhaddressindex_to_p2pkhbytes_iter
.unwrap_get_inner(typeindex.into()),
)),
OutputType::P2SH => Some(AddressBytes::from(
p2shaddressindex_to_p2shbytes_iter
.unwrap_get_inner(typeindex.into()),
)),
OutputType::P2WPKH => Some(AddressBytes::from(
p2wpkhaddressindex_to_p2wpkhbytes_iter
.unwrap_get_inner(typeindex.into()),
)),
OutputType::P2WSH => Some(AddressBytes::from(
p2wshaddressindex_to_p2wshbytes_iter
.unwrap_get_inner(typeindex.into()),
)),
OutputType::P2TR => Some(AddressBytes::from(
p2traddressindex_to_p2trbytes_iter
.unwrap_get_inner(typeindex.into()),
)),
OutputType::P2A => Some(AddressBytes::from(
p2aaddressindex_to_p2abytes_iter.unwrap_get_inner(typeindex.into()),
)),
_ => None,
};
address
.and_then(|address| self.pools.find_from_address(&address.to_string()))
})
.or_else(|| self.pools.find_from_coinbase_tag(&coinbase_tag))
.unwrap_or(unknown);
self.height_to_pool.push_if_needed(height, pool.id)?;
Ok(())
})?;
self.height_to_pool.safe_flush(exit)?;
Ok(())
}
pub fn iter_any_collectable(&self) -> impl Iterator<Item = &dyn AnyCollectableVec> {
[&self.height_to_pool as &dyn AnyCollectableVec]
.into_iter()
.chain(
self.vecs
.iter()
.flat_map(|(_, vecs)| vecs.iter_any_collectable()),
)
}
}
+46
View File
@@ -0,0 +1,46 @@
use allocative::Allocative;
use crate::pools::PoolId;
#[derive(Debug, Allocative)]
pub struct Pool {
pub id: PoolId,
pub name: &'static str,
pub addresses: Box<[&'static str]>,
pub tags: Box<[&'static str]>,
pub tags_lowercase: Box<[String]>,
pub link: &'static str,
}
impl Pool {
pub fn serialized_id(&self) -> String {
let value = serde_json::to_value(self.id).unwrap();
value.as_str().unwrap().to_string()
}
}
impl From<(usize, JSONPool)> for Pool {
fn from((index, pool): (usize, JSONPool)) -> Self {
Self {
id: (index as u8).into(),
name: pool.name,
addresses: pool.addresses,
tags_lowercase: pool
.tags
.iter()
.map(|t| t.to_lowercase())
.collect::<Vec<_>>()
.into_boxed_slice(),
tags: pool.tags,
link: pool.link,
}
}
}
#[derive(Debug)]
pub struct JSONPool {
pub name: &'static str,
pub addresses: Box<[&'static str]>,
pub tags: Box<[&'static str]>,
pub link: &'static str,
}
File diff suppressed because it is too large Load Diff
+397
View File
@@ -0,0 +1,397 @@
use allocative::Allocative;
use brk_error::Result;
use brk_structs::{Height, Sats, StoredF32, StoredU16, StoredU32};
use vecdb::{AnyCollectableVec, AnyIterableVec, Database, Exit, StoredIndex, VecIterator, Version};
use crate::{
PoolId, Pools, chain,
grouped::{
ComputedValueVecsFromHeight, ComputedVecsFromDateIndex, ComputedVecsFromHeight, Source,
VecBuilderOptions,
},
indexes::{self, Indexes},
price,
};
#[derive(Clone, Allocative)]
pub struct Vecs {
id: PoolId,
indexes_to_blocks_mined: ComputedVecsFromHeight<StoredU32>,
indexes_to_1w_blocks_mined: ComputedVecsFromDateIndex<StoredU32>,
indexes_to_1m_blocks_mined: ComputedVecsFromDateIndex<StoredU32>,
indexes_to_1y_blocks_mined: ComputedVecsFromDateIndex<StoredU32>,
indexes_to_subsidy: ComputedValueVecsFromHeight,
indexes_to_fee: ComputedValueVecsFromHeight,
indexes_to_coinbase: ComputedValueVecsFromHeight,
indexes_to_dominance: ComputedVecsFromDateIndex<StoredF32>,
indexes_to_1d_dominance: ComputedVecsFromDateIndex<StoredF32>,
indexes_to_1w_dominance: ComputedVecsFromDateIndex<StoredF32>,
indexes_to_1m_dominance: ComputedVecsFromDateIndex<StoredF32>,
indexes_to_1y_dominance: ComputedVecsFromDateIndex<StoredF32>,
indexes_to_days_since_block: ComputedVecsFromDateIndex<StoredU16>,
}
impl Vecs {
pub fn forced_import(
db: &Database,
id: PoolId,
pools: &Pools,
parent_version: Version,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
) -> Result<Self> {
let pool = pools.get(id);
let name = pool.serialized_id();
let suffix = |s: &str| format!("{name}_{s}");
let compute_dollars = price.is_some();
let version = parent_version + Version::ZERO;
Ok(Self {
id,
indexes_to_blocks_mined: ComputedVecsFromHeight::forced_import(
db,
&suffix("blocks_mined"),
Source::Compute,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
)?,
indexes_to_1w_blocks_mined: ComputedVecsFromDateIndex::forced_import(
db,
&suffix("1w_blocks_mined"),
Source::Compute,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_1m_blocks_mined: ComputedVecsFromDateIndex::forced_import(
db,
&suffix("1m_blocks_mined"),
Source::Compute,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_1y_blocks_mined: ComputedVecsFromDateIndex::forced_import(
db,
&suffix("1y_blocks_mined"),
Source::Compute,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_subsidy: ComputedValueVecsFromHeight::forced_import(
db,
&suffix("subsidy"),
Source::Compute,
version + Version::ZERO,
VecBuilderOptions::default().add_sum().add_cumulative(),
compute_dollars,
indexes,
)?,
indexes_to_fee: ComputedValueVecsFromHeight::forced_import(
db,
&suffix("fee"),
Source::Compute,
version + Version::ZERO,
VecBuilderOptions::default().add_sum().add_cumulative(),
compute_dollars,
indexes,
)?,
indexes_to_coinbase: ComputedValueVecsFromHeight::forced_import(
db,
&suffix("coinbase"),
Source::Compute,
version + Version::ZERO,
VecBuilderOptions::default().add_sum().add_cumulative(),
compute_dollars,
indexes,
)?,
indexes_to_dominance: ComputedVecsFromDateIndex::forced_import(
db,
&suffix("dominance"),
Source::Compute,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_1d_dominance: ComputedVecsFromDateIndex::forced_import(
db,
&suffix("1d_dominance"),
Source::Compute,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_1w_dominance: ComputedVecsFromDateIndex::forced_import(
db,
&suffix("1w_dominance"),
Source::Compute,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_1m_dominance: ComputedVecsFromDateIndex::forced_import(
db,
&suffix("1m_dominance"),
Source::Compute,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_1y_dominance: ComputedVecsFromDateIndex::forced_import(
db,
&suffix("1y_dominance"),
Source::Compute,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_days_since_block: ComputedVecsFromDateIndex::forced_import(
db,
&suffix("days_since_block"),
Source::Compute,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_last(),
)?,
})
}
#[allow(clippy::too_many_arguments)]
pub fn compute(
&mut self,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
height_to_pool: &impl AnyIterableVec<Height, PoolId>,
chain: &chain::Vecs,
price: Option<&price::Vecs>,
exit: &Exit,
) -> Result<()> {
self.indexes_to_blocks_mined
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_transform(
starting_indexes.height,
height_to_pool,
|(h, id, ..)| {
(
h,
if id == self.id {
StoredU32::ONE
} else {
StoredU32::ZERO
},
)
},
exit,
)?;
Ok(())
})?;
self.indexes_to_1w_blocks_mined
.compute_all(starting_indexes, exit, |v| {
v.compute_sum(
starting_indexes.dateindex,
self.indexes_to_blocks_mined.dateindex.unwrap_sum(),
7,
exit,
)?;
Ok(())
})?;
self.indexes_to_1m_blocks_mined
.compute_all(starting_indexes, exit, |v| {
v.compute_sum(
starting_indexes.dateindex,
self.indexes_to_blocks_mined.dateindex.unwrap_sum(),
30,
exit,
)?;
Ok(())
})?;
self.indexes_to_1y_blocks_mined
.compute_all(starting_indexes, exit, |v| {
v.compute_sum(
starting_indexes.dateindex,
self.indexes_to_blocks_mined.dateindex.unwrap_sum(),
365,
exit,
)?;
Ok(())
})?;
let height_to_blocks_mined = self.indexes_to_blocks_mined.height.as_ref().unwrap();
self.indexes_to_subsidy
.compute_all(indexes, price, starting_indexes, exit, |vec| {
vec.compute_transform2(
starting_indexes.height,
height_to_blocks_mined,
chain.indexes_to_subsidy.sats.height.as_ref().unwrap(),
|(h, mined, sats, ..)| {
(
h,
if mined == StoredU32::ONE {
sats
} else {
Sats::ZERO
},
)
},
exit,
)?;
Ok(())
})?;
self.indexes_to_fee
.compute_all(indexes, price, starting_indexes, exit, |vec| {
vec.compute_transform2(
starting_indexes.height,
height_to_blocks_mined,
chain.indexes_to_fee.sats.height.unwrap_sum(),
|(h, mined, sats, ..)| {
(
h,
if mined == StoredU32::ONE {
sats
} else {
Sats::ZERO
},
)
},
exit,
)?;
Ok(())
})?;
self.indexes_to_coinbase
.compute_all(indexes, price, starting_indexes, exit, |vec| {
vec.compute_transform2(
starting_indexes.height,
height_to_blocks_mined,
chain.indexes_to_coinbase.sats.height.as_ref().unwrap(),
|(h, mined, sats, ..)| {
(
h,
if mined == StoredU32::ONE {
sats
} else {
Sats::ZERO
},
)
},
exit,
)?;
Ok(())
})?;
self.indexes_to_dominance
.compute_all(starting_indexes, exit, |vec| {
vec.compute_percentage(
starting_indexes.dateindex,
self.indexes_to_blocks_mined.dateindex.unwrap_cumulative(),
chain.indexes_to_block_count.dateindex.unwrap_cumulative(),
exit,
)?;
Ok(())
})?;
self.indexes_to_1d_dominance
.compute_all(starting_indexes, exit, |vec| {
vec.compute_percentage(
starting_indexes.dateindex,
self.indexes_to_blocks_mined.dateindex.unwrap_sum(),
chain.indexes_to_block_count.dateindex.unwrap_sum(),
exit,
)?;
Ok(())
})?;
self.indexes_to_1w_dominance
.compute_all(starting_indexes, exit, |vec| {
vec.compute_percentage(
starting_indexes.dateindex,
self.indexes_to_1w_blocks_mined.dateindex.as_ref().unwrap(),
chain.indexes_to_1w_block_count.dateindex.as_ref().unwrap(),
exit,
)?;
Ok(())
})?;
self.indexes_to_1m_dominance
.compute_all(starting_indexes, exit, |vec| {
vec.compute_percentage(
starting_indexes.dateindex,
self.indexes_to_1m_blocks_mined.dateindex.as_ref().unwrap(),
chain.indexes_to_1m_block_count.dateindex.as_ref().unwrap(),
exit,
)?;
Ok(())
})?;
self.indexes_to_1y_dominance
.compute_all(starting_indexes, exit, |vec| {
vec.compute_percentage(
starting_indexes.dateindex,
self.indexes_to_1y_blocks_mined.dateindex.as_ref().unwrap(),
chain.indexes_to_1y_block_count.dateindex.as_ref().unwrap(),
exit,
)?;
Ok(())
})?;
self.indexes_to_days_since_block
.compute_all(starting_indexes, exit, |v| {
let mut prev = None;
v.compute_transform2(
starting_indexes.dateindex,
self.indexes_to_blocks_mined.dateindex.unwrap_sum(),
self.indexes_to_blocks_mined.dateindex.unwrap_cumulative(),
|(i, sum, cumulative, slf)| {
if prev.is_none() {
let i = i.unwrap_to_usize();
prev.replace(if i > 0 {
slf.into_iter().unwrap_get_inner_(i - 1)
} else {
StoredU16::ZERO
});
}
let days = if !cumulative.is_zero() && sum.is_zero() {
prev.unwrap() + StoredU16::ONE
} else {
StoredU16::ZERO
};
prev.replace(days);
(i, days)
},
exit,
)?;
Ok(())
})?;
Ok(())
}
pub fn iter_any_collectable(&self) -> impl Iterator<Item = &dyn AnyCollectableVec> {
let mut iter: Box<dyn Iterator<Item = &dyn AnyCollectableVec>> =
Box::new(std::iter::empty());
iter = Box::new(iter.chain(self.indexes_to_blocks_mined.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_1w_blocks_mined.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_1m_blocks_mined.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_1y_blocks_mined.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_subsidy.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_fee.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_coinbase.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_dominance.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_1d_dominance.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_1w_dominance.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_1m_dominance.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_1y_dominance.iter_any_collectable()));
iter = Box::new(iter.chain(self.indexes_to_days_since_block.iter_any_collectable()));
iter
}
}
File diff suppressed because it is too large Load Diff
@@ -1,7 +1,6 @@
use std::{ops::Deref, path::Path};
use std::path::Path;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_structs::{Bitcoin, DateIndex, Dollars, Height, StoredU64, Version};
use vecdb::{
AnyCollectableVec, AnyIterableVec, AnyStoredVec, AnyVec, Database, EagerVec, Exit, Format,
@@ -11,7 +10,7 @@ use vecdb::{
use crate::{
Indexes,
grouped::{ComputedVecsFromHeight, Source, VecBuilderOptions},
indexes, market, price,
indexes, price,
stateful::{
common,
r#trait::{CohortVecs, DynCohortVecs},
@@ -29,8 +28,8 @@ pub struct Vecs {
pub inner: common::Vecs,
pub height_to_address_count: EagerVec<Height, StoredU64>,
pub indexes_to_address_count: ComputedVecsFromHeight<StoredU64>,
pub height_to_addr_count: EagerVec<Height, StoredU64>,
pub indexes_to_addr_count: ComputedVecsFromHeight<StoredU64>,
}
impl Vecs {
@@ -43,7 +42,7 @@ impl Vecs {
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
states_path: Option<&Path>,
compute_relative_to_all: bool,
compute_rel_to_all: bool,
) -> Result<Self> {
let compute_dollars = price.is_some();
@@ -58,15 +57,15 @@ impl Vecs {
compute_dollars,
)
}),
height_to_address_count: EagerVec::forced_import(
height_to_addr_count: EagerVec::forced_import(
db,
&suffix("address_count"),
&suffix("addr_count"),
version + VERSION + Version::ZERO,
format,
)?,
indexes_to_address_count: ComputedVecsFromHeight::forced_import(
indexes_to_addr_count: ComputedVecsFromHeight::forced_import(
db,
&suffix("address_count"),
&suffix("addr_count"),
Source::None,
version + VERSION + Version::ZERO,
indexes,
@@ -79,23 +78,27 @@ impl Vecs {
version,
indexes,
price,
compute_relative_to_all,
false,
compute_rel_to_all,
false,
)?,
})
}
pub fn iter_any_collectable(&self) -> impl Iterator<Item = &dyn AnyCollectableVec> {
self.inner
.iter_any_collectable()
.chain([&self.height_to_addr_count as &dyn AnyCollectableVec])
.chain(self.indexes_to_addr_count.iter_any_collectable())
}
}
impl DynCohortVecs for Vecs {
fn min_height_vecs_len(&self) -> usize {
[
self.height_to_address_count.len(),
std::cmp::min(
self.height_to_addr_count.len(),
self.inner.min_height_vecs_len(),
]
.into_iter()
.min()
.unwrap()
)
}
fn reset_state_starting_height(&mut self) {
@@ -110,8 +113,8 @@ impl DynCohortVecs for Vecs {
self.starting_height = Some(starting_height);
if let Some(prev_height) = starting_height.decremented() {
self.state.as_mut().unwrap().address_count = *self
.height_to_address_count
self.state.as_mut().unwrap().addr_count = *self
.height_to_addr_count
.into_iter()
.unwrap_get_inner(prev_height);
}
@@ -120,9 +123,9 @@ impl DynCohortVecs for Vecs {
}
fn validate_computed_versions(&mut self, base_version: Version) -> Result<()> {
self.height_to_address_count
self.height_to_addr_count
.validate_computed_version_or_reset(
base_version + self.height_to_address_count.inner_version(),
base_version + self.height_to_addr_count.inner_version(),
)?;
self.inner.validate_computed_versions(base_version)
@@ -133,9 +136,9 @@ impl DynCohortVecs for Vecs {
return Ok(());
}
self.height_to_address_count.forced_push_at(
self.height_to_addr_count.forced_push_at(
height,
self.state.as_ref().unwrap().address_count.into(),
self.state.as_ref().unwrap().addr_count.into(),
exit,
)?;
@@ -162,7 +165,7 @@ impl DynCohortVecs for Vecs {
}
fn safe_flush_stateful_vecs(&mut self, height: Height, exit: &Exit) -> Result<()> {
self.height_to_address_count.safe_flush(exit)?;
self.height_to_addr_count.safe_flush(exit)?;
self.inner
.safe_flush_stateful_vecs(height, exit, &mut self.state.as_mut().unwrap().inner)
@@ -171,30 +174,20 @@ impl DynCohortVecs for Vecs {
#[allow(clippy::too_many_arguments)]
fn compute_rest_part1(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.indexes_to_address_count.compute_rest(
self.indexes_to_addr_count.compute_rest(
indexes,
starting_indexes,
exit,
Some(&self.height_to_address_count),
Some(&self.height_to_addr_count),
)?;
self.inner
.compute_rest_part1(indexer, indexes, price, 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()
.compute_rest_part1(indexes, price, starting_indexes, exit)
}
}
@@ -205,11 +198,11 @@ impl CohortVecs for Vecs {
others: &[&Self],
exit: &Exit,
) -> Result<()> {
self.height_to_address_count.compute_sum_of_others(
self.height_to_addr_count.compute_sum_of_others(
starting_indexes.height,
others
.iter()
.map(|v| &v.height_to_address_count)
.map(|v| &v.height_to_addr_count)
.collect::<Vec<_>>()
.as_slice(),
exit,
@@ -224,35 +217,28 @@ impl CohortVecs for Vecs {
#[allow(clippy::too_many_arguments)]
fn compute_rest_part2(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
market: &market::Vecs,
height_to_supply: &impl AnyIterableVec<Height, Bitcoin>,
dateindex_to_supply: &impl AnyIterableVec<DateIndex, Bitcoin>,
height_to_market_cap: Option<&impl AnyIterableVec<Height, Dollars>>,
dateindex_to_market_cap: Option<&impl AnyIterableVec<DateIndex, Dollars>>,
height_to_realized_cap: Option<&impl AnyIterableVec<Height, Dollars>>,
dateindex_to_realized_cap: Option<&impl AnyIterableVec<DateIndex, Dollars>>,
exit: &Exit,
) -> Result<()> {
self.inner.compute_rest_part2(
indexer,
indexes,
price,
starting_indexes,
market,
height_to_supply,
dateindex_to_supply,
height_to_market_cap,
dateindex_to_market_cap,
height_to_realized_cap,
dateindex_to_realized_cap,
exit,
)
}
}
impl Deref for Vecs {
type Target = common::Vecs;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
@@ -1,7 +1,6 @@
use std::path::Path;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_structs::{
AddressGroups, Bitcoin, ByAmountRange, ByGreatEqualAmount, ByLowerThanAmount, DateIndex,
Dollars, GroupFilter, Height, Version,
@@ -10,7 +9,7 @@ use derive_deref::{Deref, DerefMut};
use vecdb::{AnyIterableVec, Database, Exit, Format};
use crate::{
Indexes, indexes, market, price,
Indexes, indexes, price,
stateful::{
address_cohort,
r#trait::{CohortVecs, DynCohortVecs},
@@ -459,18 +458,17 @@ impl Vecs {
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
let by_size_range = self.0.amount_range.as_vec();
let by_size_range = &self.0.amount_range;
[
self.0
.ge_amount
.as_mut_vec()
.into_iter()
.iter_mut()
.map(|(filter, vecs)| {
(
vecs,
by_size_range
.into_iter()
.iter()
.filter(|(other, _)| filter.includes(other))
.map(|(_, v)| v)
.collect::<Vec<_>>(),
@@ -479,13 +477,12 @@ impl Vecs {
.collect::<Vec<_>>(),
self.0
.lt_amount
.as_mut_vec()
.into_iter()
.iter_mut()
.map(|(filter, vecs)| {
(
vecs,
by_size_range
.into_iter()
.iter()
.filter(|(other, _)| filter.includes(other))
.map(|(_, v)| v)
.collect::<Vec<_>>(),
@@ -502,51 +499,48 @@ impl Vecs {
pub fn compute_rest_part1(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.as_mut_vecs().into_iter().try_for_each(|(_, v)| {
v.compute_rest_part1(indexer, indexes, price, starting_indexes, exit)
})
self.iter_mut()
.into_iter()
.try_for_each(|(_, v)| v.compute_rest_part1(indexes, price, starting_indexes, exit))
}
#[allow(clippy::too_many_arguments)]
pub fn compute_rest_part2(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
market: &market::Vecs,
height_to_supply: &impl AnyIterableVec<Height, Bitcoin>,
dateindex_to_supply: &impl AnyIterableVec<DateIndex, Bitcoin>,
height_to_market_cap: Option<&impl AnyIterableVec<Height, Dollars>>,
dateindex_to_market_cap: Option<&impl AnyIterableVec<DateIndex, Dollars>>,
height_to_realized_cap: Option<&impl AnyIterableVec<Height, Dollars>>,
dateindex_to_realized_cap: Option<&impl AnyIterableVec<DateIndex, Dollars>>,
exit: &Exit,
) -> Result<()> {
self.0.as_boxed_mut_vecs().into_iter().try_for_each(|v| {
v.into_iter().try_for_each(|(_, v)| {
v.compute_rest_part2(
indexer,
indexes,
price,
starting_indexes,
market,
height_to_supply,
dateindex_to_supply,
height_to_realized_cap,
dateindex_to_realized_cap,
exit,
)
})
self.0.iter_mut().try_for_each(|(_, v)| {
v.compute_rest_part2(
indexes,
price,
starting_indexes,
height_to_supply,
dateindex_to_supply,
height_to_market_cap,
dateindex_to_market_cap,
height_to_realized_cap,
dateindex_to_realized_cap,
exit,
)
})
}
pub fn safe_flush_stateful_vecs(&mut self, height: Height, exit: &Exit) -> Result<()> {
self.as_mut_separate_vecs()
self.iter_separate_mut()
.into_iter()
.try_for_each(|(_, v)| v.safe_flush_stateful_vecs(height, exit))
}
@@ -75,11 +75,9 @@ impl AddressTypeToIndexesToAddressCount {
Ok(())
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
pub fn iter_any_collectable(&self) -> impl Iterator<Item = &dyn AnyCollectableVec> {
self.0
.as_typed_vec()
.into_iter()
.flat_map(|(_, v)| v.vecs())
.collect::<Vec<_>>()
.iter_typed()
.flat_map(|(_, v)| v.iter_any_collectable())
}
}
@@ -27,6 +27,10 @@ impl<T> AddressTypeToTypeIndexTree<T> {
mem::swap(own, other);
}
}
pub fn unwrap(self) -> ByAddressType<BTreeMap<TypeIndex, T>> {
self.0
}
}
impl<T> Default for AddressTypeToTypeIndexTree<T> {
@@ -38,6 +38,10 @@ impl<T> AddressTypeToVec<T> {
mem::swap(own, other);
}
}
pub fn unwrap(self) -> ByAddressType<Vec<T>> {
self.0
}
}
impl<T> Default for AddressTypeToVec<T> {
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+4 -8
View File
@@ -1,9 +1,8 @@
use brk_error::Result;
use brk_indexer::Indexer;
use brk_structs::{Bitcoin, DateIndex, Dollars, Height, Version};
use vecdb::{AnyCollectableVec, AnyIterableVec, Exit};
use vecdb::{AnyIterableVec, Exit};
use crate::{Indexes, indexes, market, price};
use crate::{Indexes, indexes, price};
pub trait DynCohortVecs: Send + Sync {
fn min_height_vecs_len(&self) -> usize;
@@ -29,14 +28,11 @@ pub trait DynCohortVecs: Send + Sync {
#[allow(clippy::too_many_arguments)]
fn compute_rest_part1(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()>;
fn vecs(&self) -> Vec<&dyn AnyCollectableVec>;
}
pub trait CohortVecs: DynCohortVecs {
@@ -50,13 +46,13 @@ pub trait CohortVecs: DynCohortVecs {
#[allow(clippy::too_many_arguments)]
fn compute_rest_part2(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
market: &market::Vecs,
height_to_supply: &impl AnyIterableVec<Height, Bitcoin>,
dateindex_to_supply: &impl AnyIterableVec<DateIndex, Bitcoin>,
height_to_market_cap: Option<&impl AnyIterableVec<Height, Dollars>>,
dateindex_to_market_cap: Option<&impl AnyIterableVec<DateIndex, Dollars>>,
height_to_realized_cap: Option<&impl AnyIterableVec<Height, Dollars>>,
dateindex_to_realized_cap: Option<&impl AnyIterableVec<DateIndex, Dollars>>,
exit: &Exit,
+11 -17
View File
@@ -1,12 +1,11 @@
use std::{ops::Deref, path::Path};
use brk_error::Result;
use brk_indexer::Indexer;
use brk_structs::{Bitcoin, DateIndex, Dollars, Height, Version};
use vecdb::{AnyCollectableVec, AnyIterableVec, Database, Exit, Format};
use vecdb::{AnyIterableVec, Database, Exit, Format};
use crate::{
Indexes, UTXOCohortState, indexes, market, price,
Indexes, UTXOCohortState, indexes, price,
stateful::{
common,
r#trait::{CohortVecs, DynCohortVecs},
@@ -32,8 +31,8 @@ impl Vecs {
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
states_path: Option<&Path>,
compute_relative_to_all: bool,
ratio_extended: bool,
extended: bool,
compute_rel_to_all: bool,
compute_adjusted: bool,
) -> Result<Self> {
let compute_dollars = price.is_some();
@@ -56,8 +55,8 @@ impl Vecs {
version,
indexes,
price,
compute_relative_to_all,
ratio_extended,
extended,
compute_rel_to_all,
compute_adjusted,
)?,
})
@@ -122,18 +121,13 @@ impl DynCohortVecs for Vecs {
#[allow(clippy::too_many_arguments)]
fn compute_rest_part1(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.inner
.compute_rest_part1(indexer, indexes, price, starting_indexes, exit)
}
fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
self.inner.vecs()
.compute_rest_part1(indexes, price, starting_indexes, exit)
}
}
@@ -154,25 +148,25 @@ impl CohortVecs for Vecs {
#[allow(clippy::too_many_arguments)]
fn compute_rest_part2(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
market: &market::Vecs,
height_to_supply: &impl AnyIterableVec<Height, Bitcoin>,
dateindex_to_supply: &impl AnyIterableVec<DateIndex, Bitcoin>,
height_to_market_cap: Option<&impl AnyIterableVec<Height, Dollars>>,
dateindex_to_market_cap: Option<&impl AnyIterableVec<DateIndex, Dollars>>,
height_to_realized_cap: Option<&impl AnyIterableVec<Height, Dollars>>,
dateindex_to_realized_cap: Option<&impl AnyIterableVec<DateIndex, Dollars>>,
exit: &Exit,
) -> Result<()> {
self.inner.compute_rest_part2(
indexer,
indexes,
price,
starting_indexes,
market,
height_to_supply,
dateindex_to_supply,
height_to_market_cap,
dateindex_to_market_cap,
height_to_realized_cap,
dateindex_to_realized_cap,
exit,
+152 -188
View File
@@ -1,7 +1,6 @@
use std::{collections::BTreeMap, ops::ControlFlow, path::Path};
use brk_error::Result;
use brk_indexer::Indexer;
use brk_structs::{
Bitcoin, ByAgeRange, ByAmountRange, ByEpoch, ByGreatEqualAmount, ByLowerThanAmount, ByMaxAge,
ByMinAge, BySpendableType, ByTerm, CheckedSub, DateIndex, Dollars, GroupFilter, HalvingEpoch,
@@ -11,7 +10,7 @@ use derive_deref::{Deref, DerefMut};
use vecdb::{AnyIterableVec, Database, Exit, Format, StoredIndex};
use crate::{
Indexes, indexes, market, price,
Indexes, indexes, price,
stateful::r#trait::DynCohortVecs,
states::{BlockState, Transacted},
};
@@ -38,18 +37,18 @@ impl Vecs {
db,
None,
format,
version + VERSION + Version::ZERO,
version + VERSION + Version::ONE,
indexes,
price,
None,
false,
true,
false,
true,
)?,
term: ByTerm {
short: utxo_cohort::Vecs::forced_import(
db,
Some("short_term_holders"),
Some("sth"),
format,
version + VERSION + Version::ZERO,
indexes,
@@ -61,7 +60,7 @@ impl Vecs {
)?,
long: utxo_cohort::Vecs::forced_import(
db,
Some("long_term_holders"),
Some("lth"),
format,
version + VERSION + Version::ZERO,
indexes,
@@ -143,8 +142,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
p2pk33: utxo_cohort::Vecs::forced_import(
@@ -155,8 +154,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
p2pkh: utxo_cohort::Vecs::forced_import(
@@ -167,8 +166,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
p2sh: utxo_cohort::Vecs::forced_import(
@@ -179,8 +178,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
p2wpkh: utxo_cohort::Vecs::forced_import(
@@ -191,8 +190,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
p2wsh: utxo_cohort::Vecs::forced_import(
@@ -203,8 +202,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
p2tr: utxo_cohort::Vecs::forced_import(
@@ -215,8 +214,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
p2a: utxo_cohort::Vecs::forced_import(
@@ -227,8 +226,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
p2ms: utxo_cohort::Vecs::forced_import(
@@ -239,8 +238,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
empty: utxo_cohort::Vecs::forced_import(
@@ -251,8 +250,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
unknown: utxo_cohort::Vecs::forced_import(
@@ -263,8 +262,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
},
@@ -955,8 +954,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_1sat_to_10sats: utxo_cohort::Vecs::forced_import(
@@ -967,8 +966,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_10sats_to_100sats: utxo_cohort::Vecs::forced_import(
@@ -979,8 +978,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_100sats_to_1k_sats: utxo_cohort::Vecs::forced_import(
@@ -991,8 +990,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_1k_sats_to_10k_sats: utxo_cohort::Vecs::forced_import(
@@ -1003,8 +1002,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_10k_sats_to_100k_sats: utxo_cohort::Vecs::forced_import(
@@ -1015,8 +1014,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_100k_sats_to_1m_sats: utxo_cohort::Vecs::forced_import(
@@ -1027,8 +1026,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_1m_sats_to_10m_sats: utxo_cohort::Vecs::forced_import(
@@ -1039,8 +1038,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_10m_sats_to_1btc: utxo_cohort::Vecs::forced_import(
@@ -1051,8 +1050,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_1btc_to_10btc: utxo_cohort::Vecs::forced_import(
@@ -1063,8 +1062,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_10btc_to_100btc: utxo_cohort::Vecs::forced_import(
@@ -1075,8 +1074,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_100btc_to_1k_btc: utxo_cohort::Vecs::forced_import(
@@ -1087,8 +1086,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_1k_btc_to_10k_btc: utxo_cohort::Vecs::forced_import(
@@ -1099,8 +1098,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_10k_btc_to_100k_btc: utxo_cohort::Vecs::forced_import(
@@ -1111,8 +1110,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_100k_btc_or_more: utxo_cohort::Vecs::forced_import(
@@ -1123,8 +1122,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
},
@@ -1137,8 +1136,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_100sats: utxo_cohort::Vecs::forced_import(
@@ -1149,8 +1148,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_1k_sats: utxo_cohort::Vecs::forced_import(
@@ -1161,8 +1160,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_10k_sats: utxo_cohort::Vecs::forced_import(
@@ -1173,8 +1172,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_100k_sats: utxo_cohort::Vecs::forced_import(
@@ -1185,8 +1184,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_1m_sats: utxo_cohort::Vecs::forced_import(
@@ -1197,8 +1196,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_10m_sats: utxo_cohort::Vecs::forced_import(
@@ -1209,8 +1208,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_1btc: utxo_cohort::Vecs::forced_import(
@@ -1221,8 +1220,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_10btc: utxo_cohort::Vecs::forced_import(
@@ -1233,8 +1232,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_100btc: utxo_cohort::Vecs::forced_import(
@@ -1245,8 +1244,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_1k_btc: utxo_cohort::Vecs::forced_import(
@@ -1257,8 +1256,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_10k_btc: utxo_cohort::Vecs::forced_import(
@@ -1269,8 +1268,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_100k_btc: utxo_cohort::Vecs::forced_import(
@@ -1281,8 +1280,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
},
@@ -1295,8 +1294,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_10sats: utxo_cohort::Vecs::forced_import(
@@ -1307,8 +1306,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_100sats: utxo_cohort::Vecs::forced_import(
@@ -1319,8 +1318,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_1k_sats: utxo_cohort::Vecs::forced_import(
@@ -1331,8 +1330,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_10k_sats: utxo_cohort::Vecs::forced_import(
@@ -1343,8 +1342,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_100k_sats: utxo_cohort::Vecs::forced_import(
@@ -1355,8 +1354,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_1m_sats: utxo_cohort::Vecs::forced_import(
@@ -1367,8 +1366,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_10m_sats: utxo_cohort::Vecs::forced_import(
@@ -1379,8 +1378,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_1btc: utxo_cohort::Vecs::forced_import(
@@ -1391,8 +1390,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_10btc: utxo_cohort::Vecs::forced_import(
@@ -1403,8 +1402,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_100btc: utxo_cohort::Vecs::forced_import(
@@ -1415,8 +1414,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_1k_btc: utxo_cohort::Vecs::forced_import(
@@ -1427,8 +1426,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_10k_btc: utxo_cohort::Vecs::forced_import(
@@ -1439,8 +1438,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
},
@@ -1458,8 +1457,7 @@ impl Vecs {
let mut vecs = self
.age_range
.as_mut_vec()
.into_iter()
.iter_mut()
.map(|(filter, v)| (filter, &mut v.state))
.collect::<Vec<_>>();
@@ -1503,9 +1501,8 @@ impl Vecs {
let mut time_based_vecs = self
.0
.age_range
.as_mut_vec()
.into_iter()
.chain(self.0.epoch.as_mut_vec())
.iter_mut()
.chain(self.0.epoch.iter_mut())
.collect::<Vec<_>>();
let last_timestamp = chain_state.last().unwrap().timestamp;
@@ -1551,8 +1548,10 @@ impl Vecs {
);
});
sent.by_type.spendable.as_typed_vec().into_iter().for_each(
|(output_type, supply_state)| {
sent.by_type
.spendable
.iter_typed()
.for_each(|(output_type, supply_state)| {
self.0
._type
.get_mut(output_type)
@@ -1568,12 +1567,10 @@ impl Vecs {
days_old_float,
older_than_hour,
)
},
);
});
sent.by_size_group
.as_typed_vec()
.into_iter()
.iter_typed()
.for_each(|(group, supply_state)| {
self.0
.amount_range
@@ -1606,24 +1603,20 @@ impl Vecs {
v.state.as_mut().unwrap().receive(&supply_state, price);
});
self._type
.as_mut_vec()
.into_iter()
.for_each(|(filter, vecs)| {
let output_type = match filter {
GroupFilter::Type(output_type) => *output_type,
_ => unreachable!(),
};
vecs.state
.as_mut()
.unwrap()
.receive(received.by_type.get(output_type), price)
});
self._type.iter_mut().for_each(|(filter, vecs)| {
let output_type = match filter {
GroupFilter::Type(output_type) => *output_type,
_ => unreachable!(),
};
vecs.state
.as_mut()
.unwrap()
.receive(received.by_type.get(output_type), price)
});
received
.by_size_group
.as_typed_vec()
.into_iter()
.iter_typed()
.for_each(|(group, supply_state)| {
self.amount_range
.get_mut(group)
@@ -1640,89 +1633,64 @@ impl Vecs {
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
let by_date_range = self.0.age_range.as_vec();
let by_size_range = self.0.amount_range.as_vec();
let by_date_range = &self.0.age_range;
let by_size_range = &self.0.amount_range;
[
vec![(&mut self.0.all.1, self.0.epoch.vecs().to_vec())],
self.0
.min_age
.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.0
.max_age
.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.0
.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.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<_>>(),
]
[(
&mut self.0.all.1,
by_date_range.iter().map(|(_, v)| v).collect::<Vec<_>>(),
)]
.into_iter()
.flatten()
.chain(self.0.min_age.iter_mut().map(|(filter, vecs)| {
(
vecs,
by_date_range
.iter()
.filter(|(other, _)| filter.includes(other))
.map(|(_, v)| v)
.collect::<Vec<_>>(),
)
}))
.chain(self.0.max_age.iter_mut().map(|(filter, vecs)| {
(
vecs,
by_date_range
.iter()
.filter(|(other, _)| filter.includes(other))
.map(|(_, v)| v)
.collect::<Vec<_>>(),
)
}))
.chain(self.0.term.iter_mut().map(|(filter, vecs)| {
(
vecs,
by_date_range
.iter()
.filter(|(other, _)| filter.includes(other))
.map(|(_, v)| v)
.collect::<Vec<_>>(),
)
}))
.chain(self.0.ge_amount.iter_mut().map(|(filter, vecs)| {
(
vecs,
by_size_range
.iter()
.filter(|(other, _)| filter.includes(other))
.map(|(_, v)| v)
.collect::<Vec<_>>(),
)
}))
.chain(self.0.lt_amount.iter_mut().map(|(filter, vecs)| {
(
vecs,
by_size_range
.iter()
.filter(|(other, _)| filter.includes(other))
.map(|(_, v)| v)
.collect::<Vec<_>>(),
)
}))
.try_for_each(|(vecs, stateful)| {
vecs.compute_from_stateful(starting_indexes, &stateful, exit)
})
@@ -1730,52 +1698,48 @@ impl Vecs {
pub fn compute_rest_part1(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.as_mut_vecs().into_iter().try_for_each(|(_, v)| {
v.compute_rest_part1(indexer, indexes, price, starting_indexes, exit)
})
self.iter_mut()
.into_iter()
.try_for_each(|(_, v)| v.compute_rest_part1(indexes, price, starting_indexes, exit))
}
#[allow(clippy::too_many_arguments)]
pub fn compute_rest_part2(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
market: &market::Vecs,
height_to_supply: &impl AnyIterableVec<Height, Bitcoin>,
dateindex_to_supply: &impl AnyIterableVec<DateIndex, Bitcoin>,
height_to_market_cap: Option<&impl AnyIterableVec<Height, Dollars>>,
dateindex_to_market_cap: Option<&impl AnyIterableVec<DateIndex, Dollars>>,
height_to_realized_cap: Option<&impl AnyIterableVec<Height, Dollars>>,
dateindex_to_realized_cap: Option<&impl AnyIterableVec<DateIndex, Dollars>>,
exit: &Exit,
) -> Result<()> {
self.0.as_boxed_mut_vecs().into_iter().try_for_each(|v| {
v.into_iter().try_for_each(|(_, v)| {
v.compute_rest_part2(
indexer,
indexes,
price,
starting_indexes,
market,
height_to_supply,
dateindex_to_supply,
height_to_realized_cap,
dateindex_to_realized_cap,
exit,
)
})
self.iter_mut().into_iter().try_for_each(|(_, v)| {
v.compute_rest_part2(
indexes,
price,
starting_indexes,
height_to_supply,
dateindex_to_supply,
height_to_market_cap,
dateindex_to_market_cap,
height_to_realized_cap,
dateindex_to_realized_cap,
exit,
)
})
}
pub fn safe_flush_stateful_vecs(&mut self, height: Height, exit: &Exit) -> Result<()> {
self.as_mut_separate_vecs()
.into_iter()
self.iter_separate_mut()
.try_for_each(|(_, v)| v.safe_flush_stateful_vecs(height, exit))
}
}
@@ -9,14 +9,14 @@ use super::CohortState;
#[derive(Clone)]
pub struct AddressCohortState {
pub address_count: u64,
pub addr_count: u64,
pub inner: CohortState,
}
impl AddressCohortState {
pub fn new(path: &Path, name: &str, compute_dollars: bool) -> Self {
Self {
address_count: 0,
addr_count: 0,
inner: CohortState::new(path, name, compute_dollars),
}
}
@@ -44,14 +44,14 @@ impl AddressCohortState {
let prev_realized_price = compute_price.then(|| addressdata.realized_price());
let prev_supply_state = SupplyState {
utxos: addressdata.outputs_len as u64,
utxos: addressdata.utxos as u64,
value: addressdata.amount(),
};
addressdata.send(value, prev_price)?;
let supply_state = SupplyState {
utxos: addressdata.outputs_len as u64,
utxos: addressdata.utxos as u64,
value: addressdata.amount(),
};
@@ -79,14 +79,14 @@ impl AddressCohortState {
let prev_realized_price = compute_price.then(|| address_data.realized_price());
let prev_supply_state = SupplyState {
utxos: address_data.outputs_len as u64,
utxos: address_data.utxos as u64,
value: address_data.amount(),
};
address_data.receive(value, price);
let supply_state = SupplyState {
utxos: address_data.outputs_len as u64,
utxos: address_data.utxos as u64,
value: address_data.amount(),
};
@@ -99,7 +99,7 @@ impl AddressCohortState {
}
pub fn add(&mut self, addressdata: &LoadedAddressData) {
self.address_count += 1;
self.addr_count += 1;
self.inner.increment_(
&addressdata.into(),
addressdata.realized_cap,
@@ -108,7 +108,7 @@ impl AddressCohortState {
}
pub fn subtract(&mut self, addressdata: &LoadedAddressData) {
self.address_count = self.address_count.checked_sub(1).unwrap();
self.addr_count = self.addr_count.checked_sub(1).unwrap();
self.inner.decrement_(
&addressdata.into(),
addressdata.realized_cap,
@@ -283,7 +283,7 @@ impl CohortState {
}
}
Ordering::Equal => {
state.supply_even += sats;
state.supply_breakeven += sats;
}
}
};
+1 -1
View File
@@ -43,7 +43,7 @@ impl SubAssign<&SupplyState> for SupplyState {
impl From<&LoadedAddressData> for SupplyState {
fn from(value: &LoadedAddressData) -> Self {
Self {
utxos: value.outputs_len as u64,
utxos: value.utxos as u64,
value: value.amount(),
}
}
+3 -3
View File
@@ -3,7 +3,7 @@ use brk_structs::{Dollars, Sats};
#[derive(Debug, Default, Clone)]
pub struct UnrealizedState {
pub supply_in_profit: Sats,
pub supply_even: Sats,
pub supply_breakeven: Sats,
pub supply_in_loss: Sats,
pub unrealized_profit: Dollars,
pub unrealized_loss: Dollars,
@@ -12,7 +12,7 @@ pub struct UnrealizedState {
impl UnrealizedState {
pub const NAN: Self = Self {
supply_in_profit: Sats::ZERO,
supply_even: Sats::ZERO,
supply_breakeven: Sats::ZERO,
supply_in_loss: Sats::ZERO,
unrealized_profit: Dollars::NAN,
unrealized_loss: Dollars::NAN,
@@ -20,7 +20,7 @@ impl UnrealizedState {
pub const ZERO: Self = Self {
supply_in_profit: Sats::ZERO,
supply_even: Sats::ZERO,
supply_breakeven: Sats::ZERO,
supply_in_loss: Sats::ZERO,
unrealized_profit: Dollars::ZERO,
unrealized_loss: Dollars::ZERO,
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -14,7 +14,7 @@ pub struct BRK {
dateindex_to_ohlc: BTreeMap<DateIndex, Vec<OHLCCents>>,
}
const API_URL: &str = "https://bitcoinresearchkit.org/api/vecs";
const API_URL: &str = "https://bitview.space/api/vecs";
const CHUNK_SIZE: usize = 10_000;
impl BRK {
@@ -46,7 +46,7 @@ impl BRK {
default_retry(|_| {
let url = format!(
"{API_URL}/height-to-ohlc?from={}&to={}",
"{API_URL}/height-to-price-ohlc?from={}&to={}",
height,
height + CHUNK_SIZE
);
@@ -91,7 +91,7 @@ impl BRK {
default_retry(|_| {
let url = format!(
"{API_URL}/dateindex-to-ohlc?from={}&to={}",
"{API_URL}/dateindex-to-price-ohlc?from={}&to={}",
dateindex,
dateindex + CHUNK_SIZE
);
+8 -8
View File
@@ -25,7 +25,7 @@
**Key-Value Storage (lookups):**
- Block hash prefixes → heights
- Transaction ID prefixes → transaction indices
- Transaction ID prefixes → transaction indices
- Address byte hashes → type indices
- Fast point queries by hash or address
@@ -60,7 +60,7 @@ let rpc = Box::leak(Box::new(Client::new(
// Create parser for Bitcoin Core block files
let parser = Parser::new(
Path::new("~/.bitcoin/blocks").to_path_buf(),
Path::new("./brk_data").to_path_buf(),
Some(Path::new("./brk_data").to_path_buf()),
rpc
);
@@ -85,19 +85,19 @@ use std::thread::sleep;
// Continuous indexing loop for real-time updates
loop {
let start_time = Instant::now();
// Index new blocks
let indexes = indexer.index(&parser, rpc, &exit, true)?;
println!("Indexed to height {} in {:?}",
println!("Indexed to height {} in {:?}",
indexes.height, start_time.elapsed());
// Check for exit signal
if exit.is_signaled() {
println!("Graceful shutdown requested");
break;
}
// Wait before next update cycle
sleep(Duration::from_secs(5 * 60));
}
@@ -187,4 +187,4 @@ pub struct Indexes {
---
*This README was generated by Claude Code*
*This README was generated by Claude Code*
+5 -5
View File
@@ -21,8 +21,8 @@ fn main() -> Result<()> {
let blocks_dir = bitcoin_dir.join("blocks");
let outputs_dir = Path::new("../../_outputs");
fs::create_dir_all(outputs_dir)?;
let outputs_dir = Path::new(&std::env::var("HOME").unwrap()).join(".brk");
fs::create_dir_all(&outputs_dir)?;
// let outputs_dir = Path::new("/Volumes/WD_BLACK1/brk");
let rpc = Box::leak(Box::new(bitcoincore_rpc::Client::new(
@@ -33,11 +33,11 @@ fn main() -> Result<()> {
let exit = Exit::new();
exit.set_ctrlc_handler();
let parser = Parser::new(blocks_dir, outputs_dir.to_path_buf(), rpc);
let parser = Parser::new(blocks_dir, Some(outputs_dir.to_path_buf()), rpc);
fs::create_dir_all(outputs_dir)?;
fs::create_dir_all(&outputs_dir)?;
let mut indexer = Indexer::forced_import(outputs_dir)?;
let mut indexer = Indexer::forced_import(&outputs_dir)?;
loop {
let i = Instant::now();
+19 -24
View File
@@ -5,7 +5,7 @@ use std::{collections::BTreeMap, path::Path, str::FromStr, thread, time::Instant
use bitcoin::{Transaction, TxIn, TxOut};
use brk_error::{Error, Result};
use brk_parser::Parser;
use brk_parser::{BlockExtended, Parser};
use brk_store::AnyStore;
use brk_structs::{
AddressBytes, AddressBytesHash, BlockHash, BlockHashPrefix, Height, InputIndex, OutputIndex,
@@ -14,7 +14,7 @@ use brk_structs::{
};
use log::{error, info};
use rayon::prelude::*;
use vecdb::{AnyVec, Database, Exit, GenericStoredVec, PAGE_SIZE, Reader, VecIterator};
use vecdb::{AnyVec, Exit, GenericStoredVec, Reader, VecIterator};
mod indexes;
mod stores;
mod vecs;
@@ -23,33 +23,32 @@ pub use indexes::*;
pub use stores::*;
pub use vecs::*;
// One version for all data sources
// Increment on change OR addition
const VERSION: Version = Version::new(21);
const SNAPSHOT_BLOCK_RANGE: usize = 1_000;
const COLLISIONS_CHECKED_UP_TO: Height = Height::new(909_150);
const VERSION: Version = Version::ONE;
#[derive(Clone)]
pub struct Indexer {
pub db: Database,
pub vecs: Vecs,
pub stores: Stores,
}
impl Indexer {
pub fn forced_import(outputs_dir: &Path) -> Result<Self> {
let db = Database::open(&outputs_dir.join("indexed/vecs"))?;
info!("Importing indexer...");
let vecs = Vecs::forced_import(&db, VERSION + Version::ZERO)?;
let path = outputs_dir.join("indexed");
db.set_min_len(PAGE_SIZE * 50_000_000)?;
let vecs = Vecs::forced_import(&path, VERSION)?;
info!("Imported vecs");
Ok(Self {
vecs,
stores: Stores::forced_import(
&outputs_dir.join("indexed/stores"),
VERSION + Version::ZERO,
)?,
db,
})
let stores = Stores::forced_import(&path, VERSION)?;
info!("Imported stores");
Ok(Self { vecs, stores })
}
pub fn index(
@@ -59,16 +58,9 @@ impl Indexer {
exit: &Exit,
check_collisions: bool,
) -> Result<Indexes> {
let db = self.db.clone();
// dbg!(self.db.regions().id_to_index());
// dbg!(self.db.layout());
let starting_indexes = Indexes::try_from((&mut self.vecs, &self.stores, rpc))
.unwrap_or_else(|_report| Indexes::default());
// dbg!(&starting_indexes);
let lock = exit.lock();
self.stores
.rollback_if_needed(&mut self.vecs, &starting_indexes)?;
@@ -108,7 +100,6 @@ impl Indexer {
vecs.flush(height)?;
info!("Flushed vecs in {}s", i.elapsed().as_secs());
let i = Instant::now();
db.flush()?;
info!("Flushed db in {}s", i.elapsed().as_secs());
Ok(())
};
@@ -210,6 +201,10 @@ impl Indexer {
.blockhashprefix_to_height
.insert_if_needed(blockhash_prefix, height, height);
stores
.height_to_coinbase_tag
.insert_if_needed( height, block.coinbase_tag().into(), height);
vecs.height_to_blockhash.push_if_needed(height, blockhash)?;
vecs.height_to_difficulty
.push_if_needed(height, block.header.difficulty_float().into())?;
@@ -797,7 +792,7 @@ impl Indexer {
}
let i = Instant::now();
db.punch_holes()?;
self.vecs.punch_holes()?;
info!("Punched holes in db in {}s", i.elapsed().as_secs());
Ok(starting_indexes)
+51 -49
View File
@@ -4,11 +4,12 @@ use brk_error::Result;
use brk_store::{AnyStore, Store};
use brk_structs::{
AddressBytes, AddressBytesHash, BlockHashPrefix, ByAddressType, Height, OutputIndex,
OutputType, TxIndex, TxidPrefix, TypeIndex, TypeIndexWithOutputindex, Unit, Version,
OutputType, StoredString, TxIndex, TxidPrefix, TypeIndex, TypeIndexWithOutputindex, Unit,
Version,
};
use fjall::{PersistMode, TransactionalKeyspace};
use rayon::prelude::*;
use vecdb::VecIterator;
use vecdb::{AnyVec, StoredIndex, VecIterator};
use crate::Indexes;
@@ -20,22 +21,23 @@ pub struct Stores {
pub addressbyteshash_to_typeindex: Store<AddressBytesHash, TypeIndex>,
pub blockhashprefix_to_height: Store<BlockHashPrefix, Height>,
pub height_to_coinbase_tag: Store<Height, StoredString>,
pub txidprefix_to_txindex: Store<TxidPrefix, TxIndex>,
pub addresstype_to_typeindex_with_outputindex:
ByAddressType<Store<TypeIndexWithOutputindex, Unit>>,
}
const VERSION: Version = Version::ZERO;
impl Stores {
pub fn forced_import(path: &Path, version: Version) -> Result<Self> {
fs::create_dir_all(path)?;
pub fn forced_import(parent: &Path, version: Version) -> Result<Self> {
let path = parent.join("stores");
let keyspace = match brk_store::open_keyspace(path) {
fs::create_dir_all(&path)?;
let keyspace = match brk_store::open_keyspace(&path) {
Ok(keyspace) => keyspace,
Err(_) => {
fs::remove_dir_all(path)?;
return Self::forced_import(path, version);
fs::remove_dir_all(&path)?;
return Self::forced_import(&path, version);
}
};
@@ -43,106 +45,97 @@ impl Stores {
let addressbyteshash_to_typeindex = scope.spawn(|| {
Store::import(
&keyspace,
path,
&path,
"addressbyteshash_to_typeindex",
version + VERSION + Version::ZERO,
version,
None,
)
});
let blockhashprefix_to_height = scope.spawn(|| {
Store::import(
&keyspace,
path,
"blockhashprefix_to_height",
version + VERSION + Version::ZERO,
None,
)
});
let txidprefix_to_txindex = scope.spawn(|| {
Store::import(
&keyspace,
path,
"txidprefix_to_txindex",
version + VERSION + Version::ZERO,
None,
)
Store::import(&keyspace, &path, "blockhashprefix_to_height", version, None)
});
let txidprefix_to_txindex = scope
.spawn(|| Store::import(&keyspace, &path, "txidprefix_to_txindex", version, None));
let p2aaddressindex_with_outputindex = scope.spawn(|| {
Store::import(
&keyspace,
path,
&path,
"p2aaddressindex_with_outputindex",
version + VERSION + Version::ZERO,
version,
Some(false),
)
});
let p2pk33addressindex_with_outputindex = scope.spawn(|| {
Store::import(
&keyspace,
path,
&path,
"p2pk33addressindex_with_outputindex",
version + VERSION + Version::ZERO,
version,
Some(false),
)
});
let p2pk65addressindex_with_outputindex = scope.spawn(|| {
Store::import(
&keyspace,
path,
&path,
"p2pk65addressindex_with_outputindex",
version + VERSION + Version::ZERO,
version,
Some(false),
)
});
let p2pkhaddressindex_with_outputindex = scope.spawn(|| {
Store::import(
&keyspace,
path,
&path,
"p2pkhaddressindex_with_outputindex",
version + VERSION + Version::ZERO,
version,
Some(false),
)
});
let p2shaddressindex_with_outputindex = scope.spawn(|| {
Store::import(
&keyspace,
path,
&path,
"p2shaddressindex_with_outputindex",
version + VERSION + Version::ZERO,
version,
Some(false),
)
});
let p2traddressindex_with_outputindex = scope.spawn(|| {
Store::import(
&keyspace,
path,
&path,
"p2traddressindex_with_outputindex",
version + VERSION + Version::ZERO,
version,
Some(false),
)
});
let p2wpkhaddressindex_with_outputindex = scope.spawn(|| {
Store::import(
&keyspace,
path,
&path,
"p2wpkhaddressindex_with_outputindex",
version + VERSION + Version::ZERO,
version,
Some(false),
)
});
let p2wshaddressindex_with_outputindex = scope.spawn(|| {
Store::import(
&keyspace,
path,
&path,
"p2wshaddressindex_with_outputindex",
version + VERSION + Version::ZERO,
version,
Some(false),
)
});
let height_to_coinbase_tag =
Store::import(&keyspace, &path, "height_to_coinbase_tag", version, None)?;
Ok(Self {
keyspace: keyspace.clone(),
height_to_coinbase_tag,
addressbyteshash_to_typeindex: addressbyteshash_to_typeindex.join().unwrap()?,
blockhashprefix_to_height: blockhashprefix_to_height.join().unwrap()?,
txidprefix_to_txindex: txidprefix_to_txindex.join().unwrap()?,
@@ -182,11 +175,9 @@ impl Stores {
.map_err(|e| e.into())
}
fn as_slice(&self) -> [&(dyn AnyStore + Send + Sync); 11] {
fn as_slice(&self) -> [&(dyn AnyStore + Send + Sync); 12] {
[
&self.addressbyteshash_to_typeindex,
&self.blockhashprefix_to_height,
&self.txidprefix_to_txindex,
&self.addresstype_to_typeindex_with_outputindex.p2a,
&self.addresstype_to_typeindex_with_outputindex.p2pk33,
&self.addresstype_to_typeindex_with_outputindex.p2pk65,
@@ -195,14 +186,15 @@ impl Stores {
&self.addresstype_to_typeindex_with_outputindex.p2tr,
&self.addresstype_to_typeindex_with_outputindex.p2wpkh,
&self.addresstype_to_typeindex_with_outputindex.p2wsh,
&self.blockhashprefix_to_height,
&self.height_to_coinbase_tag,
&self.txidprefix_to_txindex,
]
}
fn as_mut_slice(&mut self) -> [&mut (dyn AnyStore + Send + Sync); 11] {
fn as_mut_slice(&mut self) -> [&mut (dyn AnyStore + Send + Sync); 12] {
[
&mut self.addressbyteshash_to_typeindex,
&mut self.blockhashprefix_to_height,
&mut self.txidprefix_to_txindex,
&mut self.addresstype_to_typeindex_with_outputindex.p2a,
&mut self.addresstype_to_typeindex_with_outputindex.p2pk33,
&mut self.addresstype_to_typeindex_with_outputindex.p2pk65,
@@ -211,6 +203,9 @@ impl Stores {
&mut self.addresstype_to_typeindex_with_outputindex.p2tr,
&mut self.addresstype_to_typeindex_with_outputindex.p2wpkh,
&mut self.addresstype_to_typeindex_with_outputindex.p2wsh,
&mut self.blockhashprefix_to_height,
&mut self.height_to_coinbase_tag,
&mut self.txidprefix_to_txindex,
]
}
@@ -222,6 +217,7 @@ impl Stores {
if self.addressbyteshash_to_typeindex.is_empty()?
&& self.blockhashprefix_to_height.is_empty()?
&& self.txidprefix_to_txindex.is_empty()?
&& self.height_to_coinbase_tag.is_empty()?
&& self
.addresstype_to_typeindex_with_outputindex
.p2a
@@ -266,6 +262,12 @@ impl Stores {
self.blockhashprefix_to_height.remove(blockhashprefix);
});
(starting_indexes.height.unwrap_to_usize()..vecs.height_to_blockhash.len())
.map(Height::from)
.for_each(|h| {
self.height_to_coinbase_tag.remove(h);
});
if let Some(mut index) = vecs
.height_to_first_p2pk65addressindex
.iter()
+91 -171
View File
@@ -1,3 +1,5 @@
use std::path::Path;
use brk_error::Result;
use brk_structs::{
AddressBytes, BlockHash, EmptyOutputIndex, Height, InputIndex, OpReturnIndex, OutputIndex,
@@ -9,15 +11,16 @@ use brk_structs::{
};
use rayon::prelude::*;
use vecdb::{
AnyCollectableVec, AnyStoredVec, CompressedVec, Database, GenericStoredVec, RawVec, Stamp,
AnyCollectableVec, AnyStoredVec, CompressedVec, Database, GenericStoredVec, PAGE_SIZE, RawVec,
Stamp,
};
use crate::Indexes;
const VERSION: Version = Version::ZERO;
#[derive(Clone)]
pub struct Vecs {
db: Database,
pub emptyoutputindex_to_txindex: CompressedVec<EmptyOutputIndex, TxIndex>,
pub height_to_blockhash: RawVec<Height, BlockHash>,
pub height_to_difficulty: CompressedVec<Height, StoredF64>,
@@ -67,225 +70,136 @@ pub struct Vecs {
}
impl Vecs {
pub fn forced_import(db: &Database, version: Version) -> Result<Self> {
Ok(Self {
emptyoutputindex_to_txindex: CompressedVec::forced_import(
db,
"txindex",
version + VERSION + Version::ZERO,
)?,
height_to_blockhash: RawVec::forced_import(
db,
"blockhash",
version + VERSION + Version::ZERO,
)?,
height_to_difficulty: CompressedVec::forced_import(
db,
"difficulty",
version + VERSION + Version::ZERO,
)?,
pub fn forced_import(parent: &Path, version: Version) -> Result<Self> {
let db = Database::open(&parent.join("vecs"))?;
db.set_min_len(PAGE_SIZE * 50_000_000)?;
let this = Self {
emptyoutputindex_to_txindex: CompressedVec::forced_import(&db, "txindex", version)?,
height_to_blockhash: RawVec::forced_import(&db, "blockhash", version)?,
height_to_difficulty: CompressedVec::forced_import(&db, "difficulty", version)?,
height_to_first_emptyoutputindex: CompressedVec::forced_import(
db,
&db,
"first_emptyoutputindex",
version + VERSION + Version::ZERO,
version,
)?,
height_to_first_inputindex: CompressedVec::forced_import(
db,
&db,
"first_inputindex",
version + VERSION + Version::ZERO,
version,
)?,
height_to_first_opreturnindex: CompressedVec::forced_import(
db,
&db,
"first_opreturnindex",
version + VERSION + Version::ZERO,
version,
)?,
height_to_first_outputindex: CompressedVec::forced_import(
db,
&db,
"first_outputindex",
version + VERSION + Version::ZERO,
version,
)?,
height_to_first_p2aaddressindex: CompressedVec::forced_import(
db,
&db,
"first_p2aaddressindex",
version + VERSION + Version::ZERO,
version,
)?,
height_to_first_p2msoutputindex: CompressedVec::forced_import(
db,
&db,
"first_p2msoutputindex",
version + VERSION + Version::ZERO,
version,
)?,
height_to_first_p2pk33addressindex: CompressedVec::forced_import(
db,
&db,
"first_p2pk33addressindex",
version + VERSION + Version::ZERO,
version,
)?,
height_to_first_p2pk65addressindex: CompressedVec::forced_import(
db,
&db,
"first_p2pk65addressindex",
version + VERSION + Version::ZERO,
version,
)?,
height_to_first_p2pkhaddressindex: CompressedVec::forced_import(
db,
&db,
"first_p2pkhaddressindex",
version + VERSION + Version::ZERO,
version,
)?,
height_to_first_p2shaddressindex: CompressedVec::forced_import(
db,
&db,
"first_p2shaddressindex",
version + VERSION + Version::ZERO,
version,
)?,
height_to_first_p2traddressindex: CompressedVec::forced_import(
db,
&db,
"first_p2traddressindex",
version + VERSION + Version::ZERO,
version,
)?,
height_to_first_p2wpkhaddressindex: CompressedVec::forced_import(
db,
&db,
"first_p2wpkhaddressindex",
version + VERSION + Version::ZERO,
version,
)?,
height_to_first_p2wshaddressindex: CompressedVec::forced_import(
db,
&db,
"first_p2wshaddressindex",
version + VERSION + Version::ZERO,
)?,
height_to_first_txindex: CompressedVec::forced_import(
db,
"first_txindex",
version + VERSION + Version::ZERO,
version,
)?,
height_to_first_txindex: CompressedVec::forced_import(&db, "first_txindex", version)?,
height_to_first_unknownoutputindex: CompressedVec::forced_import(
db,
&db,
"first_unknownoutputindex",
version + VERSION + Version::ZERO,
)?,
height_to_timestamp: CompressedVec::forced_import(
db,
"timestamp",
version + VERSION + Version::ZERO,
)?,
height_to_total_size: CompressedVec::forced_import(
db,
"total_size",
version + VERSION + Version::ZERO,
)?,
height_to_weight: CompressedVec::forced_import(
db,
"weight",
version + VERSION + Version::ZERO,
)?,
inputindex_to_outputindex: RawVec::forced_import(
db,
"outputindex",
version + VERSION + Version::ZERO,
)?,
opreturnindex_to_txindex: CompressedVec::forced_import(
db,
"txindex",
version + VERSION + Version::ZERO,
)?,
outputindex_to_outputtype: RawVec::forced_import(
db,
"outputtype",
version + VERSION + Version::ZERO,
)?,
outputindex_to_typeindex: RawVec::forced_import(
db,
"typeindex",
version + VERSION + Version::ZERO,
)?,
outputindex_to_value: RawVec::forced_import(
db,
"value",
version + VERSION + Version::ZERO,
)?,
p2aaddressindex_to_p2abytes: RawVec::forced_import(
db,
"p2abytes",
version + VERSION + Version::ZERO,
)?,
p2msoutputindex_to_txindex: CompressedVec::forced_import(
db,
"txindex",
version + VERSION + Version::ZERO,
)?,
p2pk33addressindex_to_p2pk33bytes: RawVec::forced_import(
db,
"p2pk33bytes",
version + VERSION + Version::ZERO,
)?,
p2pk65addressindex_to_p2pk65bytes: RawVec::forced_import(
db,
"p2pk65bytes",
version + VERSION + Version::ZERO,
)?,
p2pkhaddressindex_to_p2pkhbytes: RawVec::forced_import(
db,
"p2pkhbytes",
version + VERSION + Version::ZERO,
)?,
p2shaddressindex_to_p2shbytes: RawVec::forced_import(
db,
"p2shbytes",
version + VERSION + Version::ZERO,
)?,
p2traddressindex_to_p2trbytes: RawVec::forced_import(
db,
"p2trbytes",
version + VERSION + Version::ZERO,
)?,
p2wpkhaddressindex_to_p2wpkhbytes: RawVec::forced_import(
db,
"p2wpkhbytes",
version + VERSION + Version::ZERO,
)?,
p2wshaddressindex_to_p2wshbytes: RawVec::forced_import(
db,
"p2wshbytes",
version + VERSION + Version::ZERO,
)?,
txindex_to_base_size: CompressedVec::forced_import(
db,
"base_size",
version + VERSION + Version::ZERO,
version,
)?,
height_to_timestamp: CompressedVec::forced_import(&db, "timestamp", version)?,
height_to_total_size: CompressedVec::forced_import(&db, "total_size", version)?,
height_to_weight: CompressedVec::forced_import(&db, "weight", version)?,
inputindex_to_outputindex: RawVec::forced_import(&db, "outputindex", version)?,
opreturnindex_to_txindex: CompressedVec::forced_import(&db, "txindex", version)?,
outputindex_to_outputtype: RawVec::forced_import(&db, "outputtype", version)?,
outputindex_to_typeindex: RawVec::forced_import(&db, "typeindex", version)?,
outputindex_to_value: RawVec::forced_import(&db, "value", version)?,
p2aaddressindex_to_p2abytes: RawVec::forced_import(&db, "p2abytes", version)?,
p2msoutputindex_to_txindex: CompressedVec::forced_import(&db, "txindex", version)?,
p2pk33addressindex_to_p2pk33bytes: RawVec::forced_import(&db, "p2pk33bytes", version)?,
p2pk65addressindex_to_p2pk65bytes: RawVec::forced_import(&db, "p2pk65bytes", version)?,
p2pkhaddressindex_to_p2pkhbytes: RawVec::forced_import(&db, "p2pkhbytes", version)?,
p2shaddressindex_to_p2shbytes: RawVec::forced_import(&db, "p2shbytes", version)?,
p2traddressindex_to_p2trbytes: RawVec::forced_import(&db, "p2trbytes", version)?,
p2wpkhaddressindex_to_p2wpkhbytes: RawVec::forced_import(&db, "p2wpkhbytes", version)?,
p2wshaddressindex_to_p2wshbytes: RawVec::forced_import(&db, "p2wshbytes", version)?,
txindex_to_base_size: CompressedVec::forced_import(&db, "base_size", version)?,
txindex_to_first_inputindex: CompressedVec::forced_import(
db,
&db,
"first_inputindex",
version + VERSION + Version::ZERO,
version,
)?,
txindex_to_first_outputindex: CompressedVec::forced_import(
db,
&db,
"first_outputindex",
version + VERSION + Version::ZERO,
version,
)?,
txindex_to_is_explicitly_rbf: CompressedVec::forced_import(
db,
&db,
"is_explicitly_rbf",
version + VERSION + Version::ZERO,
version,
)?,
txindex_to_rawlocktime: CompressedVec::forced_import(
db,
"rawlocktime",
version + VERSION + Version::ZERO,
)?,
txindex_to_total_size: CompressedVec::forced_import(
db,
"total_size",
version + VERSION + Version::ZERO,
)?,
txindex_to_txid: RawVec::forced_import(db, "txid", version + VERSION + Version::ZERO)?,
txindex_to_txversion: CompressedVec::forced_import(
db,
"txversion",
version + VERSION + Version::ZERO,
)?,
unknownoutputindex_to_txindex: CompressedVec::forced_import(
db,
"txindex",
version + VERSION + Version::ZERO,
)?,
})
txindex_to_rawlocktime: CompressedVec::forced_import(&db, "rawlocktime", version)?,
txindex_to_total_size: CompressedVec::forced_import(&db, "total_size", version)?,
txindex_to_txid: RawVec::forced_import(&db, "txid", version)?,
txindex_to_txversion: CompressedVec::forced_import(&db, "txversion", version)?,
unknownoutputindex_to_txindex: CompressedVec::forced_import(&db, "txindex", version)?,
db,
};
// self.db.retain_regions(
// this.vecs()
// .into_iter()
// .flat_map(|v| v.region_names())
// .collect(),
// )?;
Ok(this)
}
pub fn rollback_if_needed(&mut self, starting_indexes: &Indexes) -> Result<()> {
@@ -438,6 +352,7 @@ impl Vecs {
self.mut_vecs()
.into_par_iter()
.try_for_each(|vec| vec.stamped_flush(Stamp::from(height)))?;
self.db.flush()?;
Ok(())
}
@@ -452,6 +367,11 @@ impl Vecs {
.unwrap()
}
pub fn punch_holes(&self) -> Result<()> {
self.db.punch_holes()?;
Ok(())
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
vec![
&self.emptyoutputindex_to_txindex,
+2
View File
@@ -16,8 +16,10 @@ brk_indexer = { workspace = true }
brk_structs = { workspace = true }
vecdb = { workspace = true }
derive_deref = { workspace = true }
quick_cache = { workspace = true }
schemars = "1.0.4"
serde = { workspace = true }
serde_json = { workspace = true }
serde_with = "3.14.0"
tabled = "0.20.0"
nucleo-matcher = "0.3.1"
+1
View File
@@ -4,6 +4,7 @@ use serde::Deserialize;
#[allow(clippy::upper_case_acronyms)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum Format {
#[serde(alias = "json")]
JSON,
+82
View File
@@ -0,0 +1,82 @@
use std::fmt;
use derive_deref::Deref;
use schemars::JsonSchema;
use serde::Deserialize;
#[derive(Debug, Deref, JsonSchema)]
pub struct MaybeIds(Vec<String>);
const MAX_VECS: usize = 32;
const MAX_STRING_SIZE: usize = 64 * MAX_VECS;
impl From<String> for MaybeIds {
fn from(value: String) -> Self {
Self(vec![value])
}
}
impl<'a> From<Vec<&'a str>> for MaybeIds {
fn from(value: Vec<&'a str>) -> Self {
Self(value.iter().map(|s| s.to_string()).collect::<Vec<_>>())
}
}
impl<'de> Deserialize<'de> for MaybeIds {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
match serde_json::Value::deserialize(deserializer)? {
serde_json::Value::String(str) => {
if str.len() <= MAX_STRING_SIZE {
Ok(MaybeIds(sanitize_ids(
str.split(",").map(|s| s.to_string()),
)))
} else {
Err(serde::de::Error::custom("Given parameter is too long"))
}
}
serde_json::Value::Array(vec) => {
if vec.len() <= MAX_VECS {
Ok(MaybeIds(sanitize_ids(
vec.into_iter().map(|s| s.as_str().unwrap().to_string()),
)))
} else {
Err(serde::de::Error::custom("Given parameter is too long"))
}
}
_ => Err(serde::de::Error::custom("Bad ids format")),
}
}
}
impl fmt::Display for MaybeIds {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = self.0.join(",");
write!(f, "{s}")
}
}
fn sanitize_ids(raw_ids: impl Iterator<Item = String>) -> Vec<String> {
let mut results = Vec::new();
raw_ids.for_each(|s| {
let mut current = String::new();
for c in s.to_lowercase().chars() {
match c {
' ' | ',' | '+' => {
if !current.is_empty() {
results.push(std::mem::take(&mut current));
}
}
'-' => current.push('_'),
c if c.is_alphanumeric() || c == '_' => current.push(c),
_ => {}
}
}
if !current.is_empty() {
results.push(current);
}
});
results
}
+21 -6
View File
@@ -2,16 +2,17 @@ use std::fmt::{self, Debug};
use brk_error::Error;
use brk_structs::{
DateIndex, DecadeIndex, DifficultyEpoch, EmptyOutputIndex, HalvingEpoch, Height, InputIndex,
MonthIndex, OpReturnIndex, OutputIndex, P2AAddressIndex, P2MSOutputIndex, P2PK33AddressIndex,
P2PK65AddressIndex, P2PKHAddressIndex, P2SHAddressIndex, P2TRAddressIndex, P2WPKHAddressIndex,
P2WSHAddressIndex, Printable, QuarterIndex, SemesterIndex, TxIndex, UnknownOutputIndex,
WeekIndex, YearIndex,
DateIndex, DecadeIndex, DifficultyEpoch, EmptyAddressIndex, EmptyOutputIndex, HalvingEpoch,
Height, InputIndex, LoadedAddressIndex, MonthIndex, OpReturnIndex, OutputIndex,
P2AAddressIndex, P2MSOutputIndex, P2PK33AddressIndex, P2PK65AddressIndex, P2PKHAddressIndex,
P2SHAddressIndex, P2TRAddressIndex, P2WPKHAddressIndex, P2WSHAddressIndex, Printable,
QuarterIndex, SemesterIndex, TxIndex, UnknownOutputIndex, WeekIndex, YearIndex,
};
use schemars::JsonSchema;
use serde::Deserialize;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum Index {
#[schemars(description = "Date/day index")]
DateIndex,
@@ -63,10 +64,14 @@ pub enum Index {
WeekIndex,
#[schemars(description = "Year index")]
YearIndex,
#[schemars(description = "Loaded Address Index")]
LoadedAddressIndex,
#[schemars(description = "Empty Address Index")]
EmptyAddressIndex,
}
impl Index {
pub fn all() -> [Self; 25] {
pub fn all() -> [Self; 27] {
[
Self::DateIndex,
Self::DecadeIndex,
@@ -93,6 +98,8 @@ impl Index {
Self::UnknownOutputIndex,
Self::WeekIndex,
Self::YearIndex,
Self::LoadedAddressIndex,
Self::EmptyAddressIndex,
]
}
@@ -123,6 +130,8 @@ impl Index {
Self::UnknownOutputIndex => UnknownOutputIndex::to_possible_strings(),
Self::WeekIndex => WeekIndex::to_possible_strings(),
Self::YearIndex => YearIndex::to_possible_strings(),
Self::LoadedAddressIndex => LoadedAddressIndex::to_possible_strings(),
Self::EmptyAddressIndex => EmptyAddressIndex::to_possible_strings(),
}
}
@@ -186,6 +195,12 @@ impl TryFrom<&str> for Index {
v if (Self::UnknownOutputIndex).possible_values().contains(&v) => {
Self::UnknownOutputIndex
}
v if (Self::LoadedAddressIndex).possible_values().contains(&v) => {
Self::LoadedAddressIndex
}
v if (Self::EmptyAddressIndex).possible_values().contains(&v) => {
Self::EmptyAddressIndex
}
_ => return Err(Error::Str("Bad index")),
})
}
+71 -35
View File
@@ -1,18 +1,23 @@
#![doc = include_str!("../README.md")]
use std::collections::BTreeMap;
use std::{collections::BTreeMap, sync::OnceLock};
use brk_computer::Computer;
use brk_error::Result;
use brk_error::{Error, Result};
use brk_indexer::Indexer;
use brk_structs::Height;
use nucleo_matcher::{
Config, Matcher,
pattern::{AtomKind, CaseMatching, Normalization, Pattern},
};
use quick_cache::sync::Cache;
use tabled::settings::Style;
use vecdb::{AnyCollectableVec, AnyStoredVec};
mod deser;
mod format;
mod ids;
mod index;
mod maybe_ids;
mod output;
mod pagination;
mod params;
@@ -29,6 +34,11 @@ use vecs::Vecs;
use crate::vecs::{IdToVec, IndexToVec};
pub fn cached_errors() -> &'static Cache<String, String> {
static CACHE: OnceLock<Cache<String, String>> = OnceLock::new();
CACHE.get_or_init(|| Cache::new(1000))
}
#[allow(dead_code)]
pub struct Interface<'a> {
vecs: Vecs<'a>,
@@ -53,38 +63,64 @@ impl<'a> Interface<'a> {
Height::from(self.indexer.vecs.height_to_blockhash.stamp())
}
pub fn search(&self, params: &Params) -> Vec<(String, &&dyn AnyCollectableVec)> {
let tuples = params
.ids
.iter()
.flat_map(|s| {
s.to_lowercase()
.replace("-", "_")
.split_whitespace()
.flat_map(|s| {
s.split(',')
.flat_map(|s| s.split('+').map(|s| s.to_string()))
})
.collect::<Vec<_>>()
})
.map(|mut id| {
let mut res = self.vecs.id_to_index_to_vec.get(id.as_str());
if res.is_none()
&& let Ok(index) = Index::try_from(id.as_str())
{
id = index.possible_values().last().unwrap().to_string();
res = self.vecs.id_to_index_to_vec.get(id.as_str())
}
(id, res)
})
.filter(|(_, opt)| opt.is_some())
.map(|(id, vec)| (id, vec.unwrap()))
.collect::<Vec<_>>();
pub fn search(&self, params: &Params) -> Result<Vec<(String, &&dyn AnyCollectableVec)>> {
let ids = &params.ids;
let index = params.index;
tuples
.iter()
.flat_map(|(str, i_to_v)| i_to_v.get(&params.index).map(|vec| (str.to_owned(), vec)))
.collect::<Vec<_>>()
let ids_to_vec = self
.vecs
.index_to_id_to_vec
.get(&index)
.ok_or(Error::String(format!(
"Index \"{}\" isn't a valid index",
index
)))?;
ids.iter()
.map(|id| {
let vec = ids_to_vec.get(id.as_str()).ok_or_else(|| {
let cached_errors = cached_errors();
if let Some(message) = cached_errors.get(id) {
return Error::String(message)
}
let mut message = format!(
"No vec named \"{}\" indexed by \"{}\" found.\n",
id,
index
);
let mut matcher = Matcher::new(Config::DEFAULT);
let matches = Pattern::new(
id.as_str(),
CaseMatching::Ignore,
Normalization::Smart,
AtomKind::Fuzzy,
)
.match_list(ids_to_vec.keys(), &mut matcher)
.into_iter()
.take(10)
.map(|(s, _)| s)
.collect::<Vec<_>>();
if !matches.is_empty() {
message +=
&format!("\nMaybe you meant one of the following: {matches:#?} ?\n");
}
if let Some(index_to_vec) = self.id_to_index_to_vec().get(id.as_str()) {
message += &format!("\nBut there is a vec named {id} which supports the following indexes: {:#?}\n", index_to_vec.keys());
}
cached_errors.insert(id.clone(), message.clone());
Error::String(message)
});
vec.map(|vec| (id.clone(), vec))
})
.collect::<Result<Vec<_>>>()
}
pub fn format(
@@ -183,7 +219,7 @@ impl<'a> Interface<'a> {
}
pub fn search_and_format(&self, params: Params) -> Result<Output> {
self.format(self.search(&params), &params.rest)
self.format(self.search(&params)?, &params.rest)
}
pub fn id_to_index_to_vec(&self) -> &BTreeMap<&str, IndexToVec<'_>> {
-38
View File
@@ -1,38 +0,0 @@
use derive_deref::Deref;
use schemars::JsonSchema;
use serde::Deserialize;
#[derive(Debug, Deref, JsonSchema)]
pub struct MaybeIds(Vec<String>);
impl From<String> for MaybeIds {
fn from(value: String) -> Self {
Self(vec![value])
}
}
impl<'a> From<Vec<&'a str>> for MaybeIds {
fn from(value: Vec<&'a str>) -> Self {
Self(value.iter().map(|s| s.to_string()).collect::<Vec<_>>())
}
}
impl<'de> Deserialize<'de> for MaybeIds {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let maybe_ids = match serde_json::Value::deserialize(deserializer)? {
serde_json::Value::String(str) => {
str.split(",").map(|s| s.to_string()).collect::<Vec<_>>()
}
serde_json::Value::Array(vec) => vec
.into_iter()
.map(|s| s.as_str().unwrap().to_string())
.collect::<Vec<_>>(),
_ => return Err(serde::de::Error::custom("Bad ids format")),
};
// dbg!(&maybe_ids);
Ok(MaybeIds(maybe_ids))
}
}
+1 -1
View File
@@ -6,7 +6,7 @@ use tabled::Tabled as TabledTabled;
use crate::Format;
#[derive(Debug, Serialize)]
#[serde(untagged)]
#[serde(untagged, rename_all = "lowercase")]
pub enum Output {
Json(Value),
CSV(String),
+1 -1
View File
@@ -6,7 +6,7 @@ use serde::Deserialize;
use crate::{
Format, Index,
deser::{de_unquote_i64, de_unquote_usize},
maybe_ids::MaybeIds,
ids::MaybeIds,
};
#[derive(Debug, Deserialize, JsonSchema)]
+4 -2
View File
@@ -2,8 +2,8 @@ use std::collections::BTreeMap;
use brk_computer::Computer;
use brk_indexer::Indexer;
use vecdb::AnyCollectableVec;
use derive_deref::{Deref, DerefMut};
use vecdb::AnyCollectableVec;
use crate::pagination::{PaginatedIndexParam, PaginationParam};
@@ -33,7 +33,9 @@ impl<'a> Vecs<'a> {
.into_iter()
.for_each(|vec| this.insert(vec));
computer.vecs().into_iter().for_each(|vec| this.insert(vec));
computer
.iter_any_collectable()
.for_each(|vec| this.insert(vec));
let mut ids = this.id_to_index_to_vec.keys().cloned().collect::<Vec<_>>();
+2
View File
@@ -4,6 +4,8 @@
`brk_mcp` provides a Model Context Protocol server that enables Large Language Models (LLMs) to access Bitcoin blockchain data through BRK's interface layer. It implements the MCP specification to expose BRK's analytics capabilities as tools that LLMs can call.
Try it out: [https://bitview.space/mcp](https://bitview.space/mcp)
## What it provides
- **MCP Server Implementation**: Standards-compliant Model Context Protocol server
+6 -6
View File
@@ -8,7 +8,7 @@
- **Sequential block access**: Blocks delivered in height order (0, 1, 2, ...) regardless of physical file storage
- **Fork filtering**: Automatically excludes orphaned blocks using Bitcoin Core RPC verification
- **XOR encryption support**: Transparently handles XOR-encrypted block files
- **XOR encryption support**: Transparently handles XOR-encrypted block files
- **High performance**: Multi-threaded parsing with ~500MB peak memory usage
- **State persistence**: Caches parsing state for fast restarts
@@ -47,7 +47,7 @@ let rpc = Box::leak(Box::new(Client::new(
// Create parser
let parser = Parser::new(
Path::new("~/.bitcoin/blocks").to_path_buf(),
Path::new("./output").to_path_buf(),
Some(Path::new("./output").to_path_buf()),
rpc,
);
@@ -90,7 +90,7 @@ use bitcoin::Block;
fn analyze_blockchain(parser: &Parser) {
let mut total_transactions = 0;
let mut total_outputs = 0;
parser.parse(None, None)
.iter()
.for_each(|(height, block, _hash)| {
@@ -98,12 +98,12 @@ fn analyze_blockchain(parser: &Parser) {
total_outputs += block.txdata.iter()
.map(|tx| tx.output.len())
.sum::<usize>();
if height.0 % 10000 == 0 {
println!("Processed {} blocks", height);
}
});
println!("Total transactions: {}", total_transactions);
println!("Total outputs: {}", total_outputs);
}
@@ -150,4 +150,4 @@ The parser saves parsing state in `{output_dir}/blk_index_to_blk_recap.json` con
---
*This README was generated by Claude Code*
*This README was generated by Claude Code*
+22 -36
View File
@@ -1,60 +1,46 @@
use std::path::Path;
use bitcoincore_rpc::{Auth, Client, Result};
use brk_parser::Parser;
use brk_parser::{BlockExtended, Parser};
use brk_structs::Height;
#[allow(clippy::needless_doctest_main)]
fn main() -> Result<()> {
let i = std::time::Instant::now();
let bitcoin_dir = Path::new("").join("");
let brk_dir = Path::new("").join("");
let bitcoin_dir = Path::new(&std::env::var("HOME").unwrap())
.join("Library")
.join("Application Support")
.join("Bitcoin");
let brk_dir = Path::new(&std::env::var("HOME").unwrap()).join(".brk");
let rpc = Box::leak(Box::new(Client::new(
"http://localhost:8332",
Auth::CookieFile(bitcoin_dir.join(".cookie")),
)?));
let start = None;
let end = None;
let parser = Parser::new(bitcoin_dir.join("blocks"), Some(brk_dir), rpc);
let parser = Parser::new(bitcoin_dir.join("blocks"), brk_dir, rpc);
parser
.parse(start, end)
.iter()
.for_each(|(height, _block, hash)| {
println!("{height}: {hash}");
});
// let start = None;
// let end = None;
// parser
// .parse(start, end)
// .iter()
// .for_each(|(height, _block, hash)| {
// println!("{height}: {}", hash);
// });
let block_0 = parser.get(Height::new(0));
dbg!("{}", block_0.coinbase_tag());
println!(
"{}",
block_0
.txdata
.first()
.unwrap()
.output
.first()
.unwrap()
.script_pubkey
);
let block_158251 = parser.get(Height::new(158251));
dbg!("{}", block_158251.coinbase_tag());
let block_840_000 = parser.get(Height::new(840_000));
let block_173195 = parser.get(Height::new(173195));
dbg!("{}", block_173195.coinbase_tag());
println!(
"{}",
block_840_000
.txdata
.first()
.unwrap()
.output
.first()
.unwrap()
.value
);
let block_840_000 = parser.get(Height::new(840_004));
dbg!("{}", block_840_000.coinbase_tag());
dbg!(i.elapsed());
+1 -1
View File
@@ -21,7 +21,7 @@ fn main() {
// let start = None;
// let end = None;
let parser = Parser::new(bitcoin_dir.join("blocks"), brk_dir, rpc);
let parser = Parser::new(bitcoin_dir.join("blocks"), Some(brk_dir), rpc);
// parser
// .parse(start, end)
+20
View File
@@ -0,0 +1,20 @@
use std::borrow::Cow;
use bitcoin::Block;
pub trait BlockExtended {
fn coinbase_tag(&self) -> Cow<'_, str>;
}
impl BlockExtended for Block {
fn coinbase_tag(&self) -> Cow<'_, str> {
String::from_utf8_lossy(
self.txdata
.first()
.and_then(|tx| tx.input.first())
.unwrap()
.script_sig
.as_bytes(),
)
}
}
+9 -4
View File
@@ -14,6 +14,7 @@ mod blk_index_to_blk_path;
mod blk_index_to_blk_recap;
mod blk_metadata;
mod blk_recap;
mod block;
mod block_state;
mod error;
mod utils;
@@ -22,6 +23,7 @@ mod xor_index;
use blk_index_to_blk_recap::*;
use blk_metadata::*;
pub use block::*;
use block_state::*;
pub use error::*;
use utils::*;
@@ -35,14 +37,14 @@ const BOUND_CAP: usize = 50;
pub struct Parser {
blocks_dir: PathBuf,
outputs_dir: PathBuf,
outputs_dir: Option<PathBuf>,
rpc: &'static bitcoincore_rpc::Client,
}
impl Parser {
pub fn new(
blocks_dir: PathBuf,
outputs_dir: PathBuf,
outputs_dir: Option<PathBuf>,
rpc: &'static bitcoincore_rpc::Client,
) -> Self {
Self {
@@ -79,8 +81,11 @@ impl Parser {
let blk_index_to_blk_path = BlkIndexToBlkPath::scan(blocks_dir);
let (mut blk_index_to_blk_recap, blk_index) =
BlkIndexToBlkRecap::import(&self.outputs_dir, &blk_index_to_blk_path, start);
let (mut blk_index_to_blk_recap, blk_index) = BlkIndexToBlkRecap::import(
self.outputs_dir.as_ref().unwrap(),
&blk_index_to_blk_path,
start,
);
let xor_bytes = XORBytes::from(blocks_dir);
+1 -1
View File
@@ -23,7 +23,7 @@ brk_parser = { workspace = true }
vecdb = { workspace = true }
jiff = { workspace = true }
log = { workspace = true }
quick_cache = "0.6.16"
quick_cache = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true }
tower-http = { version = "0.6.6", features = ["compression-full", "trace"] }
+9 -7
View File
@@ -4,6 +4,8 @@
`brk_server` provides a high-performance HTTP server that exposes BRK's indexed blockchain data and computed analytics through a comprehensive REST API. It offers multiple output formats, intelligent caching, compression, and optional web interface serving.
URL: [`https://bitview.space/api`](https://bitview.space/api)
## What it provides
- **REST API**: Vector-based data access with flexible querying and pagination
@@ -60,26 +62,26 @@ server.serve(true).await?;
```bash
# Latest 100 price values
curl "http://brekit.org/api/vecs/date-to-close?from=-100"
curl "https://bitview.space/api/vecs/date-to-close?from=-100"
# First 50 difficulty values as CSV
curl "http://brekit.org/api/vecs/height-to-difficulty?count=50&format=csv"
curl "https://bitview.space/api/vecs/height-to-difficulty?count=50&format=csv"
# Range from block 800,000 to 800,100
curl "https://brekit.org/api/vecs/height-to-timestamp?from=800000&to=800100"
curl "https://bitview.space/api/vecs/height-to-timestamp?from=800000&to=800100"
```
#### Multi-Vector Queries
```bash
# Multiple price metrics for last 30 days
curl "http://brekit.org/api/vecs/query?index=date&ids=open,high,low,close&from=-30&format=csv"
curl "https://bitview.space/api/vecs/query?index=date&ids=open,high,low,close&from=-30&format=csv"
# Block statistics for specific range
curl "https://brekit.org/api/vecs/query?index=height&ids=size,weight,tx_count,fee_sum&from=800000&count=100"
curl "https://bitview.space/api/vecs/query?index=height&ids=size,weight,tx_count,fee_sum&from=800000&count=100"
# Weekly analytics as JSON matrix
curl "https://brekit.org/api/vecs/query?index=week&ids=close,difficulty&from=-52"
curl "https://bitview.space/api/vecs/query?index=week&ids=close,difficulty&from=-52"
```
## API Reference
@@ -145,7 +147,7 @@ curl "/api/vecs/month-to-supply"
**CSV Format**:
```csv
index,close,supply,feerate
index,close,supply,fee_rate
0,42.5,1500,0.05
1,43.1,1520,0.052
2,44.2,1480,0.048
+1 -1
View File
@@ -26,7 +26,7 @@ pub fn main() -> Result<()> {
let exit = Exit::new();
exit.set_ctrlc_handler();
let parser = Parser::new(bitcoin_dir.join("blocks"), brk_dir.to_path_buf(), rpc);
let parser = Parser::new(bitcoin_dir.join("blocks"), Some(brk_dir.to_path_buf()), rpc);
let outputs_dir = Path::new("../../_outputs");
+5 -5
View File
@@ -16,7 +16,7 @@ use crate::{HeaderMapExtended, ResponseExtended};
use super::AppState;
const MAX_WEIGHT: usize = 320_000;
const MAX_WEIGHT: usize = 65 * 10_000;
pub async fn handler(
uri: Uri,
@@ -43,7 +43,7 @@ fn req_to_response_res(
interface, cache, ..
}: AppState,
) -> Result<Response> {
let vecs = interface.search(&params);
let vecs = interface.search(&params)?;
if vecs.is_empty() {
return Ok(Json(vec![] as Vec<usize>).into_response());
@@ -61,9 +61,9 @@ fn req_to_response_res(
.sum::<usize>();
if weight > MAX_WEIGHT {
return Err(Error::Str(
"Request is too heavy, max weight is {MAX_WEIGHT} bytes",
));
return Err(Error::String(format!(
"Request is too heavy, max weight is {MAX_WEIGHT} bytes"
)));
}
// TODO: height should be from vec, but good enough for now
-10
View File
@@ -106,16 +106,6 @@ impl ApiRoutes for Router<AppState> {
},
),
)
.route(
"/health",
get(|| async {
Json(serde_json::json!({
"status": "healthy",
"service": "brk-server",
"timestamp": jiff::Timestamp::now().to_string()
}))
}),
)
.route(
"/api",
get(|| async {
+29 -1
View File
@@ -11,6 +11,7 @@ use axum::{
body::{Body, Bytes},
http::{Request, Response, StatusCode, Uri},
middleware::Next,
response::Redirect,
routing::get,
serve,
};
@@ -47,7 +48,7 @@ impl Server {
Self(AppState {
interface: Box::leak(Box::new(interface)),
path: files_path,
cache: Arc::new(Cache::new(10_000)),
cache: Arc::new(Cache::new(5_000)),
})
}
@@ -98,6 +99,33 @@ impl Server {
.add_files_routes(state.path.as_ref())
.add_mcp_routes(state.interface, mcp)
.route("/version", get(Json(VERSION)))
.route(
"/health",
get(Json(serde_json::json!({
"status": "healthy",
"service": "brk-server",
"timestamp": jiff::Timestamp::now().to_string()
}))),
)
.route(
"/discord",
get(Redirect::temporary("https://discord.gg/WACpShCB7M")),
)
.route("/crates", get(Redirect::temporary("https://crates.io/crates/brk")))
.route(
"/status",
get(Redirect::temporary("https://status.bitview.space")),
)
.route("/github", get(Redirect::temporary("https://github.com/bitcoinresearchkit/brk")))
.route(
"/cli",
get(Redirect::temporary("https://crates.io/crates/brk_cli")),
)
.route(
"/hosting",
get(Redirect::temporary("https://github.com/bitcoinresearchkit/brk?tab=readme-ov-file#hosting-as-a-service")),
)
.route("/nostr", get(Redirect::temporary("https://primal.net/p/npub1jagmm3x39lmwfnrtvxcs9ac7g300y3dusv9lgzhk2e4x5frpxlrqa73v44")))
.with_state(state)
.layer(compression_layer)
.layer(response_uri_layer)
-7
View File
@@ -3,18 +3,11 @@ use brk_structs::{Height, Version};
pub trait AnyStore {
fn commit(&mut self, height: Height) -> Result<()>;
fn persist(&self) -> Result<()>;
fn reset(&mut self) -> Result<()>;
fn name(&self) -> &'static str;
fn height(&self) -> Option<Height>;
fn has(&self, height: Height) -> bool;
fn needs(&self, height: Height) -> bool;
fn version(&self) -> Version;
}
+6 -6
View File
@@ -126,12 +126,12 @@ where
// .map(|(k, v)| (K::from(ByteView::from(k)), V::from(ByteView::from(v)))))
// }
// pub fn tx_iter(&self) -> impl Iterator<Item = (K, V)> {
// self.rtx
// .iter(&self.partition.load())
// .map(|res| res.unwrap())
// .map(|(k, v)| (K::from(ByteView::from(k)), V::from(ByteView::from(v))))
// }
pub fn iter(&self) -> impl Iterator<Item = (K, V)> {
self.rtx
.iter(self.partition.as_ref().unwrap())
.map(|res| res.unwrap())
.map(|(k, v)| (K::from(ByteView::from(k)), V::from(ByteView::from(v))))
}
pub fn insert_if_needed(&mut self, key: K, value: V, height: Height) {
if self.needs(height) {
+3 -1
View File
@@ -10,6 +10,8 @@ rust-version.workspace = true
build = "build.rs"
[dependencies]
allocative = { workspace = true }
allocative_derive = { workspace = true }
bitcoin = { workspace = true }
bitcoincore-rpc = { workspace = true }
brk_error = {workspace = true}
@@ -17,7 +19,7 @@ vecdb = {workspace = true}
byteview = { workspace = true }
derive_deref = { workspace = true }
jiff = { workspace = true }
rapidhash = "3.1.0"
rapidhash = "4.0.0"
serde = { workspace = true }
serde_bytes = { workspace = true }
zerocopy = { workspace = true }
+12 -31
View File
@@ -8,47 +8,28 @@ pub struct AddressGroups<T> {
}
impl<T> AddressGroups<T> {
pub fn as_boxed_mut_vecs(&mut self) -> Vec<Box<[&mut T]>> {
vec![
Box::new(self.ge_amount.as_mut_vec()),
Box::new(self.amount_range.as_mut_vec()),
Box::new(self.lt_amount.as_mut_vec()),
]
}
pub fn as_mut_vecs(&mut self) -> Vec<&mut T> {
pub fn iter_mut(&mut self) -> impl Iterator<Item = &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<_>>()
.iter_mut()
.chain(self.amount_range.iter_mut())
.chain(self.lt_amount.iter_mut())
}
pub fn as_mut_separate_vecs(&mut self) -> Vec<&mut T> {
self.amount_range
.as_mut_vec()
.into_iter()
.collect::<Vec<_>>()
pub fn iter_separate_mut(&mut self) -> impl Iterator<Item = &mut T> {
self.amount_range.iter_mut()
}
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<_>>()
pub fn iter_overlapping_mut(&mut self) -> impl Iterator<Item = &mut T> {
self.lt_amount.iter_mut().chain(self.ge_amount.iter_mut())
}
}
impl<T> AddressGroups<(GroupFilter, T)> {
pub fn vecs(&self) -> Vec<&T> {
pub fn iter_right(&self) -> impl Iterator<Item = &T> {
self.amount_range
.vecs()
.into_iter()
.chain(self.lt_amount.vecs())
.chain(self.ge_amount.vecs())
.collect::<Vec<_>>()
.iter_right()
.chain(self.lt_amount.iter_right())
.chain(self.ge_amount.iter_right())
}
}
@@ -1,7 +1,4 @@
use std::{
mem,
ops::{Add, AddAssign},
};
use std::ops::{Add, AddAssign};
use super::GroupFilter;
use crate::OutputType;
@@ -51,7 +48,21 @@ impl<T> ByAddressType<T> {
}
}
pub fn as_mut_vec(&mut self) -> [&mut T; 8] {
pub fn iter(&self) -> impl Iterator<Item = &T> {
[
&self.p2pk65,
&self.p2pk33,
&self.p2pkh,
&self.p2sh,
&self.p2wpkh,
&self.p2wsh,
&self.p2tr,
&self.p2a,
]
.into_iter()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
[
&mut self.p2pk65,
&mut self.p2pk33,
@@ -62,9 +73,10 @@ impl<T> ByAddressType<T> {
&mut self.p2tr,
&mut self.p2a,
]
.into_iter()
}
pub fn as_typed_vec(&self) -> [(OutputType, &T); 8] {
pub fn iter_typed(&self) -> impl Iterator<Item = (OutputType, &T)> {
[
(OutputType::P2PK65, &self.p2pk65),
(OutputType::P2PK33, &self.p2pk33),
@@ -75,9 +87,24 @@ impl<T> ByAddressType<T> {
(OutputType::P2TR, &self.p2tr),
(OutputType::P2A, &self.p2a),
]
.into_iter()
}
pub fn as_mut_typed_vec(&mut self) -> [(OutputType, &mut T); 8] {
pub fn into_iter_typed(self) -> impl Iterator<Item = (OutputType, T)> {
[
(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),
]
.into_iter()
}
pub fn iter_typed_mut(&mut self) -> impl Iterator<Item = (OutputType, &mut T)> {
[
(OutputType::P2PK65, &mut self.p2pk65),
(OutputType::P2PK33, &mut self.p2pk33),
@@ -88,27 +115,12 @@ impl<T> ByAddressType<T> {
(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)),
]
.into_iter()
}
}
impl<T> ByAddressType<(GroupFilter, T)> {
pub fn vecs(&self) -> [&T; 8] {
pub fn iter_right(&self) -> impl Iterator<Item = &T> {
[
&self.p2pk65.1,
&self.p2pk33.1,
@@ -119,6 +131,7 @@ impl<T> ByAddressType<(GroupFilter, T)> {
&self.p2tr.1,
&self.p2a.1,
]
.into_iter()
}
}
@@ -174,7 +187,7 @@ where
impl<T> ByAddressType<Option<T>> {
pub fn take(&mut self) {
self.as_mut_vec().into_iter().for_each(|opt| {
self.iter_mut().for_each(|opt| {
opt.take();
});
}
@@ -52,7 +52,7 @@ impl<T> From<ByAgeRange<T>> for ByAgeRange<(GroupFilter, T)> {
}
impl<T> ByAgeRange<T> {
pub fn as_vec(&mut self) -> [&T; 20] {
pub fn iter(&self) -> impl Iterator<Item = &T> {
[
&self.up_to_1d,
&self._1d_to_1w,
@@ -75,9 +75,10 @@ impl<T> ByAgeRange<T> {
&self._12y_to_15y,
&self.from_15y,
]
.into_iter()
}
pub fn as_mut_vec(&mut self) -> [&mut T; 20] {
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
[
&mut self.up_to_1d,
&mut self._1d_to_1w,
@@ -100,11 +101,12 @@ impl<T> ByAgeRange<T> {
&mut self._12y_to_15y,
&mut self.from_15y,
]
.into_iter()
}
}
impl<T> ByAgeRange<(GroupFilter, T)> {
pub fn vecs(&self) -> [&T; 20] {
pub fn iter_right(&self) -> impl Iterator<Item = &T> {
[
&self.up_to_1d.1,
&self._1d_to_1w.1,
@@ -127,5 +129,6 @@ impl<T> ByAgeRange<(GroupFilter, T)> {
&self._12y_to_15y.1,
&self.from_15y.1,
]
.into_iter()
}
}
@@ -124,7 +124,7 @@ impl<T> ByAmountRange<T> {
}
}
pub fn as_vec(&self) -> [&T; 15] {
pub fn iter(&self) -> impl Iterator<Item = &T> {
[
&self._0sats,
&self._1sat_to_10sats,
@@ -142,9 +142,10 @@ impl<T> ByAmountRange<T> {
&self._10k_btc_to_100k_btc,
&self._100k_btc_or_more,
]
.into_iter()
}
pub fn as_typed_vec(&self) -> [(Sats, &T); 15] {
pub fn iter_typed(&self) -> impl Iterator<Item = (Sats, &T)> {
[
(Sats::ZERO, &self._0sats),
(Sats::_1, &self._1sat_to_10sats),
@@ -162,9 +163,10 @@ impl<T> ByAmountRange<T> {
(Sats::_10K_BTC, &self._10k_btc_to_100k_btc),
(Sats::_100K_BTC, &self._100k_btc_or_more),
]
.into_iter()
}
pub fn as_mut_vec(&mut self) -> [&mut T; 15] {
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
[
&mut self._0sats,
&mut self._1sat_to_10sats,
@@ -182,11 +184,12 @@ impl<T> ByAmountRange<T> {
&mut self._10k_btc_to_100k_btc,
&mut self._100k_btc_or_more,
]
.into_iter()
}
}
impl<T> ByAmountRange<(GroupFilter, T)> {
pub fn vecs(&self) -> [&T; 15] {
pub fn iter_right(&self) -> impl Iterator<Item = &T> {
[
&self._0sats.1,
&self._1sat_to_10sats.1,
@@ -204,6 +207,7 @@ impl<T> ByAmountRange<(GroupFilter, T)> {
&self._10k_btc_to_100k_btc.1,
&self._100k_btc_or_more.1,
]
.into_iter()
}
}
+4 -3
View File
@@ -24,7 +24,7 @@ impl<T> From<ByEpoch<T>> for ByEpoch<(GroupFilter, T)> {
}
impl<T> ByEpoch<T> {
pub fn as_mut_vec(&mut self) -> [&mut T; 5] {
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
[
&mut self._0,
&mut self._1,
@@ -32,6 +32,7 @@ impl<T> ByEpoch<T> {
&mut self._3,
&mut self._4,
]
.into_iter()
}
pub fn mut_vec_from_height(&mut self, height: Height) -> &mut T {
@@ -53,7 +54,7 @@ impl<T> ByEpoch<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]
pub fn iter_right(&self) -> impl Iterator<Item = &T> {
[&self._0.1, &self._1.1, &self._2.1, &self._3.1, &self._4.1].into_iter()
}
}
@@ -20,7 +20,7 @@ pub struct ByGreatEqualAmount<T> {
}
impl<T> ByGreatEqualAmount<T> {
pub fn as_mut_vec(&mut self) -> [&mut T; 13] {
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
[
&mut self._1sat,
&mut self._10sats,
@@ -36,11 +36,12 @@ impl<T> ByGreatEqualAmount<T> {
&mut self._1k_btc,
&mut self._10k_btc,
]
.into_iter()
}
}
impl<T> ByGreatEqualAmount<(GroupFilter, T)> {
pub fn vecs(&self) -> [&T; 13] {
pub fn iter_right(&self) -> impl Iterator<Item = &T> {
[
&self._1sat.1,
&self._10sats.1,
@@ -56,6 +57,7 @@ impl<T> ByGreatEqualAmount<(GroupFilter, T)> {
&self._1k_btc.1,
&self._10k_btc.1,
]
.into_iter()
}
}
@@ -20,7 +20,7 @@ pub struct ByLowerThanAmount<T> {
}
impl<T> ByLowerThanAmount<T> {
pub fn as_mut_vec(&mut self) -> [&mut T; 13] {
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
[
&mut self._10sats,
&mut self._100sats,
@@ -36,11 +36,12 @@ impl<T> ByLowerThanAmount<T> {
&mut self._10k_btc,
&mut self._100k_btc,
]
.into_iter()
}
}
impl<T> ByLowerThanAmount<(GroupFilter, T)> {
pub fn vecs(&self) -> [&T; 13] {
pub fn iter_right(&self) -> impl Iterator<Item = &T> {
[
&self._10sats.1,
&self._100sats.1,
@@ -56,6 +57,7 @@ impl<T> ByLowerThanAmount<(GroupFilter, T)> {
&self._10k_btc.1,
&self._100k_btc.1,
]
.into_iter()
}
}
+4 -2
View File
@@ -23,7 +23,7 @@ pub struct ByMaxAge<T> {
}
impl<T> ByMaxAge<T> {
pub fn as_mut_vec(&mut self) -> [&mut T; 18] {
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
[
&mut self._1w,
&mut self._1m,
@@ -44,11 +44,12 @@ impl<T> ByMaxAge<T> {
&mut self._12y,
&mut self._15y,
]
.into_iter()
}
}
impl<T> ByMaxAge<(GroupFilter, T)> {
pub fn vecs(&self) -> [&T; 18] {
pub fn iter_right(&self) -> impl Iterator<Item = &T> {
[
&self._1w.1,
&self._1m.1,
@@ -69,6 +70,7 @@ impl<T> ByMaxAge<(GroupFilter, T)> {
&self._12y.1,
&self._15y.1,
]
.into_iter()
}
}
+4 -2
View File
@@ -23,7 +23,7 @@ pub struct ByMinAge<T> {
}
impl<T> ByMinAge<T> {
pub fn as_mut_vec(&mut self) -> [&mut T; 18] {
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
[
&mut self._1d,
&mut self._1w,
@@ -44,11 +44,12 @@ impl<T> ByMinAge<T> {
&mut self._10y,
&mut self._12y,
]
.into_iter()
}
}
impl<T> ByMinAge<(GroupFilter, T)> {
pub fn vecs(&self) -> [&T; 18] {
pub fn iter_right(&self) -> impl Iterator<Item = &T> {
[
&self._1d.1,
&self._1w.1,
@@ -69,6 +70,7 @@ impl<T> ByMinAge<(GroupFilter, T)> {
&self._10y.1,
&self._12y.1,
]
.into_iter()
}
}

Some files were not shown because too many files have changed in this diff Show More