Compare commits

...

81 Commits

Author SHA1 Message Date
nym21 3508d1e315 release: v0.0.84 2025-08-07 21:23:19 +02:00
nym21 e3177b8054 global: per crate build.rs 2025-08-07 21:22:38 +02:00
nym21 03e3760152 global: snapshot + lock file + better errors 2025-08-07 17:29:30 +02:00
nym21 4740610923 global: compressed vecs work again 2025-08-05 23:38:43 +02:00
nym21 e28a0cde55 vecs: fix race condition 2025-08-04 23:48:20 +02:00
nym21 5b855fd835 global: snapshot 2025-08-04 11:38:46 +02:00
nym21 a2f5704581 global: snapshot 2025-08-03 23:38:58 +02:00
nym21 f7aa9424db global: one big snapshot 2025-08-02 16:59:22 +02:00
nym21 aa8b47a3dd global: cleanup 2025-07-29 17:46:30 +02:00
nym21 11911c1898 release: v0.0.83 2025-07-26 23:35:43 +02:00
nym21 4814c1971d vecs: add linux punch hole impl 2025-07-26 23:35:23 +02:00
nym21 be9569f3fb release: v0.0.82 2025-07-26 22:09:21 +02:00
nym21 900e72f95a cargo: cleanup deps 2025-07-26 14:28:26 +02:00
nym21 d2827f188b computer: temp remove rayon 2025-07-26 14:24:06 +02:00
nym21 cf9903b759 computer: init file with min length and regions 2025-07-26 08:57:13 +02:00
nym21 23f96461f4 computer: remove libc dep 2025-07-26 08:42:33 +02:00
nym21 9f2fd26e98 computer: fixes 2025-07-26 08:41:19 +02:00
nym21 78d837c080 computer: flush + punch 2025-07-26 01:04:36 +02:00
nym21 241b9312b7 cli: config changes 2025-07-26 00:46:35 +02:00
nym21 ed70ad7378 indexer: take readers before last export 2025-07-25 22:45:41 +02:00
nym21 00213176d8 indexer: small changes 2025-07-25 22:38:15 +02:00
nym21 406650a45a vec: removed 2025-07-25 20:38:57 +02:00
nym21 56750ccf3c vecs: part 11 2025-07-25 20:27:15 +02:00
nym21 dfc286b393 vecs: part 10 2025-07-25 20:22:54 +02:00
nym21 49a66f72fc crates: update rapidhash 2025-07-24 17:32:38 +02:00
nym21 3f237689da vecs: part 9 2025-07-24 17:19:05 +02:00
nym21 cf1fb483b3 vecs: part 8 2025-07-24 16:48:50 +02:00
nym21 b10f5e3f67 vecs: part 7 2025-07-23 23:55:13 +02:00
nym21 c4fc24c513 vecs: part 6 2025-07-23 09:17:26 +02:00
nym21 3ac9c2d95e vecs: part 5 2025-07-22 21:26:50 +02:00
nym21 e5ab4dafc0 vecs: part 4 2025-07-22 17:36:34 +02:00
nym21 10ae1911c3 vecs: part 3 2025-07-22 15:10:07 +02:00
nym21 73ebcdf0d6 vecs: part 2 2025-07-22 13:19:19 +02:00
nym21 5347523921 vecs: init 2025-07-21 11:02:25 +02:00
nym21 7ef70b953b vec: lazy: remove unneeded phantoms 2025-07-19 17:47:25 +02:00
nym21 ccaca524fe computer: libc sync 2025-07-19 10:10:01 +02:00
nym21 dd51f91cab computer: final fix for external disks crashing 2025-07-18 16:29:53 +02:00
nym21 537d98b41b release: v0.0.81 2025-07-17 23:45:01 +02:00
nym21 9c4cadfc04 vec: fix holes export 2025-07-17 17:29:53 +02:00
nym21 2001370441 mcp: use rust-rmcp instead of brk-rmcp 2025-07-17 16:34:29 +02:00
nym21 cc87b22757 computer: perf improvements 2025-07-17 16:17:21 +02:00
nym21 c0a65b30ad indexer: update example 2025-07-17 11:39:25 +02:00
nym21 c07e66c086 computer: fix stateful 2025-07-17 11:35:40 +02:00
nym21 a0cfc1be2b computer: convert stores to vecs part 2 2025-07-16 16:23:40 +02:00
nym21 1505454793 computer: convert stores to vecs part 1 2025-07-15 22:47:46 +02:00
nym21 e1dff66283 pr: merge #21 from deadmanoz/dockerize
Add Docker support
2025-07-15 15:51:32 +00:00
deadmanoz 5be801a086 Merge branch 'main' into dockerize 2025-07-15 08:50:22 -07:00
deadmanoz 94d4b05c29 Address review feedback 2025-07-15 08:48:39 -07:00
nym21 cebb889f7e cargo: update 2025-07-14 16:00:31 +02:00
nym21 c4ed6ed034 store: remove rotate_memtable as could be the root cause of the issue 2025-07-14 15:48:19 +02:00
nym21 ec960bfefa release: v0.0.80 2025-07-13 21:20:40 +02:00
nym21 79f689dde1 mcp: remove claude results examples due to dead links 2025-07-13 21:20:02 +02:00
nym21 3b3654df56 vec: add local and shared stored_len to raw variant 2025-07-13 19:30:50 +02:00
nym21 c66f008f07 release: v0.0.79 2025-07-13 17:18:14 +02:00
nym21 37d9498d90 crates: upgrade 2025-07-13 17:18:02 +02:00
nym21 1ff67093db website: apply datasets changes to charts 2025-07-13 17:14:34 +02:00
nym21 daed37ccb8 stores: forgot some files 2025-07-13 16:52:19 +02:00
nym21 d41d807b4f stores: bloom filters back to default due to slow reads, v3 will bring down the needed RAM 2025-07-13 16:49:45 +02:00
nym21 d6fa5c8a55 vec: fix header reading of existing file 2025-07-13 16:31:22 +02:00
nym21 2dd608dfed vec: don't store mmap in struct anymore 2025-07-13 11:50:34 +02:00
nym21 a98546f605 release: v0.0.78 2025-07-13 02:05:28 +02:00
nym21 3567559d4e release: v0.0.77 2025-07-13 01:54:51 +02:00
nym21 216476ee45 computer: reduce number of ratio datasets for some cohorts 2025-07-13 01:25:45 +02:00
nym21 3fc28c07fb computer: missed a file 2025-07-13 00:23:32 +02:00
nym21 85f6ef063d computer: perf again 2025-07-13 00:21:20 +02:00
nym21 1e71e2d68f computer: perf 2025-07-12 16:17:29 +02:00
nym21 b24a29895f global: perf + resource imprv 2025-07-12 15:07:02 +02:00
nym21 0167a2ae59 global: fixes 2025-07-12 11:18:51 +02:00
nym21 2c867103ca computer: remove dbg 2025-07-11 14:23:26 +02:00
nym21 8c289df336 computer: stateful: perf improvements 2025-07-11 11:43:53 +02:00
nym21 4489920cbf computer: fix coarse lazy indexes 2025-07-11 01:51:04 +02:00
nym21 029a85081b global: snapshot 2025-07-10 22:32:04 +02:00
nym21 1bc739d07f vec + comp: small changes 2025-07-10 18:35:54 +02:00
nym21 c229e218f6 global: adding semester + making coarser intervals computed instead of eager 2025-07-10 17:44:19 +02:00
deadmanoz 5de9757d46 Remove services from docker 2025-07-04 16:37:39 +08:00
deadmanoz f89276d7b8 Remove redundant services 2025-07-04 15:51:28 +08:00
deadmanoz 30ba034206 Move docker artefacts into /docker directory 2025-07-04 13:00:12 +08:00
deadmanoz fa1e5aaa7f Make Parser::new the only entrypoint 2025-07-04 12:15:32 +08:00
deadmanoz 870c70180f Back to a single image/container setup 2025-07-04 11:40:37 +08:00
deadmanoz d83a833b4d Switch to multiple container setup 2025-06-27 12:56:25 +08:00
deadmanoz ec3a2f29f0 Docker functionality, change location of 'blk_index_to_blk_recap.json' 2025-06-27 12:56:03 +08:00
337 changed files with 19834 additions and 13092 deletions
+11 -6
View File
@@ -1,4 +1,4 @@
# This file was autogenerated by dist: https://opensource.axo.dev/cargo-dist/
# This file was autogenerated by dist: https://axodotdev.github.io/cargo-dist
#
# Copyright 2022-2024, axodotdev
# SPDX-License-Identifier: MIT or Apache-2.0
@@ -47,7 +47,7 @@ on:
jobs:
# Run 'dist plan' (or host) to determine what tasks we need to do
plan:
runs-on: "ubuntu-latest"
runs-on: "ubuntu-22.04"
outputs:
val: ${{ steps.plan.outputs.manifest }}
tag: ${{ !github.event.pull_request && github.ref_name || '' }}
@@ -58,12 +58,13 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
submodules: recursive
- name: Install dist
# 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.28.0/cargo-dist-installer.sh | sh"
run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.29.0/cargo-dist-installer.sh | sh"
- name: Cache dist
uses: actions/upload-artifact@v4
with:
@@ -117,6 +118,7 @@ jobs:
git config --global core.longpaths true
- uses: actions/checkout@v4
with:
persist-credentials: false
submodules: recursive
- name: Install Rust non-interactively if not already installed
if: ${{ matrix.container }}
@@ -168,13 +170,14 @@ jobs:
needs:
- plan
- build-local-artifacts
runs-on: "ubuntu-latest"
runs-on: "ubuntu-22.04"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
submodules: recursive
- name: Install cached dist
uses: actions/download-artifact@v4
@@ -218,12 +221,13 @@ jobs:
if: ${{ always() && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
runs-on: "ubuntu-latest"
runs-on: "ubuntu-22.04"
outputs:
val: ${{ steps.host.outputs.manifest }}
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
submodules: recursive
- name: Install cached dist
uses: actions/download-artifact@v4
@@ -282,10 +286,11 @@ jobs:
# still allowing individual publish jobs to skip themselves (for prereleases).
# "host" however must run to completion, no skipping allowed!
if: ${{ always() && needs.host.result == 'success' }}
runs-on: "ubuntu-latest"
runs-on: "ubuntu-22.04"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
submodules: recursive
+11
View File
@@ -18,3 +18,14 @@ _*
# Logs
.log
# Environment variables/configs
.env
# Profiling
profile.json.gz
flamegraph.svg
*.trace
# AI
CLAUDE.md
Generated
+651 -464
View File
File diff suppressed because it is too large Load Diff
+27 -46
View File
@@ -4,9 +4,10 @@ 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.76"
package.version = "0.0.84"
package.homepage = "https://bitcoinresearchkit.org"
package.repository = "https://github.com/bitcoinresearchkit/brk"
package.readme = "README.md"
[profile.release]
lto = "fat"
@@ -21,45 +22,38 @@ debug = true
inherits = "release"
[workspace.dependencies]
arc-swap = "1.7.1"
axum = "0.8.4"
bincode = { version = "2.0.1", features = ["serde"] }
bitcoin = { version = "0.32.6", features = ["serde"] }
bitcoin = { version = "0.32.7", features = ["serde"] }
bitcoincore-rpc = "0.19.0"
brk_bundler = { version = "0.0.76", path = "crates/brk_bundler" }
brk_cli = { version = "0.0.76", path = "crates/brk_cli" }
brk_computer = { version = "0.0.76", path = "crates/brk_computer" }
brk_core = { version = "0.0.76", path = "crates/brk_core" }
brk_exit = { version = "0.0.76", path = "crates/brk_exit" }
brk_fetcher = { version = "0.0.76", path = "crates/brk_fetcher" }
brk_indexer = { version = "0.0.76", path = "crates/brk_indexer" }
brk_interface = { version = "0.0.76", path = "crates/brk_interface" }
brk_logger = { version = "0.0.76", path = "crates/brk_logger" }
brk_mcp = { version = "0.0.76", path = "crates/brk_mcp" }
brk_parser = { version = "0.0.76", path = "crates/brk_parser" }
brk_rmcp = { version = "0.2.1", features = ["transport-streamable-http-server", "transport-worker"]}
# brk_rmcp = { path = "../rust-sdk/crates/rmcp", features = ["transport-streamable-http-server", "transport-worker"]}
brk_server = { version = "0.0.76", path = "crates/brk_server" }
brk_store = { version = "0.0.76", path = "crates/brk_store" }
brk_vec = { version = "0.0.76", path = "crates/brk_vec" }
brk_bundler = { version = "0.0.84", path = "crates/brk_bundler" }
brk_cli = { version = "0.0.84", path = "crates/brk_cli" }
brk_computer = { version = "0.0.84", path = "crates/brk_computer" }
brk_structs = { version = "0.0.84", path = "crates/brk_structs" }
brk_error = { version = "0.0.84", path = "crates/brk_error" }
brk_fetcher = { version = "0.0.84", path = "crates/brk_fetcher" }
brk_indexer = { version = "0.0.84", path = "crates/brk_indexer" }
brk_interface = { version = "0.0.84", path = "crates/brk_interface" }
brk_logger = { version = "0.0.84", path = "crates/brk_logger" }
brk_mcp = { version = "0.0.84", path = "crates/brk_mcp" }
brk_parser = { version = "0.0.84", path = "crates/brk_parser" }
brk_server = { version = "0.0.84", path = "crates/brk_server" }
brk_store = { version = "0.0.84", path = "crates/brk_store" }
brk_vecs = { version = "0.0.84", path = "crates/brk_vecs" }
brk_vecs_macros = { version = "0.0.84", path = "crates/brk_vecs_macros" }
byteview = "=0.6.1"
clap = { version = "4.5.40", features = ["string"] }
clap_derive = "4.5.40"
color-eyre = "0.6.5"
derive_deref = "1.1.1"
fjall = "2.11.1"
fjall = "2.11.2"
jiff = "0.2.15"
log = { version = "0.4.27" }
log = "0.4.27"
minreq = { version = "2.14.0", features = ["https", "serde_json"] }
parking_lot = "0.12.4"
rayon = "1.10.0"
schemars = "1.0.4"
serde = { version = "1.0.219" }
serde = "1.0.219"
serde_bytes = "0.11.17"
serde_derive = "1.0.219"
serde_json = { version = "1.0.140", features = ["float_roundtrip"] }
tabled = "0.20.0"
tokio = { version = "1.46.1", features = ["rt-multi-thread"] }
zerocopy = { version = "0.8.26" }
serde_json = { version = "1.0.142", features = ["float_roundtrip"] }
tokio = { version = "1.47.1", features = ["rt-multi-thread"] }
zerocopy = "0.8.26"
zerocopy-derive = "0.8.26"
[workspace.metadata.release]
@@ -69,20 +63,7 @@ pre-release-commit-message = "release: v{{version}}"
tag-message = "release: v{{version}}"
[workspace.metadata.dist]
cargo-dist-version = "0.28.0"
cargo-dist-version = "0.29.0"
ci = "github"
installers = []
targets = [
"aarch64-apple-darwin",
"aarch64-unknown-linux-gnu",
"x86_64-apple-darwin",
"x86_64-unknown-linux-gnu",
]
[workspace.metadata.dist.github-custom-runners]
global = "ubuntu-latest"
aarch64-apple-darwin.runner = "macos-14"
x86_64-unknown-linux-gnu.runner = "ubuntu-latest"
x86_64-unknown-linux-gnu.container = { image = "quay.io/pypa/manylinux_2_28_x86_64", host = "x86_64-unknown-linux-musl" }
aarch64-unknown-linux-gnu.runner = "ubuntu-latest"
aarch64-unknown-linux-gnu.container = { image = "quay.io/pypa/manylinux_2_28_x86_64", host = "x86_64-unknown-linux-musl" }
targets = ["aarch64-apple-darwin", "aarch64-unknown-linux-gnu", "x86_64-unknown-linux-gnu"]
+17 -23
View File
@@ -23,12 +23,6 @@
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
<img src="https://img.shields.io/badge/nostr-purple?link=https%3A%2F%2Fprimal.net%2Fp%2Fnprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6" alt="Nostr" />
</a>
<a href="https://bsky.app/profile/bitcoinresearchkit.org">
<img src="https://img.shields.io/badge/bluesky-blue?link=https%3A%2F%2Fbsky.app%2Fprofile%2Fbitcoinresearchkit.org" alt="Bluesky" />
</a>
<a href="https://x.com/brkdotorg">
<img src="https://img.shields.io/badge/x.com-black" alt="X" />
</a>
</p>
The Bitcoin Research Kit is a high-performance toolchain designed to parse, index, compute, serve and visualize data from a Bitcoin node, enabling users to gain deeper insights into the Bitcoin network.
@@ -40,14 +34,13 @@ The toolkit can be used in various ways to accommodate as many needs as possible
- **[Website](https://bitcoinresearchkit.org)** \
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: [kibo.money](https://kibo.money) // [satonomics.xyz](https://satonomics.xyz)
Also available at: [brekit.org](https://brekit.org) // [kibo.money](https://kibo.money) // [satonomics.xyz](https://satonomics.xyz)
- **[API](https://github.com/bitcoinresearchkit/brk/tree/main/crates/brk_server#brk-server)** \
Researchers and developers are free to use BRK's public API with ![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.
- **[AI](https://github.com/bitcoinresearchkit/brk/blob/main/crates/brk_mcp/README.md#brk-mcp)** \
LLMs have to possibility to connect to BRK's backend through a [MCP](https://modelcontextprotocol.io/introduction). \
It will give them access to the same tools as the API, with no restrictions, and allow you to have your very own data analysts. \
One-shot output examples: [Document](https://claude.ai/public/artifacts/71194d29-f965-417c-ba09-fdf0e4ecb1d5) // [Dashboard](https://claude.ai/public/artifacts/beef143f-399a-4ed4-b8bf-c986b776de42) // [Dashboard 2](https://claude.ai/public/artifacts/5430ae49-bb3d-4fc1-ab24-f1e33deb40dc)
It will give them access to the same tools as the API, with no restrictions, and allow you to have your very own data analysts.
- **[CLI](https://crates.io/crates/brk_cli)** \
Node runners are strongly encouraged to try out and self-host their own instance using BRK's command line interface. \
The CLI has multiple cogs available for users to tweak to adapt to all situations with even the possibility for web developers to create their own custom website which could later on be added as an alternative front-end.
@@ -61,21 +54,22 @@ In contrast, existing alternatives tend to be either [very costly](https://studi
## Crates
- [`brk`](https://crates.io/crates/brk): Wrapper around all other `brk-*` crates
- [`brk_cli`](https://crates.io/crates/brk_cli): A command line interface to run a Bitcoin Research Kit instance
- [`brk_computer`](https://crates.io/crates/brk_computer): A Bitcoin dataset computer, built on top of brk_indexer
- [`brk_core`](https://crates.io/crates/brk_core): The Core (Structs and Errors) of the Bitcoin Research Kit
- [`brk_exit`](https://crates.io/crates/brk_exit): An exit blocker built on top of ctrlc
- [`brk_fetcher`](https://crates.io/crates/brk_fetcher): A Bitcoin price fetcher
- [`brk_indexer`](https://crates.io/crates/brk_indexer): A Bitcoin Core indexer built on top of brk_parser
- [`brk_logger`](https://crates.io/crates/brk_logger): A clean logger used in the Bitcoin Research Kit
- [`brk_mcp`](https://crates.io/crates/brk_mcp): A Model Context Protocol (MCP) which gives LLMs access to all available tools in BRK
- [`brk_parser`](https://crates.io/crates/brk_parser): A very fast Bitcoin Core block parser and iterator built on top of bitcoin-rust
- [`brk_interface`](https://crates.io/crates/brk_interface): An interface to BRK's engine
- [`brk_server`](https://crates.io/crates/brk_server): A server that serves Bitcoin data and swappable front-ends, built on top of `brk_indexer`, `brk_fetcher` and `brk_computer`
- [`brk_store`](https://crates.io/crates/brk_store): A thin wrapper around [`fjall`](https://crates.io/crates/fjall)
- [`brk_vec`](https://crates.io/crates/brk_vec): A push-only, truncable, compressable, saveable Vec
- [`brk`](https://crates.io/crates/brk): A wrapper around all other `brk-*` crates
- [`brk_bundler`](https://crates.io/crates/brk_bundler): A thin wrapper around [`rolldown`](https://rolldown.rs/)
- [`brk_cli`](https://crates.io/crates/brk_cli): A command line interface to run a BRK instance
- [`brk_computer`](https://crates.io/crates/brk_computer): A Bitcoin dataset computer built on top of [`brk_indexer`](https://crates.io/crates/brk_indexer)
- [`brk_error`](https://crates.io/crates/brk_error): Errors used throughout BRK
- [`brk_fetcher`](https://crates.io/crates/brk_fetcher): A Bitcoin price fetcher
- [`brk_indexer`](https://crates.io/crates/brk_indexer): A Bitcoin indexer built on top of [`brk_parser`](https://crates.io/crates/brk_parser)
- [`brk_interface`](https://crates.io/crates/brk_interface): An interface to find and format data from BRK
- [`brk_logger`](https://crates.io/crates/brk_logger): A thin wrapper around [`env_logger`](https://crates.io/crates/env_logger)
- [`brk_mcp`](https://crates.io/crates/brk_mcp): A bridge for LLMs to access BRK
- [`brk_parser`](https://crates.io/crates/brk_parser): A very fast Bitcoin block parser and iterator built on top of [`bitcoin-rust`](https://crates.io/crates/bitcoin)
- [`brk_server`](https://crates.io/crates/brk_server): A server with an API for anything from BRK
- [`brk_store`](https://crates.io/crates/brk_store): A thin wrapper around [`fjall`](https://crates.io/crates/fjall)
- [`brk_structs`](https://crates.io/crates/brk_structs): Structs used throughout BRK
- [`brk_vecs`](https://crates.io/crates/brk_vecs): A KISS index/value store
- [`brk_vecs_macros`](https://crates.io/crates/brk_vecs_macros): Macros for [`brk_vecs`](https://crates.io/crates/brk_vecs)
## Hosting as a service
+14 -2
View File
@@ -10,21 +10,30 @@
- 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 support for per index computation
- fix feerate which is always ZERO due to coinbase transaction
- fix min feerate which is always ZERO due to coinbase transaction
- before computing multiple sources check their length, panic if not equal
- add oracle price dataset (https://utxo.live/oracle/UTXOracle.py)
- add address counts relative to all datasets
- make decade, quarter, year datasets `computed` instead of `eager`
- add 6 months (semester) interval datasets to builder
- some datasets in `indexes` can probably be removed
- add revived/sent supply datasets
- add `in-sats` version of all price datasets (average and co)
- add `p2pk` group (sum of `p2pk33` and `p2pk65`)
- add chopiness datasets
- add utxo count, address count, supply data for by reused addresses in groups by address type
- add more date ranges (3-6 months and more)
- add puell multiple dataset
- add pi cycle dataset
- add ema of price
- 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
@@ -50,6 +59,8 @@
- api
- add extensions support (.json .csv …)
- if format instead of extension then don't download file
- add support for https (rustls)
- lru cache
- _vec_
- add native lock file support (once it's available in stable rust)
- improve compressed mode (slow reads)
@@ -73,6 +84,7 @@
- remove `sum` series when it's a duplicate of the `base` (in subsidy for example)
- selected unit sometimes changes when going back end forth
- add support for custom charts
- separate z-score charts from "realized price" (with their own prices), have 4y, 2y and 1y
- price scale format depends on unit, hide digits for sats for example (if/when possible)
- table
- pagination
-2
View File
@@ -1,2 +0,0 @@
profile.json.gz
flamegraph.svg
+13 -12
View File
@@ -7,52 +7,53 @@ homepage.workspace = true
repository.workspace = true
edition.workspace = true
version.workspace = true
build = "build.rs"
[features]
full = [
"bundler",
"core",
"computer",
"exit",
"error",
"fetcher",
"indexer",
"interface",
"logger",
"mcp",
"parser",
"interface",
"server",
"store",
"vec",
"structs",
"vecs",
]
bundler = ["brk_bundler"]
core = ["brk_core"]
computer = ["brk_computer"]
exit = ["brk_exit"]
error = ["brk_error"]
fetcher = ["brk_fetcher"]
indexer = ["brk_indexer"]
interface = ["brk_interface"]
logger = ["brk_logger"]
mcp = ["brk_mcp"]
parser = ["brk_parser"]
interface = ["brk_interface"]
server = ["brk_server"]
store = ["brk_store"]
vec = ["brk_vec"]
structs = ["brk_structs"]
vecs = ["brk_vecs"]
[dependencies]
brk_bundler = { workspace = true, optional = true }
brk_cli = { workspace = true }
brk_core = { workspace = true, optional = true }
brk_computer = { workspace = true, optional = true }
brk_exit = { workspace = true, optional = true }
brk_error = { workspace = true, optional = true }
brk_fetcher = { workspace = true, optional = true }
brk_indexer = { workspace = true, optional = true }
brk_interface = { workspace = true, optional = true }
brk_logger = { workspace = true, optional = true }
brk_mcp = { workspace = true, optional = true }
brk_parser = { workspace = true, optional = true }
brk_interface = { workspace = true, optional = true }
brk_server = { workspace = true, optional = true }
brk_store = { workspace = true, optional = true }
brk_vec = { workspace = true, optional = true }
brk_structs = { workspace = true, optional = true }
brk_vecs = { workspace = true, optional = true }
[package.metadata.docs.rs]
all-features = true
+8
View File
@@ -0,0 +1,8 @@
fn main() {
let profile = std::env::var("PROFILE").unwrap_or_default();
if profile == "release" {
println!("cargo:rustc-flag=-C");
println!("cargo:rustc-flag=target-cpu=native");
}
}
+1 -2
View File
@@ -1,2 +1 @@
cargo build --profile profiling
flamegraph -- ../../target/profiling/brk
sudo cargo flamegraph --profile profiling --root
+6 -6
View File
@@ -7,17 +7,17 @@ pub use brk_bundler as bundler;
#[doc(inline)]
pub use brk_cli as cli;
#[cfg(feature = "core")]
#[cfg(feature = "structs")]
#[doc(inline)]
pub use brk_core as core;
pub use brk_structs as structs;
#[cfg(feature = "computer")]
#[doc(inline)]
pub use brk_computer as computer;
#[cfg(feature = "exit")]
#[cfg(feature = "error")]
#[doc(inline)]
pub use brk_exit as exit;
pub use brk_error as error;
#[cfg(feature = "fetcher")]
#[doc(inline)]
@@ -51,6 +51,6 @@ pub use brk_server as server;
#[doc(inline)]
pub use brk_store as store;
#[cfg(feature = "vec")]
#[cfg(feature = "vecs")]
#[doc(inline)]
pub use brk_vec as vec;
pub use brk_vecs as vecs;
+3 -2
View File
@@ -6,11 +6,12 @@ edition.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true
build = "build.rs"
[dependencies]
log = { workspace = true }
notify = "8.1.0"
brk_rolldown = "0.1.1"
notify = "8.2.0"
brk_rolldown = "0.1.4"
# brk_rolldown = { path = "../../../rolldown/crates/rolldown"}
sugar_path = "1.2.0"
tokio = { workspace = true }
+8
View File
@@ -0,0 +1,8 @@
fn main() {
let profile = std::env::var("PROFILE").unwrap_or_default();
if profile == "release" {
println!("cargo:rustc-flag=-C");
println!("cargo:rustc-flag=target-cpu=native");
}
}
+14 -12
View File
@@ -1,4 +1,8 @@
use std::{fs, io, path::Path, sync::Arc};
use std::{
fs, io,
path::{Path, PathBuf},
sync::Arc,
};
use brk_rolldown::{Bundler, BundlerOptions, RawMinifyOptions, SourceMapType};
use log::error;
@@ -8,7 +12,7 @@ use tokio::sync::Mutex;
const VERSION: &str = env!("CARGO_PKG_VERSION");
pub async fn bundle(websites_path: &Path, source_folder: &str, watch: bool) -> io::Result<()> {
pub async fn bundle(websites_path: &Path, source_folder: &str, watch: bool) -> io::Result<PathBuf> {
let source_path = websites_path.join(source_folder);
let dist_path = websites_path.join("dist");
@@ -48,14 +52,12 @@ pub async fn bundle(websites_path: &Path, source_folder: &str, watch: bool) -> i
let write_index = move || {
let mut contents = fs::read_to_string(&absolute_source_index_path).unwrap();
if let Ok(entry) = fs::read_to_string(absolute_dist_path_clone.join("scripts/entry.js")) {
if let Some(start) = entry.find("main") {
if let Some(end) = entry.find(".js") {
let main_hashed = &entry[start..end];
contents =
contents.replace("/scripts/main.js", &format!("/scripts/{main_hashed}.js"));
}
}
if let Ok(entry) = fs::read_to_string(absolute_dist_path_clone.join("scripts/entry.js"))
&& let Some(start) = entry.find("main")
&& let Some(end) = entry.find(".js")
{
let main_hashed = &entry[start..end];
contents = contents.replace("/scripts/main.js", &format!("/scripts/{main_hashed}.js"));
}
let _ = fs::write(&absolute_dist_index_path, contents);
@@ -72,7 +74,7 @@ pub async fn bundle(websites_path: &Path, source_folder: &str, watch: bool) -> i
write_sw();
if !watch {
return Ok(());
return Ok(dist_path);
}
tokio::spawn(async move {
@@ -127,7 +129,7 @@ pub async fn bundle(websites_path: &Path, source_folder: &str, watch: bool) -> i
watcher.start().await;
});
Ok(())
Ok(dist_path)
}
fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
+11 -8
View File
@@ -1,30 +1,33 @@
[package]
name = "brk_cli"
description = "A command line interface to run a Bitcoin Research Kit instance"
description = "A command line interface to run a BRK instance"
version.workspace = true
edition.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true
build = "build.rs"
[dependencies]
bitcoincore-rpc = { workspace = true }
brk_bundler = { workspace = true }
brk_computer = { workspace = true }
brk_core = { workspace = true }
brk_exit = { workspace = true }
brk_fetcher = { workspace = true }
brk_indexer = { workspace = true }
brk_interface = { workspace = true }
brk_logger = { workspace = true }
brk_parser = { workspace = true }
brk_server = { workspace = true }
brk_vec = { workspace = true }
clap = { workspace = true }
clap_derive = { workspace = true }
color-eyre = { workspace = true }
brk_vecs = { workspace = true }
clap = { version = "4.5.43", features = ["string"] }
clap_derive = "4.5.41"
color-eyre = "0.6.5"
log = { workspace = true }
minreq = { workspace = true }
serde = { workspace = true }
tokio = { workspace = true }
toml = "0.9.0"
toml = "0.9.5"
zip = { version = "4.3.0", default-features = false, features = ["deflate"] }
[[bin]]
name = "brk"
+2 -8
View File
@@ -23,12 +23,6 @@
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
<img src="https://img.shields.io/badge/nostr-purple?link=https%3A%2F%2Fprimal.net%2Fp%2Fnprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6" alt="Nostr" />
</a>
<a href="https://bsky.app/profile/bitcoinresearchkit.org">
<img src="https://img.shields.io/badge/bluesky-blue?link=https%3A%2F%2Fbsky.app%2Fprofile%2Fbitcoinresearchkit.org" alt="Bluesky" />
</a>
<a href="https://x.com/brkdotorg">
<img src="https://img.shields.io/badge/x.com-black" alt="X" />
</a>
</p>
A command line interface to run a Bitcoin Research Kit instance.
@@ -70,10 +64,10 @@ You can find a pre-built binary for your operating system in the [releases page]
```bash
# Install
cargo install brk # or `cargo install brk_cli`, the result is the same
cargo install brk --locked # or `cargo install brk_cli`, the result is the same
# Update
cargo install brk # or `cargo install-update -a` if you have `cargo-update` installed
cargo install brk --locked # or `cargo install-update -a` if you have `cargo-update` installed
```
### Source
+8
View File
@@ -0,0 +1,8 @@
fn main() {
let profile = std::env::var("PROFILE").unwrap_or_default();
if profile == "release" {
println!("cargo:rustc-flag=-C");
println!("cargo:rustc-flag=target-cpu=native");
}
}
@@ -1,8 +1,9 @@
use std::{fs, io, path::Path};
use brk_interface::{Index, Interface};
use brk_server::VERSION;
use crate::{VERSION, Website};
use crate::website::Website;
const SCRIPTS: &str = "scripts";
+18 -53
View File
@@ -4,16 +4,15 @@ use std::{
};
use bitcoincore_rpc::{self, Auth, Client};
use brk_core::{default_bitcoin_path, default_brk_path, default_on_error, dot_brk_path};
use brk_fetcher::Fetcher;
use brk_server::Website;
use brk_vec::{Computation, Format};
use clap::Parser;
use clap_derive::Parser;
use color_eyre::eyre::eyre;
use serde::{Deserialize, Serialize};
use serde::{Deserialize, Deserializer, Serialize};
use crate::services::Services;
use crate::{default_bitcoin_path, default_brk_path, dot_brk_path, website::Website};
const DOWNLOADS: &str = "downloads";
#[derive(Parser, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
#[command(version, about)]
@@ -33,21 +32,6 @@ pub struct Config {
#[arg(long, value_name = "PATH")]
brkdir: Option<String>,
/// Activated services, default: all, saved
#[serde(default, deserialize_with = "default_on_error")]
#[arg(short, long)]
services: Option<Services>,
/// Computation of computed datasets, `lazy` computes data whenever requested without saving it, `eager` computes the data once and saves it to disk, default: `lazy`, saved
#[serde(default, deserialize_with = "default_on_error")]
#[arg(short, long)]
computation: Option<Computation>,
/// Format of computed datasets, `compressed` to save disk space (experimental), `raw` to prioritize speed, default: `raw`, saved
#[serde(default, deserialize_with = "default_on_error")]
#[arg(short, long)]
format: Option<Format>,
/// Activate fetching prices from exchanges APIs and the computation of all related datasets, default: true, saved
#[serde(default, deserialize_with = "default_on_error")]
#[arg(short = 'F', long, value_name = "BOOL")]
@@ -129,22 +113,10 @@ impl Config {
config_saved.brkdir = Some(brkdir);
}
if let Some(services) = config_args.services.take() {
config_saved.services = Some(services);
}
if let Some(computation) = config_args.computation.take() {
config_saved.computation = Some(computation);
}
if let Some(fetch) = config_args.fetch.take() {
config_saved.fetch = Some(fetch);
}
if let Some(format) = config_args.format.take() {
config_saved.format = Some(format);
}
if let Some(website) = config_args.website.take() {
config_saved.website = Some(website);
}
@@ -298,22 +270,12 @@ impl Config {
.map_or_else(default_brk_path, |s| Self::fix_user_path(s.as_ref()))
}
pub fn outputsdir(&self) -> PathBuf {
self.brkdir().join("outputs")
}
pub fn harsdir(&self) -> PathBuf {
self.outputsdir().join("hars")
self.brkdir().join("hars")
}
pub fn process(&self) -> bool {
self.services
.is_none_or(|m| m == Services::All || m == Services::Processor)
}
pub fn serve(&self) -> bool {
self.services
.is_none_or(|m| m == Services::All || m == Services::Server)
pub fn downloads_dir(&self) -> PathBuf {
dot_brk_path().join(DOWNLOADS)
}
fn path_cookiefile(&self) -> PathBuf {
@@ -354,14 +316,6 @@ impl Config {
.then(|| Fetcher::import(Some(self.harsdir().as_path())).unwrap())
}
pub fn computation(&self) -> Computation {
self.computation.unwrap_or_default()
}
pub fn format(&self) -> Format {
self.format.unwrap_or_default()
}
pub fn check_collisions(&self) -> bool {
self.check_collisions.is_some_and(|b| b)
}
@@ -374,3 +328,14 @@ impl Config {
self.watch.is_some_and(|b| b)
}
}
fn default_on_error<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de> + Default,
{
match T::deserialize(deserializer) {
Ok(v) => Ok(v),
Err(_) => Ok(T::default()),
}
}
+136 -5
View File
@@ -1,12 +1,28 @@
use std::{fs, thread};
#![doc = include_str!("../README.md")]
use brk_core::{dot_brk_log_path, dot_brk_path};
use std::{
fs,
io::Cursor,
path::Path,
thread::{self, sleep},
time::Duration,
};
use bitcoincore_rpc::{self, RpcApi};
use brk_bundler::bundle;
use brk_computer::Computer;
use brk_indexer::Indexer;
use brk_interface::Interface;
use brk_server::{Server, VERSION};
use brk_vecs::Exit;
use log::info;
mod bridge;
mod config;
mod run;
mod services;
mod paths;
mod website;
use run::*;
use crate::{bridge::Bridge, config::Config, paths::*};
pub fn main() -> color_eyre::Result<()> {
color_eyre::install()?;
@@ -21,3 +37,118 @@ pub fn main() -> color_eyre::Result<()> {
.join()
.unwrap()
}
pub fn run() -> color_eyre::Result<()> {
let config = Config::import()?;
let rpc = config.rpc()?;
let exit = Exit::new();
exit.set_ctrlc_handler();
let parser = brk_parser::Parser::new(config.blocksdir(), config.brkdir(), rpc);
let mut indexer = Indexer::forced_import(&config.brkdir())?;
let wait_for_synced_node = |rpc_client: &bitcoincore_rpc::Client| -> color_eyre::Result<()> {
let is_synced = || -> color_eyre::Result<bool> {
let info = rpc_client.get_blockchain_info()?;
Ok(info.headers == info.blocks)
};
if !is_synced()? {
info!("Waiting for node to be synced...");
while !is_synced()? {
sleep(Duration::from_secs(1))
}
}
Ok(())
};
let mut computer = Computer::forced_import(&config.brkdir(), &indexer, config.fetcher())?;
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()?
.block_on(async {
let interface = Interface::build(&indexer, &computer);
let website = config.website();
let downloads_path = config.downloads_dir();
let bundle_path = if website.is_some() {
let websites_dev_path = Path::new("../../websites");
let websites_path = if fs::exists(websites_dev_path)? {
websites_dev_path.to_path_buf()
} else {
let downloaded_websites_path =
downloads_path.join(format!("brk-{VERSION}")).join("websites");
if !fs::exists(&downloaded_websites_path)? {
info!("Downloading websites from Github...");
let url = format!(
"https://github.com/bitcoinresearchkit/brk/archive/refs/tags/v{VERSION}.zip",
);
let response = minreq::get(url).send()?;
let bytes = response.as_bytes();
let cursor = Cursor::new(bytes);
let mut zip = zip::ZipArchive::new(cursor).unwrap();
zip.extract(downloads_path).unwrap();
}
downloaded_websites_path
};
interface.generate_bridge_file(website, websites_path.as_path())?;
let watch = config.watch();
Some(bundle(&websites_path, website.to_folder_name(), watch).await?)
} else {
None
};
let server = Server::new(
interface,
bundle_path,
);
let mcp = config.mcp();
tokio::spawn(async move {
server.serve(mcp).await.unwrap();
});
sleep(Duration::from_secs(1));
loop {
wait_for_synced_node(rpc)?;
let block_count = rpc.get_block_count()?;
info!("{} blocks found.", block_count + 1);
let starting_indexes =
indexer.index(&parser, rpc, &exit, config.check_collisions())?;
computer.compute(&indexer, starting_indexes, &exit)?;
if let Some(delay) = config.delay() {
sleep(Duration::from_secs(delay))
}
info!("Waiting for new blocks...");
while block_count == rpc.get_block_count()? {
sleep(Duration::from_secs(1))
}
}
})
}
-103
View File
@@ -1,103 +0,0 @@
use std::{thread::sleep, time::Duration};
use bitcoincore_rpc::{self, RpcApi};
use brk_computer::Computer;
use brk_exit::Exit;
use brk_indexer::Indexer;
use brk_server::Server;
use log::info;
use crate::config::Config;
pub fn run() -> color_eyre::Result<()> {
let config = Config::import()?;
let rpc = config.rpc()?;
let exit = Exit::new();
let parser = brk_parser::Parser::new(config.blocksdir(), rpc);
let format = config.format();
let mut indexer = Indexer::forced_import(&config.outputsdir())?;
let wait_for_synced_node = || -> color_eyre::Result<()> {
let is_synced = || -> color_eyre::Result<bool> {
let info = rpc.get_blockchain_info()?;
Ok(info.headers == info.blocks)
};
if !is_synced()? {
info!("Waiting for node to be synced...");
while !is_synced()? {
sleep(Duration::from_secs(1))
}
}
Ok(())
};
let mut computer = Computer::forced_import(
&config.outputsdir(),
&indexer,
config.computation(),
config.fetcher(),
format,
)?;
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()?
.block_on(async {
let server = if config.serve() {
let served_indexer = indexer.clone();
let served_computer = computer.clone();
let server = Server::new(served_indexer, served_computer, config.website())?;
let watch = config.watch();
let mcp = config.mcp();
let opt = Some(tokio::spawn(async move {
server.serve(watch, mcp).await.unwrap();
}));
sleep(Duration::from_secs(1));
opt
} else {
None
};
if config.process() {
loop {
wait_for_synced_node()?;
let block_count = rpc.get_block_count()?;
info!("{} blocks found.", block_count + 1);
let starting_indexes =
indexer.index(&parser, rpc, &exit, config.check_collisions())?;
computer.compute(&mut indexer, starting_indexes, &exit)?;
if let Some(delay) = config.delay() {
sleep(Duration::from_secs(delay))
}
info!("Waiting for new blocks...");
while block_count == rpc.get_block_count()? {
sleep(Duration::from_secs(1))
}
}
}
if let Some(handle) = server {
handle.await.unwrap();
}
Ok(())
})
}
-23
View File
@@ -1,23 +0,0 @@
use clap_derive::{Parser, ValueEnum};
use serde::{Deserialize, Serialize};
#[derive(
Default,
Debug,
Clone,
Copy,
Parser,
ValueEnum,
Serialize,
Deserialize,
PartialEq,
Eq,
PartialOrd,
Ord,
)]
pub enum Services {
#[default]
All,
Processor,
Server,
}
@@ -17,7 +17,7 @@ impl Website {
!self.is_none()
}
pub fn to_folder_name(&self) -> &str {
pub fn to_folder_name(self) -> &'static str {
match self {
Self::Custom => "custom",
Self::Default => "default",
+5 -10
View File
@@ -1,29 +1,24 @@
[package]
name = "brk_computer"
description = "A Bitcoin dataset computer, built on top of brk_indexer"
description = "A Bitcoin dataset computer built on top of brk_indexer"
version.workspace = true
edition.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true
build = "build.rs"
[dependencies]
bincode = { workspace = true }
bitcoin = { workspace = true }
bitcoincore-rpc = { workspace = true }
brk_core = { workspace = true }
brk_exit = { workspace = true }
brk_structs = { workspace = true }
brk_error = { workspace = true }
brk_fetcher = { workspace = true }
brk_indexer = { workspace = true }
brk_logger = { workspace = true }
brk_parser = { workspace = true }
brk_store = { workspace = true }
brk_vec = { workspace = true }
color-eyre = { workspace = true }
brk_vecs = { workspace = true }
derive_deref = { workspace = true }
either = "1.15.0"
fjall = { workspace = true }
jiff = { workspace = true }
log = { workspace = true }
rayon = { workspace = true }
serde = { workspace = true }
-6
View File
@@ -23,12 +23,6 @@
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
<img src="https://img.shields.io/badge/nostr-purple?link=https%3A%2F%2Fprimal.net%2Fp%2Fnprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6" alt="Nostr" />
</a>
<a href="https://bsky.app/profile/bitcoinresearchkit.org">
<img src="https://img.shields.io/badge/bluesky-blue?link=https%3A%2F%2Fbsky.app%2Fprofile%2Fbitcoinresearchkit.org" alt="Bluesky" />
</a>
<a href="https://x.com/brkdotorg">
<img src="https://img.shields.io/badge/x.com-black" alt="X" />
</a>
</p>
A dataset computer, built on top of `brk_indexer` and `brk_fetcher`. It computes any dataset you can think of and if it doesn't feel free to create an issue.
+8
View File
@@ -0,0 +1,8 @@
fn main() {
let profile = std::env::var("PROFILE").unwrap_or_default();
if profile == "release" {
println!("cargo:rustc-flag=-C");
println!("cargo:rustc-flag=target-cpu=native");
}
}
+55
View File
@@ -0,0 +1,55 @@
use std::{
path::Path,
thread::{self, sleep},
time::{Duration, Instant},
};
use brk_computer::Computer;
use brk_error::Result;
use brk_fetcher::Fetcher;
use brk_indexer::Indexer;
use brk_parser::Parser;
use brk_vecs::Exit;
pub fn main() -> Result<()> {
brk_logger::init(Some(Path::new(".log")));
let bitcoin_dir = Path::new(&std::env::var("HOME").unwrap())
.join("Library")
.join("Application Support")
.join("Bitcoin");
// let bitcoin_dir = Path::new("/Volumes/WD_BLACK/bitcoin");
let rpc = Box::leak(Box::new(bitcoincore_rpc::Client::new(
"http://localhost:8332",
bitcoincore_rpc::Auth::CookieFile(bitcoin_dir.join(".cookie")),
)?));
let exit = Exit::new();
exit.set_ctrlc_handler();
// Can't increase main thread's stack size, thus we need to use another thread
thread::Builder::new()
.stack_size(256 * 1024 * 1024)
.spawn(move || -> 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 mut indexer = Indexer::forced_import(&outputs_dir)?;
let fetcher = Fetcher::import(None)?;
let mut computer = Computer::forced_import(&outputs_dir, &indexer, Some(fetcher))?;
loop {
let i = Instant::now();
let starting_indexes = indexer.index(&parser, rpc, &exit, true)?;
computer.compute(&indexer, starting_indexes, &exit)?;
dbg!(i.elapsed());
sleep(Duration::from_secs(10));
}
})?
.join()
.unwrap()
}
-56
View File
@@ -1,56 +0,0 @@
use std::{path::Path, thread};
use brk_computer::Computer;
use brk_core::{default_bitcoin_path, default_brk_path};
use brk_exit::Exit;
use brk_fetcher::Fetcher;
use brk_indexer::Indexer;
use brk_parser::Parser;
use brk_vec::{Computation, Format};
pub fn main() -> color_eyre::Result<()> {
color_eyre::install()?;
brk_logger::init(Some(Path::new(".log")));
let bitcoin_dir = default_bitcoin_path();
let rpc = Box::leak(Box::new(bitcoincore_rpc::Client::new(
"http://localhost:8332",
bitcoincore_rpc::Auth::CookieFile(bitcoin_dir.join(".cookie")),
)?));
let exit = Exit::new();
// Can't increase main thread's stack programatically, thus we need to use another thread
thread::Builder::new()
.stack_size(32 * 1024 * 1024)
.spawn(move || -> color_eyre::Result<()> {
let parser = Parser::new(bitcoin_dir.join("blocks"), rpc);
let _outputs_dir = default_brk_path().join("outputs");
let outputs_dir = _outputs_dir.as_path();
// let outputs_dir = Path::new("../../_outputs");
let format = Format::Raw;
let mut indexer = Indexer::forced_import(outputs_dir)?;
let fetcher = Fetcher::import(None)?;
let mut computer = Computer::forced_import(
outputs_dir,
&indexer,
Computation::Lazy,
Some(fetcher),
format,
)?;
let starting_indexes = indexer.index(&parser, rpc, &exit, true)?;
computer.compute(&mut indexer, starting_indexes, &exit)?;
Ok(())
})?
.join()
.unwrap()
}
+2
View File
@@ -0,0 +1,2 @@
cargo build --profile profiling
flamegraph -- ../../target/profiling/examples/main
+2
View File
@@ -0,0 +1,2 @@
cargo build --example main --profile profiling
samply record ../../target/profiling/examples/main
@@ -1,16 +1,20 @@
use std::path::Path;
use std::{path::Path, sync::Arc};
use brk_core::{
CheckedSub, DifficultyEpoch, HalvingEpoch, Height, StoredU32, StoredU64, StoredUsize,
Timestamp, Version, Weight,
};
use brk_exit::Exit;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_vec::{AnyCollectableVec, AnyIterableVec, Computation, EagerVec, Format};
use brk_structs::{
CheckedSub, DifficultyEpoch, HalvingEpoch, Height, StoredU32, StoredU64, Timestamp, Version,
Weight,
};
use brk_vecs::{
AnyCollectableVec, Computation, EagerVec, Exit, File, Format, PAGE_SIZE, VecIterator,
};
use crate::grouped::Source;
use super::{
Indexes,
grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, StorableVecGeneatorOptions},
grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, VecBuilderOptions},
indexes,
};
@@ -18,6 +22,8 @@ const VERSION: Version = Version::ZERO;
#[derive(Clone)]
pub struct Vecs {
file: Arc<File>,
pub height_to_interval: EagerVec<Height, Timestamp>,
pub height_to_vbytes: EagerVec<Height, StoredU64>,
pub difficultyepoch_to_timestamp: EagerVec<DifficultyEpoch, Timestamp>,
@@ -25,102 +31,112 @@ pub struct Vecs {
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<StoredUsize>,
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(
path: &Path,
parent: &Path,
version: Version,
_computation: Computation,
computation: Computation,
format: Format,
) -> color_eyre::Result<Self> {
indexes: &indexes::Vecs,
) -> Result<Self> {
let file = Arc::new(File::open(&parent.join("blocks"))?);
file.set_min_len(PAGE_SIZE * 1_000_000)?;
Ok(Self {
height_to_interval: EagerVec::forced_import(
path,
&file,
"interval",
version + VERSION + Version::ZERO,
format,
)?,
timeindexes_to_timestamp: ComputedVecsFromDateIndex::forced_import(
path,
&file,
"timestamp",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_first(),
computation,
indexes,
VecBuilderOptions::default().add_first(),
)?,
indexes_to_block_interval: ComputedVecsFromHeight::forced_import(
path,
&file,
"block_interval",
false,
Source::None,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
computation,
indexes,
VecBuilderOptions::default()
.add_percentiles()
.add_minmax()
.add_average(),
)?,
indexes_to_block_count: ComputedVecsFromHeight::forced_import(
path,
&file,
"block_count",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
.add_sum()
.add_cumulative(),
computation,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
)?,
indexes_to_block_weight: ComputedVecsFromHeight::forced_import(
path,
&file,
"block_weight",
false,
Source::None,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
.add_sum()
.add_cumulative(),
computation,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
)?,
indexes_to_block_size: ComputedVecsFromHeight::forced_import(
path,
&file,
"block_size",
false,
Source::None,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
.add_sum()
.add_cumulative(),
computation,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
)?,
height_to_vbytes: EagerVec::forced_import(
path,
&file,
"vbytes",
version + VERSION + Version::ZERO,
format,
)?,
indexes_to_block_vbytes: ComputedVecsFromHeight::forced_import(
path,
&file,
"block_vbytes",
false,
Source::None,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
.add_sum()
.add_cumulative(),
computation,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
)?,
difficultyepoch_to_timestamp: EagerVec::forced_import(
path,
&file,
"timestamp",
version + VERSION + Version::ZERO,
format,
)?,
halvingepoch_to_timestamp: EagerVec::forced_import(
path,
&file,
"timestamp",
version + VERSION + Version::ZERO,
format,
)?,
file,
})
}
@@ -130,7 +146,19 @@ impl Vecs {
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> color_eyre::Result<()> {
) -> Result<()> {
self.compute_(indexer, indexes, starting_indexes, exit)?;
self.file.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,
@@ -142,7 +170,8 @@ impl Vecs {
&indexes.dateindex_to_date,
|(di, d, ..)| (di, Timestamp::from(d)),
exit,
)
)?;
Ok(())
},
)?;
@@ -157,7 +186,8 @@ impl Vecs {
&indexer.vecs.height_to_weight,
|h| (h, StoredU32::from(1_u32)),
exit,
)
)?;
Ok(())
},
)?;
@@ -1,26 +1,25 @@
use std::path::Path;
use std::{path::Path, sync::Arc};
use brk_core::{Bitcoin, CheckedSub, Dollars, StoredF64, Version};
use brk_exit::Exit;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_vec::{AnyCollectableVec, Computation, Format, VecIterator};
use crate::vecs::{
fetched,
grouped::{ComputedRatioVecsFromDateIndex, ComputedValueVecsFromHeight},
stateful, transactions,
};
use brk_structs::{Bitcoin, CheckedSub, Dollars, StoredF64, Version};
use brk_vecs::{AnyCollectableVec, Computation, Exit, File, Format, PAGE_SIZE, VecIterator};
use super::{
Indexes,
grouped::{ComputedVecsFromHeight, StorableVecGeneatorOptions},
indexes,
grouped::{
ComputedRatioVecsFromDateIndex, ComputedValueVecsFromHeight, ComputedVecsFromHeight,
Source, VecBuilderOptions,
},
indexes, price, stateful, transactions,
};
const VERSION: Version = Version::ZERO;
#[derive(Clone)]
pub struct Vecs {
file: Arc<File>,
pub indexes_to_coinblocks_created: ComputedVecsFromHeight<StoredF64>,
pub indexes_to_coinblocks_stored: ComputedVecsFromHeight<StoredF64>,
pub indexes_to_liveliness: ComputedVecsFromHeight<StoredF64>,
@@ -49,207 +48,253 @@ pub struct Vecs {
impl Vecs {
pub fn forced_import(
path: &Path,
parent: &Path,
version: Version,
_computation: Computation,
computation: Computation,
format: Format,
fetched: Option<&fetched::Vecs>,
) -> color_eyre::Result<Self> {
let compute_dollars = fetched.is_some();
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
) -> Result<Self> {
let file = Arc::new(File::open(&parent.join("cointime"))?);
file.set_min_len(PAGE_SIZE * 1_000_000)?;
let compute_dollars = price.is_some();
Ok(Self {
indexes_to_coinblocks_created: ComputedVecsFromHeight::forced_import(
path,
&file,
"coinblocks_created",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
.add_sum()
.add_cumulative(),
computation,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
)?,
indexes_to_coinblocks_stored: ComputedVecsFromHeight::forced_import(
path,
&file,
"coinblocks_stored",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
.add_sum()
.add_cumulative(),
computation,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
)?,
indexes_to_liveliness: ComputedVecsFromHeight::forced_import(
path,
&file,
"liveliness",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_vaultedness: ComputedVecsFromHeight::forced_import(
path,
&file,
"vaultedness",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_activity_to_vaultedness_ratio: ComputedVecsFromHeight::forced_import(
path,
&file,
"activity_to_vaultedness_ratio",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_vaulted_supply: ComputedValueVecsFromHeight::forced_import(
path,
&file,
"vaulted_supply",
true,
Source::Compute,
version + VERSION + Version::ONE,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
VecBuilderOptions::default().add_last(),
compute_dollars,
indexes,
)?,
indexes_to_active_supply: ComputedValueVecsFromHeight::forced_import(
path,
&file,
"active_supply",
true,
Source::Compute,
version + VERSION + Version::ONE,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
VecBuilderOptions::default().add_last(),
compute_dollars,
indexes,
)?,
indexes_to_thermo_cap: ComputedVecsFromHeight::forced_import(
path,
&file,
"thermo_cap",
true,
Source::Compute,
version + VERSION + Version::ONE,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_investor_cap: ComputedVecsFromHeight::forced_import(
path,
&file,
"investor_cap",
true,
Source::Compute,
version + VERSION + Version::ONE,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_vaulted_cap: ComputedVecsFromHeight::forced_import(
path,
&file,
"vaulted_cap",
true,
Source::Compute,
version + VERSION + Version::ONE,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_active_cap: ComputedVecsFromHeight::forced_import(
path,
&file,
"active_cap",
true,
Source::Compute,
version + VERSION + Version::ONE,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_vaulted_price: ComputedVecsFromHeight::forced_import(
path,
&file,
"vaulted_price",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_vaulted_price_ratio: ComputedRatioVecsFromDateIndex::forced_import(
path,
&file,
"vaulted_price",
false,
Source::None,
version + VERSION + Version::ZERO,
format,
computation,
indexes,
true,
)?,
indexes_to_active_price: ComputedVecsFromHeight::forced_import(
path,
&file,
"active_price",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_active_price_ratio: ComputedRatioVecsFromDateIndex::forced_import(
path,
&file,
"active_price",
false,
Source::None,
version + VERSION + Version::ZERO,
format,
computation,
indexes,
true,
)?,
indexes_to_true_market_mean: ComputedVecsFromHeight::forced_import(
path,
&file,
"true_market_mean",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_true_market_mean_ratio: ComputedRatioVecsFromDateIndex::forced_import(
path,
&file,
"true_market_mean",
false,
Source::None,
version + VERSION + Version::ZERO,
format,
computation,
indexes,
true,
)?,
indexes_to_cointime_value_destroyed: ComputedVecsFromHeight::forced_import(
path,
&file,
"cointime_value_destroyed",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
.add_sum()
.add_cumulative(),
computation,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
)?,
indexes_to_cointime_value_created: ComputedVecsFromHeight::forced_import(
path,
&file,
"cointime_value_created",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
.add_sum()
.add_cumulative(),
computation,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
)?,
indexes_to_cointime_value_stored: ComputedVecsFromHeight::forced_import(
path,
&file,
"cointime_value_stored",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
.add_sum()
.add_cumulative(),
computation,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
)?,
indexes_to_cointime_price: ComputedVecsFromHeight::forced_import(
path,
&file,
"cointime_price",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_cointime_cap: ComputedVecsFromHeight::forced_import(
path,
&file,
"cointime_cap",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_cointime_price_ratio: ComputedRatioVecsFromDateIndex::forced_import(
path,
&file,
"cointime_price",
false,
Source::None,
version + VERSION + Version::ZERO,
format,
computation,
indexes,
true,
)?,
file,
})
}
@@ -259,12 +304,36 @@ impl Vecs {
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
fetched: Option<&fetched::Vecs>,
price: Option<&price::Vecs>,
transactions: &transactions::Vecs,
stateful: &stateful::Vecs,
exit: &Exit,
) -> color_eyre::Result<()> {
let circulating_supply = &stateful.utxo_vecs.all.1.height_to_supply;
) -> Result<()> {
self.compute_(
indexer,
indexes,
starting_indexes,
price,
transactions,
stateful,
exit,
)?;
self.file.flush_then_punch()?;
Ok(())
}
#[allow(clippy::too_many_arguments)]
fn compute_(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
price: Option<&price::Vecs>,
transactions: &transactions::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,
@@ -277,12 +346,13 @@ impl Vecs {
circulating_supply,
|(i, v, ..)| (i, StoredF64::from(Bitcoin::from(v))),
exit,
)
)?;
Ok(())
},
)?;
let indexes_to_coinblocks_destroyed =
&stateful.utxo_vecs.all.1.indexes_to_coinblocks_destroyed;
&stateful.utxo_cohorts.all.1.indexes_to_coinblocks_destroyed;
self.indexes_to_coinblocks_stored.compute_all(
indexer,
@@ -303,7 +373,8 @@ impl Vecs {
(i, created.checked_sub(destroyed).unwrap())
},
exit,
)
)?;
Ok(())
},
)?;
@@ -322,7 +393,8 @@ impl Vecs {
.height_extra
.unwrap_cumulative(),
exit,
)
)?;
Ok(())
},
)?;
let liveliness = &self.indexes_to_liveliness;
@@ -338,7 +410,8 @@ impl Vecs {
liveliness.height.as_ref().unwrap(),
|(i, v, ..)| (i, StoredF64::from(1.0).checked_sub(v).unwrap()),
exit,
)
)?;
Ok(())
},
)?;
let vaultedness = &self.indexes_to_vaultedness;
@@ -354,14 +427,15 @@ impl Vecs {
liveliness.height.as_ref().unwrap(),
vaultedness.height.as_ref().unwrap(),
exit,
)
)?;
Ok(())
},
)?;
self.indexes_to_vaulted_supply.compute_all(
indexer,
indexes,
fetched,
price,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
@@ -370,14 +444,15 @@ impl Vecs {
circulating_supply,
vaultedness.height.as_ref().unwrap(),
exit,
)
)?;
Ok(())
},
)?;
self.indexes_to_active_supply.compute_all(
indexer,
indexes,
fetched,
price,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
@@ -386,13 +461,14 @@ impl Vecs {
circulating_supply,
liveliness.height.as_ref().unwrap(),
exit,
)
)?;
Ok(())
},
)?;
if let Some(fetched) = fetched {
if let Some(price) = price {
let realized_cap = stateful
.utxo_vecs
.utxo_cohorts
.all
.1
.height_to_realized_cap
@@ -400,7 +476,7 @@ impl Vecs {
.unwrap();
let realized_price = stateful
.utxo_vecs
.utxo_cohorts
.all
.1
.indexes_to_realized_price
@@ -427,7 +503,8 @@ impl Vecs {
.unwrap_cumulative(),
|(i, v, ..)| (i, v),
exit,
)
)?;
Ok(())
},
)?;
@@ -442,7 +519,8 @@ impl Vecs {
realized_cap,
self.indexes_to_thermo_cap.height.as_ref().unwrap(),
exit,
)
)?;
Ok(())
},
)?;
@@ -457,7 +535,8 @@ impl Vecs {
realized_cap,
self.indexes_to_vaultedness.height.as_ref().unwrap(),
exit,
)
)?;
Ok(())
},
)?;
@@ -472,7 +551,8 @@ impl Vecs {
realized_cap,
self.indexes_to_liveliness.height.as_ref().unwrap(),
exit,
)
)?;
Ok(())
},
)?;
@@ -487,14 +567,15 @@ impl Vecs {
realized_price,
self.indexes_to_vaultedness.height.as_ref().unwrap(),
exit,
)
)?;
Ok(())
},
)?;
self.indexes_to_vaulted_price_ratio.compute_rest(
indexer,
indexes,
fetched,
price,
starting_indexes,
exit,
Some(self.indexes_to_vaulted_price.dateindex.unwrap_last()),
@@ -511,14 +592,15 @@ impl Vecs {
realized_price,
self.indexes_to_liveliness.height.as_ref().unwrap(),
exit,
)
)?;
Ok(())
},
)?;
self.indexes_to_active_price_ratio.compute_rest(
indexer,
indexes,
fetched,
price,
starting_indexes,
exit,
Some(self.indexes_to_active_price.dateindex.unwrap_last()),
@@ -539,14 +621,15 @@ impl Vecs {
.as_ref()
.unwrap(),
exit,
)
)?;
Ok(())
},
)?;
self.indexes_to_true_market_mean_ratio.compute_rest(
indexer,
indexes,
fetched,
price,
starting_indexes,
exit,
Some(self.indexes_to_true_market_mean.dateindex.unwrap_last()),
@@ -562,10 +645,11 @@ impl Vecs {
// The price taken won't be correct for time based indexes
vec.compute_multiply(
starting_indexes.height,
&fetched.chainindexes_to_close.height,
&price.chainindexes_to_close.height,
indexes_to_coinblocks_destroyed.height.as_ref().unwrap(),
exit,
)
)?;
Ok(())
},
)?;
@@ -577,10 +661,11 @@ impl Vecs {
|vec, _, _, starting_indexes, exit| {
vec.compute_multiply(
starting_indexes.height,
&fetched.chainindexes_to_close.height,
&price.chainindexes_to_close.height,
self.indexes_to_coinblocks_created.height.as_ref().unwrap(),
exit,
)
)?;
Ok(())
},
)?;
@@ -592,10 +677,11 @@ impl Vecs {
|vec, _, _, starting_indexes, exit| {
vec.compute_multiply(
starting_indexes.height,
&fetched.chainindexes_to_close.height,
&price.chainindexes_to_close.height,
self.indexes_to_coinblocks_stored.height.as_ref().unwrap(),
exit,
)
)?;
Ok(())
},
)?;
@@ -614,7 +700,8 @@ impl Vecs {
.height_extra
.unwrap_cumulative(),
exit,
)
)?;
Ok(())
},
)?;
@@ -629,14 +716,15 @@ impl Vecs {
self.indexes_to_cointime_price.height.as_ref().unwrap(),
circulating_supply,
exit,
)
)?;
Ok(())
},
)?;
self.indexes_to_cointime_price_ratio.compute_rest(
indexer,
indexes,
fetched,
price,
starting_indexes,
exit,
Some(self.indexes_to_cointime_price.dateindex.unwrap_last()),
@@ -1,13 +1,15 @@
use std::path::Path;
use std::{path::Path, sync::Arc};
use brk_core::{StoredU8, Version};
use brk_exit::Exit;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_vec::{AnyCollectableVec, AnyVec, Computation, Format};
use brk_structs::{StoredU16, Version};
use brk_vecs::{AnyCollectableVec, AnyVec, Computation, Exit, File, Format};
use crate::grouped::Source;
use super::{
Indexes,
grouped::{ComputedVecsFromHeight, StorableVecGeneatorOptions},
grouped::{ComputedVecsFromHeight, VecBuilderOptions},
indexes,
};
@@ -15,52 +17,67 @@ const VERSION: Version = Version::ZERO;
#[derive(Clone)]
pub struct Vecs {
pub constant_0: ComputedVecsFromHeight<StoredU8>,
pub constant_1: ComputedVecsFromHeight<StoredU8>,
pub constant_50: ComputedVecsFromHeight<StoredU8>,
pub constant_100: ComputedVecsFromHeight<StoredU8>,
file: Arc<File>,
pub constant_0: ComputedVecsFromHeight<StoredU16>,
pub constant_1: ComputedVecsFromHeight<StoredU16>,
pub constant_50: ComputedVecsFromHeight<StoredU16>,
pub constant_100: ComputedVecsFromHeight<StoredU16>,
}
impl Vecs {
pub fn forced_import(
path: &Path,
parent: &Path,
version: Version,
_computation: Computation,
computation: Computation,
format: Format,
) -> color_eyre::Result<Self> {
indexes: &indexes::Vecs,
) -> Result<Self> {
let file = Arc::new(File::open(&parent.join("constants"))?);
Ok(Self {
constant_0: ComputedVecsFromHeight::forced_import(
path,
&file,
"constant_0",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
indexes,
VecBuilderOptions::default().add_last(),
)?,
constant_1: ComputedVecsFromHeight::forced_import(
path,
&file,
"constant_1",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
indexes,
VecBuilderOptions::default().add_last(),
)?,
constant_50: ComputedVecsFromHeight::forced_import(
path,
&file,
"constant_50",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
indexes,
VecBuilderOptions::default().add_last(),
)?,
constant_100: ComputedVecsFromHeight::forced_import(
path,
&file,
"constant_100",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
indexes,
VecBuilderOptions::default().add_last(),
)?,
file,
})
}
@@ -70,7 +87,19 @@ impl Vecs {
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> color_eyre::Result<()> {
) -> Result<()> {
self.compute_(indexer, indexes, starting_indexes, exit)?;
self.file.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,
@@ -81,9 +110,10 @@ impl Vecs {
starting_indexes.height,
indexes.height_to_date.len(),
indexes.height_to_date.version(),
|i| (i, StoredU8::new(0)),
|i| (i, StoredU16::new(0)),
exit,
)
)?;
Ok(())
},
)?;
@@ -97,9 +127,10 @@ impl Vecs {
starting_indexes.height,
indexes.height_to_date.len(),
indexes.height_to_date.version(),
|i| (i, StoredU8::new(1)),
|i| (i, StoredU16::new(1)),
exit,
)
)?;
Ok(())
},
)?;
@@ -113,9 +144,10 @@ impl Vecs {
starting_indexes.height,
indexes.height_to_date.len(),
indexes.height_to_date.version(),
|i| (i, StoredU8::new(50)),
|i| (i, StoredU16::new(50)),
exit,
)
)?;
Ok(())
},
)?;
@@ -129,9 +161,10 @@ impl Vecs {
starting_indexes.height,
indexes.height_to_date.len(),
indexes.height_to_date.version(),
|i| (i, StoredU8::new(100)),
|i| (i, StoredU16::new(100)),
exit,
)
)?;
Ok(())
},
)?;
+139
View File
@@ -0,0 +1,139 @@
use std::{path::Path, sync::Arc};
use brk_error::Result;
use brk_fetcher::Fetcher;
use brk_indexer::Indexer;
use brk_structs::{DateIndex, Height, OHLCCents, Version};
use brk_vecs::{
AnyCollectableVec, AnyIterableVec, AnyStoredVec, AnyVec, Exit, File, GenericStoredVec, RawVec,
StoredIndex, VecIterator,
};
use super::{Indexes, indexes};
#[derive(Clone)]
pub struct Vecs {
file: Arc<File>,
fetcher: Fetcher,
pub dateindex_to_ohlc_in_cents: RawVec<DateIndex, OHLCCents>,
pub height_to_ohlc_in_cents: RawVec<Height, OHLCCents>,
}
impl Vecs {
pub fn forced_import(parent: &Path, fetcher: Fetcher, version: Version) -> Result<Self> {
let file = Arc::new(File::open(&parent.join("fetched"))?);
Ok(Self {
fetcher,
dateindex_to_ohlc_in_cents: RawVec::forced_import(
&file,
"ohlc_in_cents",
version + Version::ZERO,
)?,
height_to_ohlc_in_cents: RawVec::forced_import(
&file,
"ohlc_in_cents",
version + Version::ZERO,
)?,
file,
})
}
pub fn compute(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.compute_(indexer, indexes, starting_indexes, exit)?;
self.file.flush_then_punch()?;
Ok(())
}
fn compute_(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
let height_to_timestamp = &indexer.vecs.height_to_timestamp;
let index = starting_indexes
.height
.min(Height::from(self.height_to_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(
i,
self.fetcher
.get_height(
i,
v,
i.decremented().map(|prev_i| {
height_to_timestamp.into_iter().unwrap_get_inner(prev_i)
}),
)
.unwrap(),
exit,
)?;
Ok(())
})?;
self.height_to_ohlc_in_cents.safe_flush(exit)?;
let index = starting_indexes
.dateindex
.min(DateIndex::from(self.dateindex_to_ohlc_in_cents.len()));
let mut prev = None;
indexes
.dateindex_to_date
.iter_at(index)
.try_for_each(|(i, v)| -> Result<()> {
let d = v.into_owned();
if prev.is_none() {
let i = i.unwrap_to_usize();
prev.replace(if i > 0 {
self.dateindex_to_ohlc_in_cents
.into_iter()
.unwrap_get_inner_(i - 1)
} else {
OHLCCents::default()
});
}
let ohlc = if i.unwrap_to_usize() + 100 >= self.dateindex_to_ohlc_in_cents.len()
&& let Ok(mut ohlc) = self.fetcher.get_date(d)
{
let prev_open = *prev.as_ref().unwrap().close;
*ohlc.open = prev_open;
*ohlc.high = (*ohlc.high).max(prev_open);
*ohlc.low = (*ohlc.low).min(prev_open);
ohlc
} else {
prev.clone().unwrap()
};
prev.replace(ohlc.clone());
self.dateindex_to_ohlc_in_cents
.forced_push_at(i, ohlc, exit)?;
Ok(())
})?;
self.dateindex_to_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,
]
}
}
@@ -0,0 +1,475 @@
use std::sync::Arc;
use brk_error::Result;
use brk_structs::Version;
use brk_vecs::{
AnyBoxedIterableVec, AnyCloneableIterableVec, AnyCollectableVec, AnyIterableVec, Computation,
ComputedVec, ComputedVecFrom2, Exit, File, 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(
file: &Arc<File>,
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,
file,
&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,
file,
name,
version + VERSION + Version::ZERO,
format,
source_extra.last.as_ref().map_or_else(
|| {
source
.as_ref()
.unwrap_or_else(|| {
dbg!(file, 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,
file,
&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,
file,
&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,
file,
&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,
file,
&(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,
file,
&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()
}
}
}
@@ -1,16 +1,18 @@
use std::path::Path;
use std::sync::Arc;
use brk_core::{CheckedSub, Result, StoredUsize, Version};
use brk_exit::Exit;
use brk_vec::{AnyCollectableVec, AnyIterableVec, EagerVec, Format, StoredIndex, StoredType};
use color_eyre::eyre::ContextCompat;
use brk_error::{Error, Result};
use brk_structs::{CheckedSub, StoredU64, Version};
use brk_vecs::{
AnyCollectableVec, AnyIterableVec, AnyStoredVec, AnyVec, EagerVec, Exit, File, Format,
GenericStoredVec, StoredIndex, StoredRaw,
};
use crate::utils::get_percentile;
use super::ComputedType;
#[derive(Clone, Debug)]
pub struct ComputedVecBuilder<I, T>
pub struct EagerVecBuilder<I, T>
where
I: StoredIndex,
T: ComputedType,
@@ -31,18 +33,18 @@ where
const VERSION: Version = Version::ZERO;
impl<I, T> ComputedVecBuilder<I, T>
impl<I, T> EagerVecBuilder<I, T>
where
I: StoredIndex,
T: ComputedType,
{
pub fn forced_import(
path: &Path,
file: &Arc<File>,
name: &str,
version: Version,
format: Format,
options: StorableVecGeneatorOptions,
) -> color_eyre::Result<Self> {
options: VecBuilderOptions,
) -> Result<Self> {
let only_one_active = options.is_only_one_active();
let suffix = |s: &str| format!("{name}_{s}");
@@ -59,7 +61,7 @@ where
first: options.first.then(|| {
Box::new(
EagerVec::forced_import(
path,
file,
&maybe_suffix("first"),
version + VERSION + Version::ZERO,
format,
@@ -69,13 +71,13 @@ where
}),
last: options.last.then(|| {
Box::new(
EagerVec::forced_import(path, name, version + Version::ZERO, format).unwrap(),
EagerVec::forced_import(file, name, version + Version::ZERO, format).unwrap(),
)
}),
min: options.min.then(|| {
Box::new(
EagerVec::forced_import(
path,
file,
&maybe_suffix("min"),
version + VERSION + Version::ZERO,
format,
@@ -86,7 +88,7 @@ where
max: options.max.then(|| {
Box::new(
EagerVec::forced_import(
path,
file,
&maybe_suffix("max"),
version + VERSION + Version::ZERO,
format,
@@ -97,7 +99,7 @@ where
median: options.median.then(|| {
Box::new(
EagerVec::forced_import(
path,
file,
&maybe_suffix("median"),
version + VERSION + Version::ZERO,
format,
@@ -108,7 +110,7 @@ where
average: options.average.then(|| {
Box::new(
EagerVec::forced_import(
path,
file,
&maybe_suffix("average"),
version + VERSION + Version::ZERO,
format,
@@ -119,7 +121,7 @@ where
sum: options.sum.then(|| {
Box::new(
EagerVec::forced_import(
path,
file,
&(if !options.last && !options.average && !options.min && !options.max {
name.to_string()
} else {
@@ -134,7 +136,7 @@ where
cumulative: options.cumulative.then(|| {
Box::new(
EagerVec::forced_import(
path,
file,
&suffix("cumulative"),
version + VERSION + Version::ZERO,
format,
@@ -145,7 +147,7 @@ where
_90p: options._90p.then(|| {
Box::new(
EagerVec::forced_import(
path,
file,
&maybe_suffix("90p"),
version + VERSION + Version::ZERO,
format,
@@ -156,7 +158,7 @@ where
_75p: options._75p.then(|| {
Box::new(
EagerVec::forced_import(
path,
file,
&maybe_suffix("75p"),
version + VERSION + Version::ZERO,
format,
@@ -167,7 +169,7 @@ where
_25p: options._25p.then(|| {
Box::new(
EagerVec::forced_import(
path,
file,
&maybe_suffix("25p"),
version + VERSION + Version::ZERO,
format,
@@ -178,7 +180,7 @@ where
_10p: options._10p.then(|| {
Box::new(
EagerVec::forced_import(
path,
file,
&maybe_suffix("10p"),
version + VERSION + Version::ZERO,
format,
@@ -211,8 +213,9 @@ where
cumulative_vec.iter().unwrap_get_inner(index)
});
source.iter_at(index).try_for_each(|(i, v)| -> Result<()> {
cumulative = cumulative.clone() + v.into_owned();
cumulative_vec.forced_push_at(i, cumulative.clone(), exit)
cumulative += v.into_owned();
cumulative_vec.forced_push_at(i, cumulative, exit)?;
Ok(())
})?;
self.safe_flush(exit)?;
@@ -225,11 +228,11 @@ where
max_from: I,
source: &impl AnyIterableVec<I2, T>,
first_indexes: &impl AnyIterableVec<I, I2>,
count_indexes: &impl AnyIterableVec<I, StoredUsize>,
count_indexes: &impl AnyIterableVec<I, StoredU64>,
exit: &Exit,
) -> Result<()>
where
I2: StoredIndex + StoredType + CheckedSub<I2>,
I2: StoredIndex + StoredRaw + CheckedSub<I2>,
{
self.validate_computed_version_or_reset_file(
source.version() + first_indexes.version() + count_indexes.version(),
@@ -263,7 +266,7 @@ where
}
if let Some(last) = self.last.as_mut() {
let count_index = *count_index;
let count_index = *count_index as usize;
if count_index == 0 {
panic!("should compute last if count can be 0")
}
@@ -293,7 +296,7 @@ where
if needs_values {
source_iter.set(first_index);
let mut values = (&mut source_iter)
.take(*count_index)
.take(*count_index as usize)
.map(|(_, v)| v.into_owned())
.collect::<Vec<_>>();
@@ -303,13 +306,13 @@ where
if let Some(max) = self.max.as_mut() {
max.forced_push_at(
i,
values
*values
.last()
.context("expect some")
.ok_or(Error::Str("expect some"))
.inspect_err(|_| {
dbg!(
&values,
max.path(),
max.name(),
first_indexes.name(),
first_index,
count_indexes.name(),
@@ -318,8 +321,7 @@ where
source.name()
);
})
.unwrap()
.clone(),
.unwrap(),
exit,
)?;
}
@@ -345,7 +347,7 @@ where
}
if let Some(min) = self.min.as_mut() {
min.forced_push_at(i, values.first().unwrap().clone(), exit)?;
min.forced_push_at(i, *values.first().unwrap(), exit)?;
}
}
@@ -354,18 +356,18 @@ where
let sum = values.into_iter().fold(T::from(0), |a, b| a + b);
if let Some(average) = self.average.as_mut() {
let avg = sum.clone() / len;
let avg = sum / len;
average.forced_push_at(i, avg, exit)?;
}
if needs_sum_or_cumulative {
if let Some(sum_vec) = self.sum.as_mut() {
sum_vec.forced_push_at(i, sum.clone(), exit)?;
sum_vec.forced_push_at(i, sum, exit)?;
}
if let Some(cumulative_vec) = self.cumulative.as_mut() {
let t = cumulative.as_ref().unwrap().clone() + sum;
cumulative.replace(t.clone());
let t = cumulative.unwrap() + sum;
cumulative.replace(t);
cumulative_vec.forced_push_at(i, t, exit)?;
}
}
@@ -384,13 +386,13 @@ where
pub fn from_aligned<I2>(
&mut self,
max_from: I,
source: &ComputedVecBuilder<I2, T>,
source: &EagerVecBuilder<I2, T>,
first_indexes: &impl AnyIterableVec<I, I2>,
count_indexes: &impl AnyIterableVec<I, StoredUsize>,
count_indexes: &impl AnyIterableVec<I, StoredU64>,
exit: &Exit,
) -> Result<()>
where
I2: StoredIndex + StoredType + CheckedSub<I2>,
I2: StoredIndex + StoredRaw + CheckedSub<I2>,
{
if self._90p.is_some()
|| self._75p.is_some()
@@ -438,7 +440,7 @@ where
}
if let Some(last) = self.last.as_mut() {
let count_index = *count_index;
let count_index = *count_index as usize;
if count_index == 0 {
panic!("should compute last if count can be 0")
}
@@ -462,22 +464,22 @@ where
let source_max_iter = source_max_iter.as_mut().unwrap();
source_max_iter.set(first_index);
let mut values = source_max_iter
.take(*count_index)
.take(*count_index as usize)
.map(|(_, v)| v.into_owned())
.collect::<Vec<_>>();
values.sort_unstable();
max.forced_push_at(i, values.last().unwrap().clone(), exit)?;
max.forced_push_at(i, *values.last().unwrap(), exit)?;
}
if let Some(min) = self.min.as_mut() {
let source_min_iter = source_min_iter.as_mut().unwrap();
source_min_iter.set(first_index);
let mut values = source_min_iter
.take(*count_index)
.take(*count_index as usize)
.map(|(_, v)| v.into_owned())
.collect::<Vec<_>>();
values.sort_unstable();
min.forced_push_at(i, values.first().unwrap().clone(), exit)?;
min.forced_push_at(i, *values.first().unwrap(), exit)?;
}
}
@@ -486,7 +488,7 @@ where
let source_average_iter = source_average_iter.as_mut().unwrap();
source_average_iter.set(first_index);
let values = source_average_iter
.take(*count_index)
.take(*count_index as usize)
.map(|(_, v)| v.into_owned())
.collect::<Vec<_>>();
@@ -502,19 +504,19 @@ where
let source_sum_iter = source_sum_iter.as_mut().unwrap();
source_sum_iter.set(first_index);
let values = source_sum_iter
.take(*count_index)
.take(*count_index as usize)
.map(|(_, v)| v.into_owned())
.collect::<Vec<_>>();
let sum = values.into_iter().fold(T::from(0), |a, b| a + b);
if let Some(sum_vec) = self.sum.as_mut() {
sum_vec.forced_push_at(i, sum.clone(), exit)?;
sum_vec.forced_push_at(i, sum, exit)?;
}
if let Some(cumulative_vec) = self.cumulative.as_mut() {
let t = cumulative.as_ref().unwrap().clone() + sum;
cumulative.replace(t.clone());
let t = cumulative.unwrap() + sum;
cumulative.replace(t);
cumulative_vec.forced_push_at(i, t, exit)?;
}
}
@@ -706,7 +708,7 @@ where
}
#[derive(Default, Clone, Copy)]
pub struct StorableVecGeneatorOptions {
pub struct VecBuilderOptions {
average: bool,
sum: bool,
max: bool,
@@ -721,7 +723,55 @@ pub struct StorableVecGeneatorOptions {
cumulative: bool,
}
impl StorableVecGeneatorOptions {
impl VecBuilderOptions {
pub fn average(&self) -> bool {
self.average
}
pub fn sum(&self) -> bool {
self.sum
}
pub fn max(&self) -> bool {
self.max
}
pub fn _90p(&self) -> bool {
self._90p
}
pub fn _75p(&self) -> bool {
self._75p
}
pub fn median(&self) -> bool {
self.median
}
pub fn _25p(&self) -> bool {
self._25p
}
pub fn _10p(&self) -> bool {
self._10p
}
pub fn min(&self) -> bool {
self.min
}
pub fn first(&self) -> bool {
self.first
}
pub fn last(&self) -> bool {
self.last
}
pub fn cumulative(&self) -> bool {
self.cumulative
}
pub fn add_first(mut self) -> Self {
self.first = true;
self
@@ -0,0 +1,23 @@
use std::ops::{Add, AddAssign, Div};
use brk_vecs::StoredCompressed;
pub trait ComputedType
where
Self: StoredCompressed
+ From<usize>
+ Div<usize, Output = Self>
+ Add<Output = Self>
+ AddAssign
+ Ord,
{
}
impl<T> ComputedType for T where
T: StoredCompressed
+ From<usize>
+ Div<usize, Output = Self>
+ Add<Output = Self>
+ AddAssign
+ Ord
{
}
@@ -0,0 +1,240 @@
use std::sync::Arc;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_structs::{
DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, Version, WeekIndex, YearIndex,
};
use brk_vecs::{
AnyCloneableIterableVec, AnyCollectableVec, AnyIterableVec, Computation, EagerVec, Exit, File,
Format,
};
use crate::{Indexes, grouped::ComputedVecBuilder, indexes};
use super::{ComputedType, EagerVecBuilder, Source, VecBuilderOptions};
#[derive(Clone)]
pub struct ComputedVecsFromDateIndex<T>
where
T: ComputedType + PartialOrd,
{
pub dateindex: Option<EagerVec<DateIndex, T>>,
pub dateindex_extra: EagerVecBuilder<DateIndex, T>,
pub weekindex: ComputedVecBuilder<WeekIndex, T, DateIndex, WeekIndex>,
pub monthindex: ComputedVecBuilder<MonthIndex, T, DateIndex, MonthIndex>,
pub quarterindex: ComputedVecBuilder<QuarterIndex, T, DateIndex, QuarterIndex>,
pub semesterindex: ComputedVecBuilder<SemesterIndex, T, DateIndex, SemesterIndex>,
pub yearindex: ComputedVecBuilder<YearIndex, T, DateIndex, YearIndex>,
pub decadeindex: ComputedVecBuilder<DecadeIndex, T, DateIndex, DecadeIndex>,
}
const VERSION: Version = Version::ZERO;
impl<T> ComputedVecsFromDateIndex<T>
where
T: ComputedType + 'static,
{
#[allow(clippy::too_many_arguments)]
pub fn forced_import(
file: &Arc<File>,
name: &str,
source: Source<DateIndex, T>,
version: Version,
format: Format,
computation: Computation,
indexes: &indexes::Vecs,
options: VecBuilderOptions,
) -> Result<Self> {
let dateindex = source.is_compute().then(|| {
EagerVec::forced_import(file, name, version + VERSION + Version::ZERO, format).unwrap()
});
let dateindex_extra = EagerVecBuilder::forced_import(
file,
name,
version + VERSION + Version::ZERO,
format,
options.copy_self_extra(),
)?;
let options = options.remove_percentiles();
let dateindex_source = source.vec().or(dateindex.as_ref().map(|v| v.boxed_clone()));
Ok(Self {
weekindex: ComputedVecBuilder::forced_import(
file,
name,
version + VERSION + Version::ZERO,
format,
computation,
dateindex_source.clone(),
&dateindex_extra,
indexes.weekindex_to_weekindex.boxed_clone(),
options.into(),
)?,
monthindex: ComputedVecBuilder::forced_import(
file,
name,
version + VERSION + Version::ZERO,
format,
Computation::Lazy,
dateindex_source.clone(),
&dateindex_extra,
indexes.monthindex_to_monthindex.boxed_clone(),
options.into(),
)?,
quarterindex: ComputedVecBuilder::forced_import(
file,
name,
version + VERSION + Version::ZERO,
format,
Computation::Lazy,
dateindex_source.clone(),
&dateindex_extra,
indexes.quarterindex_to_quarterindex.boxed_clone(),
options.into(),
)?,
semesterindex: ComputedVecBuilder::forced_import(
file,
name,
version + VERSION + Version::ZERO,
format,
Computation::Lazy,
dateindex_source.clone(),
&dateindex_extra,
indexes.semesterindex_to_semesterindex.boxed_clone(),
options.into(),
)?,
yearindex: ComputedVecBuilder::forced_import(
file,
name,
version + VERSION + Version::ZERO,
format,
Computation::Lazy,
dateindex_source.clone(),
&dateindex_extra,
indexes.yearindex_to_yearindex.boxed_clone(),
options.into(),
)?,
decadeindex: ComputedVecBuilder::forced_import(
file,
name,
version + VERSION + Version::ZERO,
format,
Computation::Lazy,
dateindex_source.clone(),
&dateindex_extra,
indexes.decadeindex_to_decadeindex.boxed_clone(),
options.into(),
)?,
dateindex,
dateindex_extra,
})
}
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<()>,
{
compute(
self.dateindex.as_mut().unwrap(),
indexer,
indexes,
starting_indexes,
exit,
)?;
let dateindex: Option<&EagerVec<DateIndex, T>> = None;
self.compute_rest(indexes, starting_indexes, exit, dateindex)
}
pub fn compute_rest(
&mut self,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
dateindex: Option<&impl AnyIterableVec<DateIndex, T>>,
) -> Result<()> {
if let Some(dateindex) = dateindex {
self.dateindex_extra
.extend(starting_indexes.dateindex, dateindex, exit)?;
} else {
let dateindex = self.dateindex.as_ref().unwrap();
self.dateindex_extra
.extend(starting_indexes.dateindex, dateindex, exit)?;
}
self.weekindex.compute_if_necessary(
starting_indexes.weekindex,
&indexes.weekindex_to_dateindex_count,
exit,
)?;
self.monthindex.compute_if_necessary(
starting_indexes.monthindex,
&indexes.monthindex_to_dateindex_count,
exit,
)?;
self.quarterindex.compute_if_necessary(
starting_indexes.quarterindex,
&indexes.quarterindex_to_monthindex_count,
exit,
)?;
self.semesterindex.compute_if_necessary(
starting_indexes.semesterindex,
&indexes.semesterindex_to_monthindex_count,
exit,
)?;
self.yearindex.compute_if_necessary(
starting_indexes.yearindex,
&indexes.yearindex_to_monthindex_count,
exit,
)?;
self.decadeindex.compute_if_necessary(
starting_indexes.decadeindex,
&indexes.decadeindex_to_yearindex_count,
exit,
)?;
Ok(())
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
[
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<_>>()
}
}
@@ -1,16 +1,24 @@
use std::path::Path;
use std::sync::Arc;
use brk_error::Result;
use brk_core::{
DateIndex, DecadeIndex, DifficultyEpoch, Height, MonthIndex, QuarterIndex, Result, Version,
WeekIndex, YearIndex,
};
use brk_exit::Exit;
use brk_indexer::Indexer;
use brk_vec::{AnyCollectableVec, AnyIterableVec, EagerVec, Format};
use brk_structs::{
DateIndex, DecadeIndex, DifficultyEpoch, Height, MonthIndex, QuarterIndex, SemesterIndex,
Version, WeekIndex, YearIndex,
};
use brk_vecs::{
AnyCloneableIterableVec, AnyCollectableVec, AnyIterableVec, Computation, EagerVec, Exit, File,
Format,
};
use crate::vecs::{Indexes, indexes};
use crate::{
Indexes,
grouped::{ComputedVecBuilder, Source},
indexes,
};
use super::{ComputedType, ComputedVecBuilder, StorableVecGeneatorOptions};
use super::{ComputedType, EagerVecBuilder, VecBuilderOptions};
#[derive(Clone)]
pub struct ComputedVecsFromHeight<T>
@@ -18,47 +26,50 @@ where
T: ComputedType + PartialOrd,
{
pub height: Option<EagerVec<Height, T>>,
pub height_extra: ComputedVecBuilder<Height, T>,
pub dateindex: ComputedVecBuilder<DateIndex, T>,
pub weekindex: ComputedVecBuilder<WeekIndex, T>,
pub difficultyepoch: ComputedVecBuilder<DifficultyEpoch, T>,
pub monthindex: ComputedVecBuilder<MonthIndex, T>,
pub quarterindex: ComputedVecBuilder<QuarterIndex, T>,
// 6 months
pub yearindex: ComputedVecBuilder<YearIndex, T>,
pub height_extra: EagerVecBuilder<Height, T>,
pub dateindex: EagerVecBuilder<DateIndex, T>,
pub weekindex: ComputedVecBuilder<WeekIndex, T, DateIndex, WeekIndex>,
pub difficultyepoch: EagerVecBuilder<DifficultyEpoch, T>,
pub monthindex: ComputedVecBuilder<MonthIndex, T, DateIndex, MonthIndex>,
pub quarterindex: ComputedVecBuilder<QuarterIndex, T, DateIndex, QuarterIndex>,
pub semesterindex: ComputedVecBuilder<SemesterIndex, T, DateIndex, SemesterIndex>,
pub yearindex: ComputedVecBuilder<YearIndex, T, DateIndex, YearIndex>,
// TODO: pub halvingepoch: StorableVecGeneator<Halvingepoch, T>,
pub decadeindex: ComputedVecBuilder<DecadeIndex, T>,
pub decadeindex: ComputedVecBuilder<DecadeIndex, T, DateIndex, DecadeIndex>,
}
const VERSION: Version = Version::ZERO;
impl<T> ComputedVecsFromHeight<T>
where
T: ComputedType + Ord + From<f64>,
T: ComputedType + Ord + From<f64> + 'static,
f64: From<T>,
{
#[allow(clippy::too_many_arguments)]
pub fn forced_import(
path: &Path,
file: &Arc<File>,
name: &str,
compute_source: bool,
source: Source<Height, T>,
version: Version,
format: Format,
options: StorableVecGeneatorOptions,
) -> color_eyre::Result<Self> {
let height = compute_source.then(|| {
EagerVec::forced_import(path, name, version + VERSION + Version::ZERO, format).unwrap()
computation: Computation,
indexes: &indexes::Vecs,
options: VecBuilderOptions,
) -> Result<Self> {
let height = source.is_compute().then(|| {
EagerVec::forced_import(file, name, version + VERSION + Version::ZERO, format).unwrap()
});
let height_extra = ComputedVecBuilder::forced_import(
path,
let height_extra = EagerVecBuilder::forced_import(
file,
name,
version + VERSION + Version::ZERO,
format,
options.copy_self_extra(),
)?;
let dateindex = ComputedVecBuilder::forced_import(
path,
let dateindex = EagerVecBuilder::forced_import(
file,
name,
version + VERSION + Version::ZERO,
format,
@@ -68,47 +79,78 @@ where
let options = options.remove_percentiles();
Ok(Self {
weekindex: ComputedVecBuilder::forced_import(
file,
name,
version + VERSION + Version::ZERO,
format,
computation,
None,
&dateindex,
indexes.weekindex_to_weekindex.boxed_clone(),
options.into(),
)?,
monthindex: ComputedVecBuilder::forced_import(
file,
name,
version + VERSION + Version::ZERO,
format,
Computation::Lazy,
None,
&dateindex,
indexes.monthindex_to_monthindex.boxed_clone(),
options.into(),
)?,
quarterindex: ComputedVecBuilder::forced_import(
file,
name,
version + VERSION + Version::ZERO,
format,
Computation::Lazy,
None,
&dateindex,
indexes.quarterindex_to_quarterindex.boxed_clone(),
options.into(),
)?,
semesterindex: ComputedVecBuilder::forced_import(
file,
name,
version + VERSION + Version::ZERO,
format,
Computation::Lazy,
None,
&dateindex,
indexes.semesterindex_to_semesterindex.boxed_clone(),
options.into(),
)?,
yearindex: ComputedVecBuilder::forced_import(
file,
name,
version + VERSION + Version::ZERO,
format,
Computation::Lazy,
None,
&dateindex,
indexes.yearindex_to_yearindex.boxed_clone(),
options.into(),
)?,
decadeindex: ComputedVecBuilder::forced_import(
file,
name,
version + VERSION + Version::ZERO,
format,
Computation::Lazy,
None,
&dateindex,
indexes.decadeindex_to_decadeindex.boxed_clone(),
options.into(),
)?,
// halvingepoch: StorableVecGeneator::forced_import(file, name, version + VERSION + Version::ZERO, format, options)?,
height,
height_extra,
dateindex,
weekindex: ComputedVecBuilder::forced_import(
path,
name,
version + VERSION + Version::ZERO,
format,
options,
)?,
difficultyepoch: ComputedVecBuilder::forced_import(
path,
name,
version + VERSION + Version::ZERO,
format,
options,
)?,
monthindex: ComputedVecBuilder::forced_import(
path,
name,
version + VERSION + Version::ZERO,
format,
options,
)?,
quarterindex: ComputedVecBuilder::forced_import(
path,
name,
version + VERSION + Version::ZERO,
format,
options,
)?,
yearindex: ComputedVecBuilder::forced_import(
path,
name,
version + VERSION + Version::ZERO,
format,
options,
)?,
// halvingepoch: StorableVecGeneator::forced_import(path, name, version + VERSION + Version::ZERO, format, options)?,
decadeindex: ComputedVecBuilder::forced_import(
path,
difficultyepoch: EagerVecBuilder::forced_import(
file,
name,
version + VERSION + Version::ZERO,
format,
@@ -124,7 +166,7 @@ where
starting_indexes: &Indexes,
exit: &Exit,
mut compute: F,
) -> color_eyre::Result<()>
) -> Result<()>
where
F: FnMut(&mut EagerVec<Height, T>, &Indexer, &indexes::Vecs, &Indexes, &Exit) -> Result<()>,
{
@@ -146,7 +188,7 @@ where
starting_indexes: &Indexes,
exit: &Exit,
height_vec: Option<&impl AnyIterableVec<Height, T>>,
) -> color_eyre::Result<()> {
) -> Result<()> {
if let Some(height) = height_vec {
self.height_extra
.extend(starting_indexes.height, height, exit)?;
@@ -189,42 +231,38 @@ where
)?;
}
self.weekindex.from_aligned(
self.weekindex.compute_if_necessary(
starting_indexes.weekindex,
&self.dateindex,
&indexes.weekindex_to_first_dateindex,
&indexes.weekindex_to_dateindex_count,
exit,
)?;
self.monthindex.from_aligned(
self.monthindex.compute_if_necessary(
starting_indexes.monthindex,
&self.dateindex,
&indexes.monthindex_to_first_dateindex,
&indexes.monthindex_to_dateindex_count,
exit,
)?;
self.quarterindex.from_aligned(
self.quarterindex.compute_if_necessary(
starting_indexes.quarterindex,
&self.monthindex,
&indexes.quarterindex_to_first_monthindex,
&indexes.quarterindex_to_monthindex_count,
exit,
)?;
self.yearindex.from_aligned(
self.semesterindex.compute_if_necessary(
starting_indexes.semesterindex,
&indexes.semesterindex_to_monthindex_count,
exit,
)?;
self.yearindex.compute_if_necessary(
starting_indexes.yearindex,
&self.monthindex,
&indexes.yearindex_to_first_monthindex,
&indexes.yearindex_to_monthindex_count,
exit,
)?;
self.decadeindex.from_aligned(
self.decadeindex.compute_if_necessary(
starting_indexes.decadeindex,
&self.yearindex,
&indexes.decadeindex_to_first_yearindex,
&indexes.decadeindex_to_yearindex_count,
exit,
)?;
@@ -243,6 +281,7 @@ where
self.difficultyepoch.vecs(),
self.monthindex.vecs(),
self.quarterindex.vecs(),
self.semesterindex.vecs(),
self.yearindex.vecs(),
// self.halvingepoch.vecs(),
self.decadeindex.vecs(),
@@ -1,13 +1,14 @@
use std::path::Path;
use std::sync::Arc;
use brk_error::Result;
use brk_core::{DifficultyEpoch, Height, Result, Version};
use brk_exit::Exit;
use brk_indexer::Indexer;
use brk_vec::{AnyCollectableVec, EagerVec, Format};
use brk_structs::{DifficultyEpoch, Height, Version};
use brk_vecs::{AnyCollectableVec, EagerVec, Exit, File, Format};
use crate::vecs::{indexes, Indexes};
use crate::{Indexes, indexes};
use super::{ComputedType, ComputedVecBuilder, StorableVecGeneatorOptions};
use super::{ComputedType, EagerVecBuilder, VecBuilderOptions};
#[derive(Clone)]
pub struct ComputedVecsFromHeightStrict<T>
@@ -15,8 +16,8 @@ where
T: ComputedType + PartialOrd,
{
pub height: EagerVec<Height, T>,
pub height_extra: ComputedVecBuilder<Height, T>,
pub difficultyepoch: ComputedVecBuilder<DifficultyEpoch, T>,
pub height_extra: EagerVecBuilder<Height, T>,
pub difficultyepoch: EagerVecBuilder<DifficultyEpoch, T>,
// TODO: pub halvingepoch: StorableVecGeneator<Halvingepoch, T>,
}
@@ -28,17 +29,17 @@ where
f64: From<T>,
{
pub fn forced_import(
path: &Path,
file: &Arc<File>,
name: &str,
version: Version,
format: Format,
options: StorableVecGeneatorOptions,
) -> color_eyre::Result<Self> {
options: VecBuilderOptions,
) -> Result<Self> {
let height =
EagerVec::forced_import(path, name, version + VERSION + Version::ZERO, format)?;
EagerVec::forced_import(file, name, version + VERSION + Version::ZERO, format)?;
let height_extra = ComputedVecBuilder::forced_import(
path,
let height_extra = EagerVecBuilder::forced_import(
file,
name,
version + VERSION + Version::ZERO,
format,
@@ -50,14 +51,14 @@ where
Ok(Self {
height,
height_extra,
difficultyepoch: ComputedVecBuilder::forced_import(
path,
difficultyepoch: EagerVecBuilder::forced_import(
file,
name,
version + VERSION + Version::ZERO,
format,
options,
)?,
// halvingepoch: StorableVecGeneator::forced_import(path, name, version + VERSION + Version::ZERO, format, options)?,
// halvingepoch: StorableVecGeneator::forced_import(file, name, version + VERSION + Version::ZERO, format, options)?,
})
}
@@ -68,7 +69,7 @@ where
starting_indexes: &Indexes,
exit: &Exit,
mut compute: F,
) -> color_eyre::Result<()>
) -> Result<()>
where
F: FnMut(&mut EagerVec<Height, T>, &Indexer, &indexes::Vecs, &Indexes, &Exit) -> Result<()>,
{
@@ -1,18 +1,23 @@
use std::path::Path;
use std::sync::Arc;
use brk_core::{
Bitcoin, DateIndex, DecadeIndex, DifficultyEpoch, Dollars, Height, MonthIndex, QuarterIndex,
Result, Sats, TxIndex, Version, WeekIndex, YearIndex,
};
use brk_exit::Exit;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_vec::{
AnyCollectableVec, AnyVec, CollectableVec, EagerVec, Format, StoredIndex, VecIterator,
use brk_structs::{
Bitcoin, DateIndex, DecadeIndex, DifficultyEpoch, Dollars, Height, MonthIndex, QuarterIndex,
Sats, SemesterIndex, TxIndex, Version, WeekIndex, YearIndex,
};
use brk_vecs::{
AnyCloneableIterableVec, AnyCollectableVec, AnyVec, CollectableVec, Computation, EagerVec,
Exit, File, Format, GenericStoredVec, StoredIndex, VecIterator,
};
use crate::vecs::{Indexes, fetched, indexes};
use crate::{
Indexes,
grouped::{ComputedVecBuilder, Source},
indexes, price,
};
use super::{ComputedType, ComputedVecBuilder, StorableVecGeneatorOptions};
use super::{ComputedType, EagerVecBuilder, VecBuilderOptions};
#[derive(Clone)]
pub struct ComputedVecsFromTxindex<T>
@@ -20,41 +25,45 @@ where
T: ComputedType + PartialOrd,
{
pub txindex: Option<Box<EagerVec<TxIndex, T>>>,
pub height: ComputedVecBuilder<Height, T>,
pub dateindex: ComputedVecBuilder<DateIndex, T>,
pub weekindex: ComputedVecBuilder<WeekIndex, T>,
pub difficultyepoch: ComputedVecBuilder<DifficultyEpoch, T>,
pub monthindex: ComputedVecBuilder<MonthIndex, T>,
pub quarterindex: ComputedVecBuilder<QuarterIndex, T>,
pub yearindex: ComputedVecBuilder<YearIndex, T>,
pub height: EagerVecBuilder<Height, T>,
pub dateindex: EagerVecBuilder<DateIndex, T>,
pub weekindex: ComputedVecBuilder<WeekIndex, T, DateIndex, WeekIndex>,
pub difficultyepoch: EagerVecBuilder<DifficultyEpoch, T>,
pub monthindex: ComputedVecBuilder<MonthIndex, T, DateIndex, MonthIndex>,
pub quarterindex: ComputedVecBuilder<QuarterIndex, T, DateIndex, QuarterIndex>,
pub semesterindex: ComputedVecBuilder<SemesterIndex, T, DateIndex, SemesterIndex>,
pub yearindex: ComputedVecBuilder<YearIndex, T, DateIndex, YearIndex>,
// TODO: pub halvingepoch: StorableVecGeneator<Halvingepoch, T>,
pub decadeindex: ComputedVecBuilder<DecadeIndex, T>,
pub decadeindex: ComputedVecBuilder<DecadeIndex, T, DateIndex, DecadeIndex>,
}
const VERSION: Version = Version::ZERO;
impl<T> ComputedVecsFromTxindex<T>
where
T: ComputedType + Ord + From<f64>,
T: ComputedType + Ord + From<f64> + 'static,
f64: From<T>,
{
#[allow(clippy::too_many_arguments)]
pub fn forced_import(
path: &Path,
file: &Arc<File>,
name: &str,
compute_source: bool,
source: Source<TxIndex, T>,
version: Version,
format: Format,
options: StorableVecGeneatorOptions,
) -> color_eyre::Result<Self> {
let txindex = compute_source.then(|| {
computation: Computation,
indexes: &indexes::Vecs,
options: VecBuilderOptions,
) -> Result<Self> {
let txindex = source.is_compute().then(|| {
Box::new(
EagerVec::forced_import(path, name, version + VERSION + Version::ZERO, format)
EagerVec::forced_import(file, name, version + VERSION + Version::ZERO, format)
.unwrap(),
)
});
let height = ComputedVecBuilder::forced_import(
path,
let height = EagerVecBuilder::forced_import(
file,
name,
version + VERSION + Version::ZERO,
format,
@@ -63,59 +72,93 @@ where
let options = options.remove_percentiles();
let dateindex = EagerVecBuilder::forced_import(
file,
name,
version + VERSION + Version::ZERO,
format,
options,
)?;
Ok(Self {
txindex,
height,
dateindex: ComputedVecBuilder::forced_import(
path,
name,
version + VERSION + Version::ZERO,
format,
options,
)?,
weekindex: ComputedVecBuilder::forced_import(
path,
file,
name,
version + VERSION + Version::ZERO,
format,
options,
)?,
difficultyepoch: ComputedVecBuilder::forced_import(
path,
name,
version + VERSION + Version::ZERO,
format,
options,
computation,
None,
&dateindex,
indexes.weekindex_to_weekindex.boxed_clone(),
options.into(),
)?,
monthindex: ComputedVecBuilder::forced_import(
path,
file,
name,
version + VERSION + Version::ZERO,
format,
options,
Computation::Lazy,
None,
&dateindex,
indexes.monthindex_to_monthindex.boxed_clone(),
options.into(),
)?,
quarterindex: ComputedVecBuilder::forced_import(
path,
file,
name,
version + VERSION + Version::ZERO,
format,
options,
Computation::Lazy,
None,
&dateindex,
indexes.quarterindex_to_quarterindex.boxed_clone(),
options.into(),
)?,
semesterindex: ComputedVecBuilder::forced_import(
file,
name,
version + VERSION + Version::ZERO,
format,
Computation::Lazy,
None,
&dateindex,
indexes.semesterindex_to_semesterindex.boxed_clone(),
options.into(),
)?,
yearindex: ComputedVecBuilder::forced_import(
path,
file,
name,
version + VERSION + Version::ZERO,
format,
options,
Computation::Lazy,
None,
&dateindex,
indexes.yearindex_to_yearindex.boxed_clone(),
options.into(),
)?,
// halvingepoch: StorableVecGeneator::forced_import(path, name, version + VERSION + Version::ZERO, format, options)?,
decadeindex: ComputedVecBuilder::forced_import(
path,
file,
name,
version + VERSION + Version::ZERO,
format,
Computation::Lazy,
None,
&dateindex,
indexes.decadeindex_to_decadeindex.boxed_clone(),
options.into(),
)?,
txindex,
height,
dateindex,
difficultyepoch: EagerVecBuilder::forced_import(
file,
name,
version + VERSION + Version::ZERO,
format,
options,
)?,
// halvingepoch: StorableVecGeneator::forced_import(file, name, version + VERSION + Version::ZERO, format, options)?,
})
}
@@ -127,7 +170,7 @@ where
// starting_indexes: &Indexes,
// exit: &Exit,
// mut compute: F,
// ) -> color_eyre::Result<()>
// ) -> Result<()>
// where
// F: FnMut(
// &mut EagerVec<TxIndex, T>,
@@ -196,42 +239,38 @@ where
exit,
)?;
self.weekindex.from_aligned(
self.weekindex.compute_if_necessary(
starting_indexes.weekindex,
&self.dateindex,
&indexes.weekindex_to_first_dateindex,
&indexes.weekindex_to_dateindex_count,
exit,
)?;
self.monthindex.from_aligned(
self.monthindex.compute_if_necessary(
starting_indexes.monthindex,
&self.dateindex,
&indexes.monthindex_to_first_dateindex,
&indexes.monthindex_to_dateindex_count,
exit,
)?;
self.quarterindex.from_aligned(
self.quarterindex.compute_if_necessary(
starting_indexes.quarterindex,
&self.monthindex,
&indexes.quarterindex_to_first_monthindex,
&indexes.quarterindex_to_monthindex_count,
exit,
)?;
self.yearindex.from_aligned(
self.semesterindex.compute_if_necessary(
starting_indexes.semesterindex,
&indexes.semesterindex_to_monthindex_count,
exit,
)?;
self.yearindex.compute_if_necessary(
starting_indexes.yearindex,
&self.monthindex,
&indexes.yearindex_to_first_monthindex,
&indexes.yearindex_to_monthindex_count,
exit,
)?;
self.decadeindex.from_aligned(
self.decadeindex.compute_if_necessary(
starting_indexes.decadeindex,
&self.yearindex,
&indexes.decadeindex_to_first_yearindex,
&indexes.decadeindex_to_yearindex_count,
exit,
)?;
@@ -258,6 +297,7 @@ where
self.difficultyepoch.vecs(),
self.monthindex.vecs(),
self.quarterindex.vecs(),
self.semesterindex.vecs(),
self.yearindex.vecs(),
// self.halvingepoch.vecs(),
self.decadeindex.vecs(),
@@ -455,7 +495,7 @@ impl ComputedVecsFromTxindex<Dollars> {
exit: &Exit,
bitcoin: &ComputedVecsFromTxindex<Bitcoin>,
txindex: Option<&impl CollectableVec<TxIndex, Dollars>>,
fetched: &fetched::Vecs,
price: &price::Vecs,
) -> Result<()> {
let txindex_version = if let Some(txindex) = txindex {
txindex.version()
@@ -468,7 +508,7 @@ impl ComputedVecsFromTxindex<Dollars> {
let starting_index = self.height.starting_index(starting_indexes.height);
let mut close_iter = fetched.chainindexes_to_close.height.into_iter();
let mut close_iter = price.chainindexes_to_close.height.into_iter();
(starting_index.unwrap_to_usize()..indexer.vecs.height_to_weight.len())
.map(Height::from)
@@ -1,22 +1,26 @@
mod builder;
mod builder_computed;
mod builder_eager;
mod computed;
mod from_dateindex;
mod from_height;
mod from_height_strict;
mod from_txindex;
mod ratio_from_dateindex;
mod r#type;
mod source;
mod value_from_dateindex;
mod value_from_height;
mod value_from_txindex;
mod value_height;
pub use builder::*;
pub use builder_computed::*;
pub use builder_eager::*;
use computed::*;
pub use from_dateindex::*;
pub use from_height::*;
pub use from_height_strict::*;
pub use from_txindex::*;
pub use ratio_from_dateindex::*;
use r#type::*;
pub use source::*;
pub use value_from_dateindex::*;
pub use value_from_height::*;
pub use value_from_txindex::*;
File diff suppressed because it is too large Load Diff
+51
View File
@@ -0,0 +1,51 @@
use brk_vecs::AnyBoxedIterableVec;
#[derive(Clone)]
pub enum Source<I, T> {
Compute,
None,
Vec(AnyBoxedIterableVec<I, T>),
}
impl<I, T> Source<I, T> {
pub fn is_compute(&self) -> bool {
matches!(self, Self::Compute)
}
pub fn is_none(&self) -> bool {
matches!(self, Self::None)
}
pub fn is_vec(&self) -> bool {
matches!(self, Self::Vec(_))
}
pub fn vec(self) -> Option<AnyBoxedIterableVec<I, T>> {
match self {
Self::Vec(v) => Some(v),
_ => None,
}
}
}
impl<I, T> From<bool> for Source<I, T> {
fn from(value: bool) -> Self {
if value { Self::Compute } else { Self::None }
}
}
impl<I, T> From<AnyBoxedIterableVec<I, T>> for Source<I, T> {
fn from(value: AnyBoxedIterableVec<I, T>) -> Self {
Self::Vec(value)
}
}
impl<I, T> From<Option<AnyBoxedIterableVec<I, T>>> for Source<I, T> {
fn from(value: Option<AnyBoxedIterableVec<I, T>>) -> Self {
if let Some(v) = value {
Self::Vec(v)
} else {
Self::None
}
}
}
@@ -1,13 +1,20 @@
use std::path::Path;
use std::sync::Arc;
use brk_core::{Bitcoin, DateIndex, Dollars, Result, Sats, Version};
use brk_exit::Exit;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_vec::{AnyCollectableVec, CollectableVec, EagerVec, Format, StoredVec};
use brk_structs::{Bitcoin, DateIndex, Dollars, Sats, Version};
use brk_vecs::{
AnyCollectableVec, CollectableVec, Computation, EagerVec, Exit, File, Format, StoredVec,
};
use crate::vecs::{Indexes, fetched, grouped::ComputedVecsFromDateIndex, indexes};
use crate::{
Indexes,
grouped::ComputedVecsFromDateIndex,
indexes, price,
traits::{ComputeFromBitcoin, ComputeFromSats},
};
use super::StorableVecGeneatorOptions;
use super::{Source, VecBuilderOptions};
#[derive(Clone)]
pub struct ComputedValueVecsFromDateIndex {
@@ -19,39 +26,48 @@ pub struct ComputedValueVecsFromDateIndex {
const VERSION: Version = Version::ZERO;
impl ComputedValueVecsFromDateIndex {
#[allow(clippy::too_many_arguments)]
pub fn forced_import(
path: &Path,
file: &Arc<File>,
name: &str,
compute_source: bool,
source: Source<DateIndex, Sats>,
version: Version,
format: Format,
options: StorableVecGeneatorOptions,
computation: Computation,
options: VecBuilderOptions,
compute_dollars: bool,
) -> color_eyre::Result<Self> {
indexes: &indexes::Vecs,
) -> Result<Self> {
Ok(Self {
sats: ComputedVecsFromDateIndex::forced_import(
path,
file,
name,
compute_source,
source,
version + VERSION,
format,
computation,
indexes,
options,
)?,
bitcoin: ComputedVecsFromDateIndex::forced_import(
path,
file,
&format!("{name}_in_btc"),
true,
Source::Compute,
version + VERSION,
format,
computation,
indexes,
options,
)?,
dollars: compute_dollars.then(|| {
ComputedVecsFromDateIndex::forced_import(
path,
file,
&format!("{name}_in_usd"),
true,
Source::Compute,
version + VERSION,
format,
computation,
indexes,
options,
)
.unwrap()
@@ -63,11 +79,11 @@ impl ComputedValueVecsFromDateIndex {
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
fetched: Option<&fetched::Vecs>,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
exit: &Exit,
mut compute: F,
) -> color_eyre::Result<()>
) -> Result<()>
where
F: FnMut(
&mut EagerVec<DateIndex, Sats>,
@@ -86,7 +102,7 @@ impl ComputedValueVecsFromDateIndex {
)?;
let dateindex: Option<&StoredVec<DateIndex, Sats>> = None;
self.compute_rest(indexer, indexes, fetched, starting_indexes, exit, dateindex)?;
self.compute_rest(indexer, indexes, price, starting_indexes, exit, dateindex)?;
Ok(())
}
@@ -95,11 +111,11 @@ impl ComputedValueVecsFromDateIndex {
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
fetched: Option<&fetched::Vecs>,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
exit: &Exit,
dateindex: Option<&impl CollectableVec<DateIndex, Sats>>,
) -> color_eyre::Result<()> {
) -> Result<()> {
if let Some(dateindex) = dateindex {
self.sats
.compute_rest(indexes, starting_indexes, exit, Some(dateindex))?;
@@ -135,7 +151,7 @@ impl ComputedValueVecsFromDateIndex {
}
let dateindex_to_bitcoin = self.bitcoin.dateindex.as_ref().unwrap();
let dateindex_to_close = fetched
let dateindex_to_close = price
.as_ref()
.unwrap()
.timeindexes_to_close
@@ -1,13 +1,20 @@
use std::path::Path;
use std::sync::Arc;
use brk_core::{Bitcoin, Dollars, Height, Result, Sats, Version};
use brk_exit::Exit;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_vec::{AnyCollectableVec, CollectableVec, EagerVec, Format, StoredVec};
use brk_structs::{Bitcoin, Dollars, Height, Sats, Version};
use brk_vecs::{
AnyCollectableVec, CollectableVec, Computation, EagerVec, Exit, File, Format, StoredVec,
};
use crate::vecs::{Indexes, fetched, indexes};
use crate::{
Indexes,
grouped::Source,
indexes, price,
traits::{ComputeFromBitcoin, ComputeFromSats},
};
use super::{ComputedVecsFromHeight, StorableVecGeneatorOptions};
use super::{ComputedVecsFromHeight, VecBuilderOptions};
#[derive(Clone)]
pub struct ComputedValueVecsFromHeight {
@@ -19,39 +26,48 @@ pub struct ComputedValueVecsFromHeight {
const VERSION: Version = Version::ZERO;
impl ComputedValueVecsFromHeight {
#[allow(clippy::too_many_arguments)]
pub fn forced_import(
path: &Path,
file: &Arc<File>,
name: &str,
compute_source: bool,
source: Source<Height, Sats>,
version: Version,
format: Format,
options: StorableVecGeneatorOptions,
computation: Computation,
options: VecBuilderOptions,
compute_dollars: bool,
) -> color_eyre::Result<Self> {
indexes: &indexes::Vecs,
) -> Result<Self> {
Ok(Self {
sats: ComputedVecsFromHeight::forced_import(
path,
file,
name,
compute_source,
source,
version + VERSION,
format,
computation,
indexes,
options,
)?,
bitcoin: ComputedVecsFromHeight::forced_import(
path,
file,
&format!("{name}_in_btc"),
true,
Source::Compute,
version + VERSION,
format,
computation,
indexes,
options,
)?,
dollars: compute_dollars.then(|| {
ComputedVecsFromHeight::forced_import(
path,
file,
&format!("{name}_in_usd"),
true,
Source::Compute,
version + VERSION,
format,
computation,
indexes,
options,
)
.unwrap()
@@ -63,11 +79,11 @@ impl ComputedValueVecsFromHeight {
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
fetched: Option<&fetched::Vecs>,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
exit: &Exit,
mut compute: F,
) -> color_eyre::Result<()>
) -> Result<()>
where
F: FnMut(
&mut EagerVec<Height, Sats>,
@@ -86,7 +102,7 @@ impl ComputedValueVecsFromHeight {
)?;
let height: Option<&StoredVec<Height, Sats>> = None;
self.compute_rest(indexer, indexes, fetched, starting_indexes, exit, height)?;
self.compute_rest(indexer, indexes, price, starting_indexes, exit, height)?;
Ok(())
}
@@ -95,11 +111,11 @@ impl ComputedValueVecsFromHeight {
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
fetched: Option<&fetched::Vecs>,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
exit: &Exit,
height: Option<&impl CollectableVec<Height, Sats>>,
) -> color_eyre::Result<()> {
) -> Result<()> {
if let Some(height) = height {
self.sats
.compute_rest(indexes, starting_indexes, exit, Some(height))?;
@@ -135,7 +151,7 @@ impl ComputedValueVecsFromHeight {
}
let height_to_bitcoin = self.bitcoin.height.as_ref().unwrap();
let height_to_close = &fetched.as_ref().unwrap().chainindexes_to_close.height;
let height_to_close = &price.as_ref().unwrap().chainindexes_to_close.height;
if let Some(dollars) = self.dollars.as_mut() {
dollars.compute_all(
@@ -1,16 +1,16 @@
use std::path::Path;
use std::sync::Arc;
use brk_core::{Bitcoin, Close, Dollars, Height, Sats, TxIndex, Version};
use brk_exit::Exit;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_vec::{
AnyCollectableVec, BoxedAnyIterableVec, CloneableAnyIterableVec, CollectableVec, Computation,
ComputedVecFrom3, Format, LazyVecFrom1, StoredIndex, StoredVec,
use brk_structs::{Bitcoin, Close, Dollars, Height, Sats, TxIndex, Version};
use brk_vecs::{
AnyCloneableIterableVec, AnyCollectableVec, CollectableVec, Computation, ComputedVecFrom3,
Exit, File, Format, LazyVecFrom1, StoredIndex, StoredVec,
};
use crate::vecs::{Indexes, fetched, indexes};
use crate::{Indexes, grouped::Source, indexes, price};
use super::{ComputedVecsFromTxindex, StorableVecGeneatorOptions};
use super::{ComputedVecsFromTxindex, VecBuilderOptions};
#[derive(Clone)]
pub struct ComputedValueVecsFromTxindex {
@@ -38,35 +38,38 @@ const VERSION: Version = Version::ZERO;
impl ComputedValueVecsFromTxindex {
#[allow(clippy::too_many_arguments)]
pub fn forced_import(
path: &Path,
file: &Arc<File>,
name: &str,
indexes: &indexes::Vecs,
source: Option<BoxedAnyIterableVec<TxIndex, Sats>>,
source: Source<TxIndex, Sats>,
version: Version,
computation: Computation,
format: Format,
fetched: Option<&fetched::Vecs>,
options: StorableVecGeneatorOptions,
) -> color_eyre::Result<Self> {
let compute_source = source.is_none();
let compute_dollars = fetched.is_some();
price: Option<&price::Vecs>,
options: VecBuilderOptions,
) -> 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 sats = ComputedVecsFromTxindex::forced_import(
path,
file,
name,
compute_source,
source.clone(),
version + VERSION,
format,
computation,
indexes,
options,
)?;
let source_vec = source.vec();
let bitcoin_txindex = LazyVecFrom1::init(
&name_in_btc,
version + VERSION,
source.map_or_else(|| sats.txindex.as_ref().unwrap().boxed_clone(), |s| s),
source_vec.map_or_else(|| sats.txindex.as_ref().unwrap().boxed_clone(), |s| s),
|txindex: TxIndex, iter| {
iter.next_at(txindex.unwrap_to_usize()).map(|(_, value)| {
let sats = value.into_owned();
@@ -76,24 +79,26 @@ impl ComputedValueVecsFromTxindex {
);
let bitcoin = ComputedVecsFromTxindex::forced_import(
path,
file,
&name_in_btc,
false,
Source::None,
version + VERSION,
format,
computation,
indexes,
options,
)?;
let dollars_txindex = fetched.map(|fetched| {
let dollars_txindex = price.map(|price| {
ComputedVecFrom3::forced_import_or_init_from_3(
computation,
path,
file,
&name_in_usd,
version + VERSION,
format,
bitcoin_txindex.boxed_clone(),
indexes.txindex_to_height.boxed_clone(),
fetched.chainindexes_to_close.height.boxed_clone(),
price.chainindexes_to_close.height.boxed_clone(),
|txindex: TxIndex,
txindex_to_btc_iter,
txindex_to_height_iter,
@@ -122,11 +127,13 @@ impl ComputedValueVecsFromTxindex {
dollars_txindex,
dollars: compute_dollars.then(|| {
ComputedVecsFromTxindex::forced_import(
path,
file,
&name_in_usd,
false,
Source::None,
version + VERSION,
format,
computation,
indexes,
options,
)
.unwrap()
@@ -138,11 +145,11 @@ impl ComputedValueVecsFromTxindex {
// &mut self,
// indexer: &Indexer,
// indexes: &indexes::Vecs,
// fetched: Option<&marketprice::Vecs>,
// price: Option<&marketprice::Vecs>,
// starting_indexes: &Indexes,
// exit: &Exit,
// mut compute: F,
// ) -> color_eyre::Result<()>
// ) -> Result<()>
// where
// F: FnMut(
// &mut EagerVec<TxIndex, Sats>,
@@ -180,8 +187,8 @@ impl ComputedValueVecsFromTxindex {
starting_indexes: &Indexes,
exit: &Exit,
txindex: Option<&impl CollectableVec<TxIndex, Sats>>,
fetched: Option<&fetched::Vecs>,
) -> color_eyre::Result<()> {
price: Option<&price::Vecs>,
) -> Result<()> {
if let Some(txindex) = txindex {
self.sats
.compute_rest(indexer, indexes, starting_indexes, exit, Some(txindex))?;
@@ -216,7 +223,7 @@ impl ComputedValueVecsFromTxindex {
exit,
&self.bitcoin,
Some(dollars_txindex),
fetched.as_ref().unwrap(),
price.as_ref().unwrap(),
)?;
}
@@ -1,11 +1,16 @@
use std::path::Path;
use std::sync::Arc;
use brk_core::{Bitcoin, Dollars, Height, Result, Sats, Version};
use brk_exit::Exit;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_vec::{AnyCollectableVec, CollectableVec, EagerVec, Format, StoredVec};
use brk_structs::{Bitcoin, Dollars, Height, Sats, Version};
use brk_vecs::{AnyCollectableVec, CollectableVec, EagerVec, Exit, File, Format, StoredVec};
use crate::vecs::{Indexes, fetched, indexes};
use crate::{
Indexes,
grouped::Source,
indexes, price,
traits::{ComputeFromBitcoin, ComputeFromSats},
};
#[derive(Clone)]
pub struct ComputedHeightValueVecs {
@@ -18,27 +23,27 @@ const VERSION: Version = Version::ZERO;
impl ComputedHeightValueVecs {
pub fn forced_import(
path: &Path,
file: &Arc<File>,
name: &str,
compute_source: bool,
source: Source<Height, Sats>,
version: Version,
format: Format,
compute_dollars: bool,
) -> color_eyre::Result<Self> {
) -> Result<Self> {
Ok(Self {
sats: compute_source.then(|| {
EagerVec::forced_import(path, name, version + VERSION + Version::ZERO, format)
sats: source.is_compute().then(|| {
EagerVec::forced_import(file, name, version + VERSION + Version::ZERO, format)
.unwrap()
}),
bitcoin: EagerVec::forced_import(
path,
file,
&format!("{name}_in_btc"),
version + VERSION + Version::ZERO,
format,
)?,
dollars: compute_dollars.then(|| {
EagerVec::forced_import(
path,
file,
&format!("{name}_in_usd"),
version + VERSION + Version::ZERO,
format,
@@ -52,11 +57,11 @@ impl ComputedHeightValueVecs {
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
fetched: Option<&fetched::Vecs>,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
exit: &Exit,
mut compute: F,
) -> color_eyre::Result<()>
) -> Result<()>
where
F: FnMut(
&mut EagerVec<Height, Sats>,
@@ -75,18 +80,18 @@ impl ComputedHeightValueVecs {
)?;
let height: Option<&StoredVec<Height, Sats>> = None;
self.compute_rest(fetched, starting_indexes, exit, height)?;
self.compute_rest(price, starting_indexes, exit, height)?;
Ok(())
}
pub fn compute_rest(
&mut self,
fetched: Option<&fetched::Vecs>,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
exit: &Exit,
height: Option<&impl CollectableVec<Height, Sats>>,
) -> color_eyre::Result<()> {
) -> Result<()> {
if let Some(height) = height {
self.bitcoin
.compute_from_sats(starting_indexes.height, height, exit)?;
@@ -99,7 +104,7 @@ impl ComputedHeightValueVecs {
}
let height_to_bitcoin = &self.bitcoin;
let height_to_close = &fetched.as_ref().unwrap().chainindexes_to_close.height;
let height_to_close = &price.as_ref().unwrap().chainindexes_to_close.height;
if let Some(dollars) = self.dollars.as_mut() {
dollars.compute_from_bitcoin(
@@ -1,38 +1,38 @@
use std::{ops::Deref, path::Path};
use std::{ops::Deref, path::Path, sync::Arc};
use brk_core::{
use brk_error::Result;
use brk_indexer::Indexer;
use brk_structs::{
Date, DateIndex, DecadeIndex, DifficultyEpoch, EmptyOutputIndex, HalvingEpoch, Height,
InputIndex, MonthIndex, OpReturnIndex, OutputIndex, P2AAddressIndex, P2ABytes, P2MSOutputIndex,
P2PK33AddressIndex, P2PK33Bytes, P2PK65AddressIndex, P2PK65Bytes, P2PKHAddressIndex,
P2PKHBytes, P2SHAddressIndex, P2SHBytes, P2TRAddressIndex, P2TRBytes, P2WPKHAddressIndex,
P2WPKHBytes, P2WSHAddressIndex, P2WSHBytes, QuarterIndex, Sats, StoredUsize, Timestamp,
TxIndex, Txid, UnknownOutputIndex, Version, WeekIndex, YearIndex,
P2WPKHBytes, P2WSHAddressIndex, P2WSHBytes, QuarterIndex, Sats, SemesterIndex, StoredU64,
Timestamp, TxIndex, Txid, UnknownOutputIndex, Version, WeekIndex, YearIndex,
};
use brk_exit::Exit;
use brk_indexer::Indexer;
use brk_vec::{
AnyCollectableVec, CloneableAnyIterableVec, Computation, ComputedVec, ComputedVecFrom1,
ComputedVecFrom2, EagerVec, Format, StoredIndex, VecIterator,
use brk_vecs::{
AnyCloneableIterableVec, AnyCollectableVec, Computation, ComputedVec, ComputedVecFrom1,
ComputedVecFrom2, EagerVec, Exit, File, Format, PAGE_SIZE, StoredIndex, VecIterator,
};
use crate::vecs::indexes;
const VERSION: Version = Version::ZERO;
#[derive(Clone)]
pub struct Vecs {
file: Arc<File>,
pub dateindex_to_date: EagerVec<DateIndex, Date>,
pub dateindex_to_dateindex: EagerVec<DateIndex, DateIndex>,
pub dateindex_to_first_height: EagerVec<DateIndex, Height>,
pub dateindex_to_height_count: EagerVec<DateIndex, StoredUsize>,
pub dateindex_to_height_count: EagerVec<DateIndex, StoredU64>,
pub dateindex_to_monthindex: EagerVec<DateIndex, MonthIndex>,
pub dateindex_to_weekindex: EagerVec<DateIndex, WeekIndex>,
pub decadeindex_to_decadeindex: EagerVec<DecadeIndex, DecadeIndex>,
pub decadeindex_to_first_yearindex: EagerVec<DecadeIndex, YearIndex>,
pub decadeindex_to_yearindex_count: EagerVec<DecadeIndex, StoredUsize>,
pub decadeindex_to_yearindex_count: EagerVec<DecadeIndex, StoredU64>,
pub difficultyepoch_to_difficultyepoch: EagerVec<DifficultyEpoch, DifficultyEpoch>,
pub difficultyepoch_to_first_height: EagerVec<DifficultyEpoch, Height>,
pub difficultyepoch_to_height_count: EagerVec<DifficultyEpoch, StoredUsize>,
pub difficultyepoch_to_height_count: EagerVec<DifficultyEpoch, StoredU64>,
pub emptyoutputindex_to_emptyoutputindex:
ComputedVecFrom1<EmptyOutputIndex, EmptyOutputIndex, EmptyOutputIndex, TxIndex>,
pub halvingepoch_to_first_height: EagerVec<HalvingEpoch, Height>,
@@ -44,12 +44,13 @@ pub struct Vecs {
pub height_to_halvingepoch: EagerVec<Height, HalvingEpoch>,
pub height_to_height: EagerVec<Height, Height>,
pub height_to_timestamp_fixed: EagerVec<Height, Timestamp>,
pub height_to_txindex_count: EagerVec<Height, StoredUsize>,
pub height_to_txindex_count: EagerVec<Height, StoredU64>,
pub inputindex_to_inputindex: ComputedVecFrom1<InputIndex, InputIndex, InputIndex, OutputIndex>,
pub monthindex_to_dateindex_count: EagerVec<MonthIndex, StoredUsize>,
pub monthindex_to_dateindex_count: EagerVec<MonthIndex, StoredU64>,
pub monthindex_to_first_dateindex: EagerVec<MonthIndex, DateIndex>,
pub monthindex_to_monthindex: EagerVec<MonthIndex, MonthIndex>,
pub monthindex_to_quarterindex: EagerVec<MonthIndex, QuarterIndex>,
pub monthindex_to_semesterindex: EagerVec<MonthIndex, SemesterIndex>,
pub monthindex_to_yearindex: EagerVec<MonthIndex, YearIndex>,
pub opreturnindex_to_opreturnindex:
ComputedVecFrom1<OpReturnIndex, OpReturnIndex, OpReturnIndex, TxIndex>,
@@ -74,36 +75,42 @@ pub struct Vecs {
pub p2wshaddressindex_to_p2wshaddressindex:
ComputedVecFrom1<P2WSHAddressIndex, P2WSHAddressIndex, P2WSHAddressIndex, P2WSHBytes>,
pub quarterindex_to_first_monthindex: EagerVec<QuarterIndex, MonthIndex>,
pub quarterindex_to_monthindex_count: EagerVec<QuarterIndex, StoredUsize>,
pub quarterindex_to_monthindex_count: EagerVec<QuarterIndex, StoredU64>,
pub quarterindex_to_quarterindex: EagerVec<QuarterIndex, QuarterIndex>,
pub semesterindex_to_first_monthindex: EagerVec<SemesterIndex, MonthIndex>,
pub semesterindex_to_monthindex_count: EagerVec<SemesterIndex, StoredU64>,
pub semesterindex_to_semesterindex: EagerVec<SemesterIndex, SemesterIndex>,
pub txindex_to_height: EagerVec<TxIndex, Height>,
pub txindex_to_input_count:
ComputedVecFrom2<TxIndex, StoredUsize, TxIndex, InputIndex, InputIndex, OutputIndex>,
ComputedVecFrom2<TxIndex, StoredU64, TxIndex, InputIndex, InputIndex, OutputIndex>,
pub txindex_to_output_count:
ComputedVecFrom2<TxIndex, StoredUsize, TxIndex, OutputIndex, OutputIndex, Sats>,
ComputedVecFrom2<TxIndex, StoredU64, TxIndex, OutputIndex, OutputIndex, Sats>,
pub txindex_to_txindex: ComputedVecFrom1<TxIndex, TxIndex, TxIndex, Txid>,
pub unknownoutputindex_to_unknownoutputindex:
ComputedVecFrom1<UnknownOutputIndex, UnknownOutputIndex, UnknownOutputIndex, TxIndex>,
pub weekindex_to_dateindex_count: EagerVec<WeekIndex, StoredUsize>,
pub weekindex_to_dateindex_count: EagerVec<WeekIndex, StoredU64>,
pub weekindex_to_first_dateindex: EagerVec<WeekIndex, DateIndex>,
pub weekindex_to_weekindex: EagerVec<WeekIndex, WeekIndex>,
pub yearindex_to_decadeindex: EagerVec<YearIndex, DecadeIndex>,
pub yearindex_to_first_monthindex: EagerVec<YearIndex, MonthIndex>,
pub yearindex_to_monthindex_count: EagerVec<YearIndex, StoredUsize>,
pub yearindex_to_monthindex_count: EagerVec<YearIndex, StoredU64>,
pub yearindex_to_yearindex: EagerVec<YearIndex, YearIndex>,
}
impl Vecs {
pub fn forced_import(
path: &Path,
parent: &Path,
version: Version,
indexer: &Indexer,
computation: Computation,
format: Format,
) -> color_eyre::Result<Self> {
) -> Result<Self> {
let file = Arc::new(File::open(&parent.join("indexes"))?);
file.set_min_len(PAGE_SIZE * 10_000_000)?;
let outputindex_to_outputindex = ComputedVec::forced_import_or_init_from_1(
computation,
path,
&file,
"outputindex",
version + VERSION + Version::ZERO,
format,
@@ -113,7 +120,7 @@ impl Vecs {
let inputindex_to_inputindex = ComputedVec::forced_import_or_init_from_1(
computation,
path,
&file,
"inputindex",
version + VERSION + Version::ZERO,
format,
@@ -123,7 +130,7 @@ impl Vecs {
let txindex_to_txindex = ComputedVec::forced_import_or_init_from_1(
computation,
path,
&file,
"txindex",
version + VERSION + Version::ZERO,
format,
@@ -133,7 +140,7 @@ impl Vecs {
let txindex_to_input_count = ComputedVec::forced_import_or_init_from_2(
computation,
path,
&file,
"input_count",
version + VERSION + Version::ZERO,
format,
@@ -149,14 +156,14 @@ impl Vecs {
.next_at(txindex + 1)
.map(|(_, v)| usize::from(v.into_owned()))
.unwrap_or_else(|| inputindex_to_outputindex_iter.len());
StoredUsize::from((start..end).count())
StoredU64::from((start..end).count())
})
},
)?;
let txindex_to_output_count = ComputedVec::forced_import_or_init_from_2(
computation,
path,
&file,
"output_count",
version + VERSION + Version::ZERO,
format,
@@ -172,14 +179,14 @@ impl Vecs {
.next_at(txindex + 1)
.map(|(_, v)| usize::from(v.into_owned()))
.unwrap_or_else(|| outputindex_to_value_iter.len());
StoredUsize::from((start..end).count())
StoredU64::from((start..end).count())
})
},
)?;
let p2pk33addressindex_to_p2pk33addressindex = ComputedVec::forced_import_or_init_from_1(
computation,
path,
&file,
"p2pk33addressindex",
version + VERSION + Version::ZERO,
format,
@@ -188,7 +195,7 @@ impl Vecs {
)?;
let p2pk65addressindex_to_p2pk65addressindex = ComputedVec::forced_import_or_init_from_1(
computation,
path,
&file,
"p2pk65addressindex",
version + VERSION + Version::ZERO,
format,
@@ -197,7 +204,7 @@ impl Vecs {
)?;
let p2pkhaddressindex_to_p2pkhaddressindex = ComputedVec::forced_import_or_init_from_1(
computation,
path,
&file,
"p2pkhaddressindex",
version + VERSION + Version::ZERO,
format,
@@ -206,7 +213,7 @@ impl Vecs {
)?;
let p2shaddressindex_to_p2shaddressindex = ComputedVec::forced_import_or_init_from_1(
computation,
path,
&file,
"p2shaddressindex",
version + VERSION + Version::ZERO,
format,
@@ -215,7 +222,7 @@ impl Vecs {
)?;
let p2traddressindex_to_p2traddressindex = ComputedVec::forced_import_or_init_from_1(
computation,
path,
&file,
"p2traddressindex",
version + VERSION + Version::ZERO,
format,
@@ -224,7 +231,7 @@ impl Vecs {
)?;
let p2wpkhaddressindex_to_p2wpkhaddressindex = ComputedVec::forced_import_or_init_from_1(
computation,
path,
&file,
"p2wpkhaddressindex",
version + VERSION + Version::ZERO,
format,
@@ -233,7 +240,7 @@ impl Vecs {
)?;
let p2wshaddressindex_to_p2wshaddressindex = ComputedVec::forced_import_or_init_from_1(
computation,
path,
&file,
"p2wshaddressindex",
version + VERSION + Version::ZERO,
format,
@@ -242,7 +249,7 @@ impl Vecs {
)?;
let p2aaddressindex_to_p2aaddressindex = ComputedVec::forced_import_or_init_from_1(
computation,
path,
&file,
"p2aaddressindex",
version + VERSION + Version::ZERO,
format,
@@ -251,7 +258,7 @@ impl Vecs {
)?;
let p2msoutputindex_to_p2msoutputindex = ComputedVec::forced_import_or_init_from_1(
computation,
path,
&file,
"p2msoutputindex",
version + VERSION + Version::ZERO,
format,
@@ -260,7 +267,7 @@ impl Vecs {
)?;
let emptyoutputindex_to_emptyoutputindex = ComputedVec::forced_import_or_init_from_1(
computation,
path,
&file,
"emptyoutputindex",
version + VERSION + Version::ZERO,
format,
@@ -269,7 +276,7 @@ impl Vecs {
)?;
let unknownoutputindex_to_unknownoutputindex = ComputedVec::forced_import_or_init_from_1(
computation,
path,
&file,
"unknownoutputindex",
version + VERSION + Version::ZERO,
format,
@@ -278,7 +285,7 @@ impl Vecs {
)?;
let opreturnindex_to_opreturnindex = ComputedVec::forced_import_or_init_from_1(
computation,
path,
&file,
"opreturnindex",
version + VERSION + Version::ZERO,
format,
@@ -306,239 +313,265 @@ impl Vecs {
unknownoutputindex_to_unknownoutputindex,
dateindex_to_date: EagerVec::forced_import(
path,
&file,
"date",
version + VERSION + Version::ZERO,
format,
)?,
dateindex_to_dateindex: EagerVec::forced_import(
path,
&file,
"dateindex",
version + VERSION + Version::ZERO,
format,
)?,
dateindex_to_first_height: EagerVec::forced_import(
path,
&file,
"first_height",
version + VERSION + Version::ZERO,
format,
)?,
dateindex_to_monthindex: EagerVec::forced_import(
path,
&file,
"monthindex",
version + VERSION + Version::ZERO,
format,
)?,
dateindex_to_weekindex: EagerVec::forced_import(
path,
&file,
"weekindex",
version + VERSION + Version::ZERO,
format,
)?,
decadeindex_to_decadeindex: EagerVec::forced_import(
path,
&file,
"decadeindex",
version + VERSION + Version::ZERO,
format,
)?,
decadeindex_to_first_yearindex: EagerVec::forced_import(
path,
&file,
"first_yearindex",
version + VERSION + Version::ZERO,
format,
)?,
difficultyepoch_to_difficultyepoch: EagerVec::forced_import(
path,
&file,
"difficultyepoch",
version + VERSION + Version::ZERO,
format,
)?,
difficultyepoch_to_first_height: EagerVec::forced_import(
path,
&file,
"first_height",
version + VERSION + Version::ZERO,
format,
)?,
halvingepoch_to_first_height: EagerVec::forced_import(
path,
&file,
"first_height",
version + VERSION + Version::ZERO,
format,
)?,
halvingepoch_to_halvingepoch: EagerVec::forced_import(
path,
&file,
"halvingepoch",
version + VERSION + Version::ZERO,
format,
)?,
height_to_date: EagerVec::forced_import(
path,
&file,
"date",
version + VERSION + Version::ZERO,
format,
)?,
height_to_difficultyepoch: EagerVec::forced_import(
path,
&file,
"difficultyepoch",
version + VERSION + Version::ZERO,
format,
)?,
height_to_halvingepoch: EagerVec::forced_import(
path,
&file,
"halvingepoch",
version + VERSION + Version::ZERO,
format,
)?,
height_to_height: EagerVec::forced_import(
path,
&file,
"height",
version + VERSION + Version::ZERO,
format,
)?,
monthindex_to_first_dateindex: EagerVec::forced_import(
path,
&file,
"first_dateindex",
version + VERSION + Version::ZERO,
format,
)?,
monthindex_to_monthindex: EagerVec::forced_import(
path,
&file,
"monthindex",
version + VERSION + Version::ZERO,
format,
)?,
monthindex_to_quarterindex: EagerVec::forced_import(
path,
&file,
"quarterindex",
version + VERSION + Version::ZERO,
format,
)?,
monthindex_to_semesterindex: EagerVec::forced_import(
&file,
"semesterindex",
version + VERSION + Version::ZERO,
format,
)?,
monthindex_to_yearindex: EagerVec::forced_import(
path,
&file,
"yearindex",
version + VERSION + Version::ZERO,
format,
)?,
quarterindex_to_first_monthindex: EagerVec::forced_import(
path,
&file,
"first_monthindex",
version + VERSION + Version::ZERO,
format,
)?,
semesterindex_to_first_monthindex: EagerVec::forced_import(
&file,
"first_monthindex",
version + VERSION + Version::ZERO,
format,
)?,
weekindex_to_first_dateindex: EagerVec::forced_import(
path,
&file,
"first_dateindex",
version + VERSION + Version::ZERO,
format,
)?,
yearindex_to_first_monthindex: EagerVec::forced_import(
path,
&file,
"first_monthindex",
version + VERSION + Version::ZERO,
format,
)?,
quarterindex_to_quarterindex: EagerVec::forced_import(
path,
&file,
"quarterindex",
version + VERSION + Version::ZERO,
format,
)?,
semesterindex_to_semesterindex: EagerVec::forced_import(
&file,
"semesterindex",
version + VERSION + Version::ZERO,
format,
)?,
weekindex_to_weekindex: EagerVec::forced_import(
path,
&file,
"weekindex",
version + VERSION + Version::ZERO,
format,
)?,
yearindex_to_decadeindex: EagerVec::forced_import(
path,
&file,
"decadeindex",
version + VERSION + Version::ZERO,
format,
)?,
yearindex_to_yearindex: EagerVec::forced_import(
path,
&file,
"yearindex",
version + VERSION + Version::ZERO,
format,
)?,
height_to_date_fixed: EagerVec::forced_import(
path,
&file,
"date_fixed",
version + VERSION + Version::ZERO,
format,
)?,
height_to_dateindex: EagerVec::forced_import(
path,
&file,
"dateindex",
version + VERSION + Version::ZERO,
format,
)?,
txindex_to_height: EagerVec::forced_import(
path,
&file,
"height",
version + VERSION + Version::ZERO,
format,
)?,
height_to_timestamp_fixed: EagerVec::forced_import(
path,
&file,
"timestamp_fixed",
version + VERSION + Version::ZERO,
format,
)?,
height_to_txindex_count: EagerVec::forced_import(
path,
&file,
"txindex_count",
version + VERSION + Version::ZERO,
format,
)?,
dateindex_to_height_count: EagerVec::forced_import(
path,
&file,
"height_count",
version + VERSION + Version::ZERO,
format,
)?,
weekindex_to_dateindex_count: EagerVec::forced_import(
path,
&file,
"dateindex_count",
version + VERSION + Version::ZERO,
format,
)?,
difficultyepoch_to_height_count: EagerVec::forced_import(
path,
&file,
"height_count",
version + VERSION + Version::ZERO,
format,
)?,
monthindex_to_dateindex_count: EagerVec::forced_import(
path,
&file,
"dateindex_count",
version + VERSION + Version::ZERO,
format,
)?,
quarterindex_to_monthindex_count: EagerVec::forced_import(
path,
&file,
"monthindex_count",
version + VERSION + Version::ZERO,
format,
)?,
semesterindex_to_monthindex_count: EagerVec::forced_import(
&file,
"monthindex_count",
version + VERSION + Version::ZERO,
format,
)?,
yearindex_to_monthindex_count: EagerVec::forced_import(
path,
&file,
"monthindex_count",
version + VERSION + Version::ZERO,
format,
)?,
decadeindex_to_yearindex_count: EagerVec::forced_import(
path,
&file,
"yearindex_count",
version + VERSION + Version::ZERO,
format,
)?,
outputindex_to_txindex: EagerVec::forced_import(
path,
&file,
"txindex",
version + VERSION + Version::ZERO,
format,
)?,
file,
})
}
@@ -547,7 +580,18 @@ impl Vecs {
indexer: &Indexer,
starting_indexes: brk_indexer::Indexes,
exit: &Exit,
) -> color_eyre::Result<Indexes> {
) -> Result<Indexes> {
let idxs = self.compute_(indexer, starting_indexes, exit)?;
self.file.flush_then_punch()?;
Ok(idxs)
}
fn compute_(
&mut self,
indexer: &Indexer,
starting_indexes: brk_indexer::Indexes,
exit: &Exit,
) -> Result<Indexes> {
// ---
// OutputIndex
// ---
@@ -716,14 +760,14 @@ impl Vecs {
starting_indexes.height,
&indexer.vecs.height_to_timestamp,
|(h, timestamp, height_to_timestamp_fixed_iter)| {
if prev_timestamp_fixed.is_none() {
if let Some(prev_h) = h.decremented() {
prev_timestamp_fixed.replace(
height_to_timestamp_fixed_iter
.into_iter()
.unwrap_get_inner(prev_h),
);
}
if prev_timestamp_fixed.is_none()
&& let Some(prev_h) = h.decremented()
{
prev_timestamp_fixed.replace(
height_to_timestamp_fixed_iter
.into_iter()
.unwrap_get_inner(prev_h),
);
}
let timestamp_fixed =
prev_timestamp_fixed.map_or(timestamp, |prev_d| prev_d.max(timestamp));
@@ -943,6 +987,45 @@ impl Vecs {
exit,
)?;
// ---
// SemesterIndex
// ---
let starting_semesterindex = self
.monthindex_to_semesterindex
.into_iter()
.get_inner(starting_monthindex)
.unwrap_or_default();
self.monthindex_to_semesterindex.compute_from_index(
starting_monthindex,
&self.monthindex_to_first_dateindex,
exit,
)?;
self.semesterindex_to_first_monthindex
.compute_inverse_more_to_less(
starting_monthindex,
&self.monthindex_to_semesterindex,
exit,
)?;
// let semester_count = self.semesterindex_to_first_monthindex.len();
self.semesterindex_to_semesterindex.compute_from_index(
starting_semesterindex,
&self.semesterindex_to_first_monthindex,
exit,
)?;
self.semesterindex_to_monthindex_count
.compute_count_from_indexes(
starting_semesterindex,
&self.semesterindex_to_first_monthindex,
&self.monthindex_to_monthindex,
exit,
)?;
// ---
// YearIndex
// ---
@@ -1051,6 +1134,7 @@ impl Vecs {
weekindex: starting_weekindex,
monthindex: starting_monthindex,
quarterindex: starting_quarterindex,
semesterindex: starting_semesterindex,
yearindex: starting_yearindex,
decadeindex: starting_decadeindex,
difficultyepoch: starting_difficultyepoch,
@@ -1088,6 +1172,7 @@ impl Vecs {
&self.monthindex_to_first_dateindex,
&self.monthindex_to_monthindex,
&self.monthindex_to_quarterindex,
&self.monthindex_to_semesterindex,
&self.monthindex_to_yearindex,
&self.opreturnindex_to_opreturnindex,
&self.outputindex_to_outputindex,
@@ -1103,6 +1188,9 @@ impl Vecs {
&self.quarterindex_to_first_monthindex,
&self.quarterindex_to_monthindex_count,
&self.quarterindex_to_quarterindex,
&self.semesterindex_to_first_monthindex,
&self.semesterindex_to_monthindex_count,
&self.semesterindex_to_semesterindex,
&self.txindex_to_height,
&self.txindex_to_txindex,
&self.txindex_to_input_count,
@@ -1126,6 +1214,7 @@ pub struct Indexes {
pub weekindex: WeekIndex,
pub monthindex: MonthIndex,
pub quarterindex: QuarterIndex,
pub semesterindex: SemesterIndex,
pub yearindex: YearIndex,
pub decadeindex: DecadeIndex,
pub difficultyepoch: DifficultyEpoch,
@@ -1133,7 +1222,7 @@ pub struct Indexes {
}
impl Indexes {
pub fn update_from_height(&mut self, height: Height, indexes: &indexes::Vecs) {
pub fn update_from_height(&mut self, height: Height, indexes: &Vecs) {
self.indexes.height = height;
self.dateindex = DateIndex::try_from(
indexes
@@ -1145,6 +1234,7 @@ impl Indexes {
self.weekindex = WeekIndex::from(self.dateindex);
self.monthindex = MonthIndex::from(self.dateindex);
self.quarterindex = QuarterIndex::from(self.monthindex);
self.semesterindex = SemesterIndex::from(self.monthindex);
self.yearindex = YearIndex::from(self.monthindex);
self.decadeindex = DecadeIndex::from(self.dateindex);
self.difficultyepoch = DifficultyEpoch::from(self.height);
+205 -37
View File
@@ -1,31 +1,48 @@
#![doc = include_str!("../README.md")]
#![doc = "\n## Example\n\n```rust"]
#![doc = include_str!("../examples/main.rs")]
#![doc = include_str!("../examples/computer.rs")]
#![doc = "```"]
use std::path::Path;
use brk_core::Version;
use brk_exit::Exit;
use brk_error::Result;
use brk_fetcher::Fetcher;
use brk_indexer::Indexer;
use brk_vec::{Computation, Format};
use brk_structs::Version;
use brk_vecs::{AnyCollectableVec, Computation, Exit, Format};
use log::info;
mod blocks;
mod cointime;
mod constants;
mod fetched;
mod grouped;
mod indexes;
mod market;
mod mining;
mod price;
mod stateful;
mod states;
mod stores;
mod traits;
mod transactions;
mod utils;
mod vecs;
use indexes::Indexes;
use states::*;
use stores::Stores;
use vecs::Vecs;
#[derive(Clone)]
pub struct Computer {
fetcher: Option<Fetcher>,
pub vecs: Vecs,
pub stores: Stores,
pub indexes: indexes::Vecs,
pub constants: constants::Vecs,
pub blocks: blocks::Vecs,
pub mining: mining::Vecs,
pub market: market::Vecs,
pub price: Option<price::Vecs>,
pub transactions: transactions::Vecs,
pub stateful: stateful::Vecs,
pub fetched: Option<fetched::Vecs>,
pub cointime: cointime::Vecs,
}
const VERSION: Version = Version::ONE;
@@ -33,47 +50,198 @@ const VERSION: Version = Version::ONE;
impl Computer {
/// Do NOT import multiple times or things will break !!!
pub fn forced_import(
outputs_dir: &Path,
outputs_path: &Path,
indexer: &Indexer,
computation: Computation,
fetcher: Option<Fetcher>,
format: Format,
) -> color_eyre::Result<Self> {
Ok(Self {
vecs: Vecs::import(
// TODO: Give self.path, join inside import
&outputs_dir.join("vecs/computed"),
) -> Result<Self> {
let computed_path = outputs_path.join("computed");
let computation = Computation::Lazy;
let format = Format::Compressed;
let indexes = indexes::Vecs::forced_import(
&computed_path,
VERSION + Version::ZERO,
indexer,
computation,
format,
)?;
let fetched = fetcher.map(|fetcher| {
fetched::Vecs::forced_import(outputs_path, fetcher, VERSION + Version::ZERO).unwrap()
});
let price = fetched.is_some().then(|| {
price::Vecs::forced_import(
&computed_path,
VERSION + Version::ZERO,
indexer,
fetcher.is_some(),
computation,
format,
)?,
stores: Stores::import(
// TODO: Give self.path, join inside import
&outputs_dir.join("stores"),
&indexes,
)
.unwrap()
});
Ok(Self {
blocks: blocks::Vecs::forced_import(
&computed_path,
VERSION + Version::ZERO,
&indexer.stores.keyspace,
computation,
format,
&indexes,
)?,
fetcher,
mining: mining::Vecs::forced_import(
&computed_path,
VERSION + Version::ZERO,
computation,
format,
&indexes,
)?,
constants: constants::Vecs::forced_import(
&computed_path,
VERSION + Version::ZERO,
computation,
format,
&indexes,
)?,
market: market::Vecs::forced_import(
&computed_path,
VERSION + Version::ZERO,
computation,
format,
&indexes,
)?,
stateful: stateful::Vecs::forced_import(
&computed_path,
VERSION + Version::ZERO,
computation,
format,
&indexes,
price.as_ref(),
&computed_path.join("states"),
)?,
transactions: transactions::Vecs::forced_import(
&computed_path,
VERSION + Version::ZERO,
indexer,
&indexes,
computation,
format,
price.as_ref(),
)?,
cointime: cointime::Vecs::forced_import(
&computed_path,
VERSION + Version::ZERO,
computation,
format,
&indexes,
price.as_ref(),
)?,
indexes,
fetched,
price,
})
}
}
impl Computer {
pub fn compute(
&mut self,
indexer: &mut Indexer,
indexer: &Indexer,
starting_indexes: brk_indexer::Indexes,
exit: &Exit,
) -> color_eyre::Result<()> {
info!("Computing...");
self.vecs.compute(
) -> Result<()> {
info!("Computing indexes...");
let mut starting_indexes = self.indexes.compute(indexer, starting_indexes, exit)?;
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)?;
if let Some(fetched) = self.fetched.as_mut() {
info!("Computing fetched...");
fetched.compute(indexer, &self.indexes, &starting_indexes, exit)?;
info!("Computing prices...");
self.price.as_mut().unwrap().compute(
indexer,
&self.indexes,
&starting_indexes,
fetched,
exit,
)?;
}
info!("Computing transactions...");
self.transactions.compute(
indexer,
starting_indexes,
self.fetcher.as_mut(),
&self.indexes,
&starting_indexes,
self.price.as_ref(),
exit,
&mut self.stores,
)
)?;
if let Some(price) = self.price.as_ref() {
info!("Computing market...");
self.market.compute(
indexer,
&self.indexes,
price,
&mut self.transactions,
&starting_indexes,
exit,
)?;
}
info!("Computing stateful...");
self.stateful.compute(
indexer,
&self.indexes,
&self.transactions,
self.price.as_ref(),
&self.market,
&mut starting_indexes,
exit,
)?;
self.cointime.compute(
indexer,
&self.indexes,
&starting_indexes,
self.price.as_ref(),
&self.transactions,
&self.stateful,
exit,
)?;
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 static_clone(&self) -> &'static Self {
Box::leak(Box::new(self.clone()))
}
}
File diff suppressed because it is too large Load Diff
@@ -1,13 +1,15 @@
use std::path::Path;
use std::{path::Path, sync::Arc};
use brk_core::{DifficultyEpoch, HalvingEpoch, StoredF64, Version};
use brk_exit::Exit;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_vec::{AnyCollectableVec, Computation, Format, VecIterator};
use brk_structs::{DifficultyEpoch, HalvingEpoch, StoredF64, Version};
use brk_vecs::{AnyCollectableVec, Computation, Exit, File, Format, PAGE_SIZE, VecIterator};
use crate::grouped::Source;
use super::{
Indexes,
grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, StorableVecGeneatorOptions},
grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, VecBuilderOptions},
indexes,
};
@@ -15,6 +17,8 @@ const VERSION: Version = Version::ZERO;
#[derive(Clone)]
pub struct Vecs {
file: Arc<File>,
pub indexes_to_difficulty: ComputedVecsFromHeight<StoredF64>,
pub indexes_to_difficultyepoch: ComputedVecsFromDateIndex<DifficultyEpoch>,
pub indexes_to_halvingepoch: ComputedVecsFromDateIndex<HalvingEpoch>,
@@ -22,36 +26,48 @@ pub struct Vecs {
impl Vecs {
pub fn forced_import(
path: &Path,
parent: &Path,
version: Version,
_computation: Computation,
computation: Computation,
format: Format,
) -> color_eyre::Result<Self> {
indexes: &indexes::Vecs,
) -> Result<Self> {
let file = Arc::new(File::open(&parent.join("mining"))?);
file.set_min_len(PAGE_SIZE * 1_000_000)?;
Ok(Self {
indexes_to_difficulty: ComputedVecsFromHeight::forced_import(
path,
&file,
"difficulty",
false,
Source::None,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_difficultyepoch: ComputedVecsFromDateIndex::forced_import(
path,
&file,
"difficultyepoch",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
indexes,
VecBuilderOptions::default().add_last(),
)?,
indexes_to_halvingepoch: ComputedVecsFromDateIndex::forced_import(
path,
&file,
"halvingepoch",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
indexes,
VecBuilderOptions::default().add_last(),
)?,
file,
})
}
@@ -61,7 +77,19 @@ impl Vecs {
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> color_eyre::Result<()> {
) -> Result<()> {
self.compute_(indexer, indexes, starting_indexes, exit)?;
self.file.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,
@@ -82,7 +110,8 @@ impl Vecs {
)
},
exit,
)
)?;
Ok(())
},
)?;
@@ -106,7 +135,8 @@ impl Vecs {
)
},
exit,
)
)?;
Ok(())
},
)?;
File diff suppressed because it is too large Load Diff
@@ -1,23 +1,22 @@
use std::{ops::Deref, path::Path};
use std::{ops::Deref, path::Path, sync::Arc};
use brk_core::{Bitcoin, DateIndex, Dollars, Height, Result, StoredUsize, Version};
use brk_exit::Exit;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_vec::{
AnyCollectableVec, AnyIterableVec, AnyVec, Computation, EagerVec, Format, VecIterator,
use brk_structs::{Bitcoin, DateIndex, Dollars, Height, StoredU64, Version};
use brk_vecs::{
AnyCollectableVec, AnyIterableVec, AnyStoredVec, AnyVec, Computation, EagerVec, Exit, File,
Format, GenericStoredVec, VecIterator,
};
use crate::{
states::AddressCohortState,
vecs::{
Indexes, fetched,
grouped::{ComputedVecsFromHeight, StorableVecGeneatorOptions},
indexes, market,
stateful::{
common,
r#trait::{CohortVecs, DynCohortVecs},
},
Indexes,
grouped::{ComputedVecsFromHeight, Source, VecBuilderOptions},
indexes, market, price,
stateful::{
common,
r#trait::{CohortVecs, DynCohortVecs},
},
states::AddressCohortState,
};
const VERSION: Version = Version::ZERO;
@@ -30,23 +29,24 @@ pub struct Vecs {
pub inner: common::Vecs,
pub height_to_address_count: EagerVec<Height, StoredUsize>,
pub indexes_to_address_count: ComputedVecsFromHeight<StoredUsize>,
pub height_to_address_count: EagerVec<Height, StoredU64>,
pub indexes_to_address_count: ComputedVecsFromHeight<StoredU64>,
}
impl Vecs {
#[allow(clippy::too_many_arguments)]
pub fn forced_import(
path: &Path,
file: &Arc<File>,
cohort_name: Option<&str>,
computation: Computation,
format: Format,
version: Version,
fetched: Option<&fetched::Vecs>,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
states_path: &Path,
compute_relative_to_all: bool,
) -> color_eyre::Result<Self> {
let compute_dollars = fetched.is_some();
) -> Result<Self> {
let compute_dollars = price.is_some();
let suffix = |s: &str| cohort_name.map_or(s.to_string(), |name| format!("{name}_{s}"));
@@ -58,27 +58,31 @@ impl Vecs {
compute_dollars,
)?,
height_to_address_count: EagerVec::forced_import(
path,
file,
&suffix("address_count"),
version + VERSION + Version::ZERO,
format,
)?,
indexes_to_address_count: ComputedVecsFromHeight::forced_import(
path,
file,
&suffix("address_count"),
false,
Source::None,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
indexes,
VecBuilderOptions::default().add_last(),
)?,
inner: common::Vecs::forced_import(
path,
file,
cohort_name,
computation,
format,
version,
fetched,
indexes,
price,
compute_relative_to_all,
false,
)?,
})
}
@@ -167,10 +171,10 @@ impl DynCohortVecs for Vecs {
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
fetched: Option<&fetched::Vecs>,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
exit: &Exit,
) -> color_eyre::Result<()> {
) -> Result<()> {
self.indexes_to_address_count.compute_rest(
indexes,
starting_indexes,
@@ -179,7 +183,7 @@ impl DynCohortVecs for Vecs {
)?;
self.inner
.compute_rest_part1(indexer, indexes, fetched, starting_indexes, exit)
.compute_rest_part1(indexer, indexes, price, starting_indexes, exit)
}
fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
@@ -220,7 +224,7 @@ impl CohortVecs for Vecs {
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
fetched: Option<&fetched::Vecs>,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
market: &market::Vecs,
height_to_supply: &impl AnyIterableVec<Height, Bitcoin>,
@@ -228,11 +232,11 @@ impl CohortVecs for Vecs {
height_to_realized_cap: Option<&impl AnyIterableVec<Height, Dollars>>,
dateindex_to_realized_cap: Option<&impl AnyIterableVec<DateIndex, Dollars>>,
exit: &Exit,
) -> color_eyre::Result<()> {
) -> Result<()> {
self.inner.compute_rest_part2(
indexer,
indexes,
fetched,
price,
starting_indexes,
market,
height_to_supply,
@@ -1,16 +1,16 @@
use std::path::Path;
use std::{path::Path, sync::Arc};
use brk_core::{
AddressGroups, ByAmountRange, ByGreatEqualAmount, ByLowerThanAmount, GroupFilter, Height,
Result, Version,
use brk_error::Result;
use brk_indexer::Indexer;
use brk_structs::{
AddressGroups, Bitcoin, ByAmountRange, ByGreatEqualAmount, ByLowerThanAmount, DateIndex,
Dollars, GroupFilter, Height, Version,
};
use brk_exit::Exit;
use brk_vec::{Computation, Format};
use brk_vecs::{AnyIterableVec, Computation, Exit, File, Format};
use derive_deref::{Deref, DerefMut};
use rayon::prelude::*;
use crate::vecs::{
Indexes, fetched,
use crate::{
Indexes, indexes, market, price,
stateful::{
address_cohort,
r#trait::{CohortVecs, DynCohortVecs},
@@ -24,427 +24,469 @@ pub struct Vecs(AddressGroups<(GroupFilter, address_cohort::Vecs)>);
impl Vecs {
pub fn forced_import(
path: &Path,
file: &Arc<File>,
version: Version,
_computation: Computation,
format: Format,
fetched: Option<&fetched::Vecs>,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
states_path: &Path,
) -> color_eyre::Result<Self> {
) -> Result<Self> {
Ok(Self(
AddressGroups {
amount_range: ByAmountRange {
_0sats: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_with_0sats"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_1sat_to_10sats: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_1sat_under_10sats"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_10sats_to_100sats: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_10sats_under_100sats"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_100sats_to_1k_sats: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_100sats_under_1k_sats"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_1k_sats_to_10k_sats: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_1k_sats_under_10k_sats"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_10k_sats_to_100k_sats: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_10k_sats_under_100k_sats"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_100k_sats_to_1m_sats: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_100k_sats_under_1m_sats"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_1m_sats_to_10m_sats: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_1m_sats_under_10m_sats"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_10m_sats_to_1btc: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_10m_sats_under_1btc"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_1btc_to_10btc: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_1btc_under_10btc"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_10btc_to_100btc: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_10btc_under_100btc"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_100btc_to_1k_btc: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_100btc_under_1k_btc"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_1k_btc_to_10k_btc: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_1k_btc_under_10k_btc"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_10k_btc_to_100k_btc: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_10k_btc_under_100k_btc"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_100k_btc_or_more: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_100k_btc"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
},
lt_amount: ByLowerThanAmount {
_10sats: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_under_10sats"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_100sats: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_under_100sats"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_1k_sats: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_under_1k_sats"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_10k_sats: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_under_10k_sats"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_100k_sats: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_under_100k_sats"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_1m_sats: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_under_1m_sats"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_10m_sats: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_under_10m_sats"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_1btc: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_under_1btc"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_10btc: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_under_10btc"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_100btc: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_under_100btc"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_1k_btc: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_under_1k_btc"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_10k_btc: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_under_10k_btc"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_100k_btc: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_under_100k_btc"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
},
ge_amount: ByGreatEqualAmount {
_1sat: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_1sat"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_10sats: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_10sats"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_100sats: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_100sats"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_1k_sats: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_1k_sats"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_10k_sats: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_10k_sats"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_100k_sats: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_100k_sats"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_1m_sats: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_1m_sats"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_10m_sats: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_10m_sats"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_1btc: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_1btc"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_10btc: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_10btc"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_100btc: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_100btc"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_1k_btc: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_1k_btc"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
_10k_btc: address_cohort::Vecs::forced_import(
path,
file,
Some("addrs_above_10k_btc"),
_computation,
format,
version + VERSION + Version::ZERO,
fetched,
indexes,
price,
states_path,
true,
)?,
@@ -493,16 +535,61 @@ impl Vecs {
})
.collect::<Vec<_>>(),
]
.into_par_iter()
.into_iter()
.flatten()
.try_for_each(|(vecs, stateful)| {
vecs.compute_from_stateful(starting_indexes, &stateful, exit)
})
}
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)
})
}
#[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_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,
)
})
})
}
pub fn safe_flush_stateful_vecs(&mut self, height: Height, exit: &Exit) -> Result<()> {
self.as_mut_separate_vecs()
.par_iter_mut()
.into_iter()
.try_for_each(|(_, v)| v.safe_flush_stateful_vecs(height, exit))
}
}
@@ -1,11 +1,11 @@
use brk_core::{ByAddressType, Height};
use brk_vec::VecIterator;
use brk_structs::{ByAddressType, Height};
use brk_vecs::VecIterator;
use derive_deref::{Deref, DerefMut};
use crate::vecs::stateful::addresstype_to_height_to_addresscount::AddressTypeToHeightToAddressCount;
use crate::stateful::addresstype_to_height_to_addresscount::AddressTypeToHeightToAddressCount;
#[derive(Debug, Default, Deref, DerefMut)]
pub struct AddressTypeToAddressCount(ByAddressType<usize>);
pub struct AddressTypeToAddressCount(ByAddressType<u64>);
impl From<(&AddressTypeToHeightToAddressCount, Height)> for AddressTypeToAddressCount {
fn from((groups, starting_height): (&AddressTypeToHeightToAddressCount, Height)) -> Self {
@@ -1,15 +1,15 @@
use brk_core::{ByAddressType, Height, Result, StoredUsize};
use brk_exit::Exit;
use brk_vec::EagerVec;
use brk_error::Result;
use brk_structs::{ByAddressType, Height, StoredU64};
use brk_vecs::{EagerVec, Exit, GenericStoredVec};
use derive_deref::{Deref, DerefMut};
use crate::vecs::stateful::addresstype_to_addresscount::AddressTypeToAddressCount;
use crate::stateful::addresstype_to_addresscount::AddressTypeToAddressCount;
#[derive(Debug, Clone, Deref, DerefMut)]
pub struct AddressTypeToHeightToAddressCount(ByAddressType<EagerVec<Height, StoredUsize>>);
pub struct AddressTypeToHeightToAddressCount(ByAddressType<EagerVec<Height, StoredU64>>);
impl From<ByAddressType<EagerVec<Height, StoredUsize>>> for AddressTypeToHeightToAddressCount {
fn from(value: ByAddressType<EagerVec<Height, StoredUsize>>) -> Self {
impl From<ByAddressType<EagerVec<Height, StoredU64>>> for AddressTypeToHeightToAddressCount {
fn from(value: ByAddressType<EagerVec<Height, StoredU64>>) -> Self {
Self(value)
}
}
@@ -1,20 +1,18 @@
use brk_core::{ByAddressType, StoredUsize};
use brk_exit::Exit;
use brk_vec::AnyCollectableVec;
use brk_error::Result;
use brk_structs::{ByAddressType, StoredU64};
use brk_vecs::{AnyCollectableVec, Exit};
use derive_deref::{Deref, DerefMut};
use crate::vecs::{
use crate::{
Indexes, grouped::ComputedVecsFromHeight, indexes,
stateful::addresstype_to_height_to_addresscount::AddressTypeToHeightToAddressCount,
};
#[derive(Clone, Deref, DerefMut)]
pub struct AddressTypeToIndexesToAddressCount(ByAddressType<ComputedVecsFromHeight<StoredUsize>>);
pub struct AddressTypeToIndexesToAddressCount(ByAddressType<ComputedVecsFromHeight<StoredU64>>);
impl From<ByAddressType<ComputedVecsFromHeight<StoredUsize>>>
for AddressTypeToIndexesToAddressCount
{
fn from(value: ByAddressType<ComputedVecsFromHeight<StoredUsize>>) -> Self {
impl From<ByAddressType<ComputedVecsFromHeight<StoredU64>>> for AddressTypeToIndexesToAddressCount {
fn from(value: ByAddressType<ComputedVecsFromHeight<StoredU64>>) -> Self {
Self(value)
}
}
@@ -27,7 +25,7 @@ impl AddressTypeToIndexesToAddressCount {
starting_indexes: &Indexes,
exit: &Exit,
addresstype_to_height_to_addresscount: &AddressTypeToHeightToAddressCount,
) -> color_eyre::Result<()> {
) -> Result<()> {
self.p2pk65.compute_rest(
indexes,
starting_indexes,
@@ -1,6 +1,6 @@
use std::{collections::BTreeMap, mem};
use brk_core::TypeIndex;
use brk_structs::TypeIndex;
use derive_deref::{Deref, DerefMut};
use super::ByAddressType;
@@ -9,7 +9,7 @@ use super::ByAddressType;
pub struct AddressTypeToTypeIndexTree<T>(ByAddressType<BTreeMap<TypeIndex, T>>);
impl<T> AddressTypeToTypeIndexTree<T> {
pub fn merge(&mut self, mut other: Self) {
pub fn merge(mut self, mut other: Self) -> Self {
Self::merge_(&mut self.p2pk65, &mut other.p2pk65);
Self::merge_(&mut self.p2pk33, &mut other.p2pk33);
Self::merge_(&mut self.p2pkh, &mut other.p2pkh);
@@ -18,6 +18,7 @@ impl<T> AddressTypeToTypeIndexTree<T> {
Self::merge_(&mut self.p2wsh, &mut other.p2wsh);
Self::merge_(&mut self.p2tr, &mut other.p2tr);
Self::merge_(&mut self.p2a, &mut other.p2a);
self
}
fn merge_(own: &mut BTreeMap<TypeIndex, T>, other: &mut BTreeMap<TypeIndex, T>) {
@@ -28,10 +29,6 @@ impl<T> AddressTypeToTypeIndexTree<T> {
mem::swap(own, other);
}
}
pub fn unwrap(self) -> ByAddressType<BTreeMap<TypeIndex, T>> {
self.0
}
}
impl<T> Default for AddressTypeToTypeIndexTree<T> {
@@ -0,0 +1,57 @@
use std::mem;
use derive_deref::{Deref, DerefMut};
use super::ByAddressType;
#[derive(Debug, Deref, DerefMut)]
pub struct AddressTypeToVec<T>(ByAddressType<Vec<T>>);
impl<T> AddressTypeToVec<T> {
pub fn merge(mut self, mut other: Self) -> Self {
Self::merge_(&mut self.p2pk65, &mut other.p2pk65);
Self::merge_(&mut self.p2pk33, &mut other.p2pk33);
Self::merge_(&mut self.p2pkh, &mut other.p2pkh);
Self::merge_(&mut self.p2sh, &mut other.p2sh);
Self::merge_(&mut self.p2wpkh, &mut other.p2wpkh);
Self::merge_(&mut self.p2wsh, &mut other.p2wsh);
Self::merge_(&mut self.p2tr, &mut other.p2tr);
Self::merge_(&mut self.p2a, &mut other.p2a);
self
}
pub fn merge_mut(&mut self, mut other: Self) {
Self::merge_(&mut self.p2pk65, &mut other.p2pk65);
Self::merge_(&mut self.p2pk33, &mut other.p2pk33);
Self::merge_(&mut self.p2pkh, &mut other.p2pkh);
Self::merge_(&mut self.p2sh, &mut other.p2sh);
Self::merge_(&mut self.p2wpkh, &mut other.p2wpkh);
Self::merge_(&mut self.p2wsh, &mut other.p2wsh);
Self::merge_(&mut self.p2tr, &mut other.p2tr);
Self::merge_(&mut self.p2a, &mut other.p2a);
}
fn merge_(own: &mut Vec<T>, other: &mut Vec<T>) {
if own.len() >= other.len() {
own.append(other);
} else {
other.append(own);
mem::swap(own, other);
}
}
}
impl<T> Default for AddressTypeToVec<T> {
fn default() -> Self {
Self(ByAddressType {
p2pk65: vec![],
p2pk33: vec![],
p2pkh: vec![],
p2sh: vec![],
p2wpkh: vec![],
p2wsh: vec![],
p2tr: vec![],
p2a: vec![],
})
}
}
@@ -0,0 +1,9 @@
use std::collections::BTreeMap;
use brk_structs::Height;
use derive_deref::{Deref, DerefMut};
use crate::stateful::AddressTypeToVec;
#[derive(Debug, Default, Deref, DerefMut)]
pub struct HeightToAddressTypeToVec<T>(pub BTreeMap<Height, AddressTypeToVec<T>>);
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,49 @@
use std::collections::BTreeMap;
use brk_vecs::{CompressedVec, RawVec, StoredCompressed, StoredIndex, StoredRaw};
#[derive(Debug)]
pub struct RangeMap<I, T>(BTreeMap<I, T>);
impl<I, T> RangeMap<I, T>
where
I: StoredIndex,
T: StoredIndex,
{
pub fn get(&self, key: I) -> Option<&T> {
self.0.range(..=key).next_back().map(|(&min, value)| {
if min > key {
unreachable!()
}
value
})
}
}
impl<I, T> From<&RawVec<I, T>> for RangeMap<T, I>
where
I: StoredIndex,
T: StoredIndex + StoredRaw,
{
fn from(vec: &RawVec<I, T>) -> Self {
Self(
vec.into_iter()
.map(|(i, v)| (v.into_owned(), i))
.collect::<BTreeMap<_, _>>(),
)
}
}
impl<I, T> From<&CompressedVec<I, T>> for RangeMap<T, I>
where
I: StoredIndex,
T: StoredIndex + StoredCompressed,
{
fn from(vec: &CompressedVec<I, T>) -> Self {
Self(
vec.into_iter()
.map(|(i, v)| (v.into_owned(), i))
.collect::<BTreeMap<_, _>>(),
)
}
}
@@ -1,9 +1,9 @@
use brk_core::{Bitcoin, DateIndex, Dollars, Height, Result, Version};
use brk_exit::Exit;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_vec::{AnyCollectableVec, AnyIterableVec};
use brk_structs::{Bitcoin, DateIndex, Dollars, Height, Version};
use brk_vecs::{AnyCollectableVec, AnyIterableVec, Exit};
use crate::vecs::{Indexes, fetched, indexes, market};
use crate::{Indexes, indexes, market, price};
pub trait DynCohortVecs: Send + Sync {
fn starting_height(&self) -> Height;
@@ -30,10 +30,10 @@ pub trait DynCohortVecs: Send + Sync {
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
fetched: Option<&fetched::Vecs>,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
exit: &Exit,
) -> color_eyre::Result<()>;
) -> Result<()>;
fn vecs(&self) -> Vec<&dyn AnyCollectableVec>;
}
@@ -51,7 +51,7 @@ pub trait CohortVecs: DynCohortVecs {
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
fetched: Option<&fetched::Vecs>,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
market: &market::Vecs,
height_to_supply: &impl AnyIterableVec<Height, Bitcoin>,
@@ -59,5 +59,5 @@ pub trait CohortVecs: DynCohortVecs {
height_to_realized_cap: Option<&impl AnyIterableVec<Height, Dollars>>,
dateindex_to_realized_cap: Option<&impl AnyIterableVec<DateIndex, Dollars>>,
exit: &Exit,
) -> color_eyre::Result<()>;
) -> Result<()>;
}
@@ -1,18 +1,15 @@
use std::{ops::Deref, path::Path};
use std::{ops::Deref, path::Path, sync::Arc};
use brk_core::{Bitcoin, DateIndex, Dollars, Height, Result, Version};
use brk_exit::Exit;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_vec::{AnyCollectableVec, AnyIterableVec, Computation, Format};
use brk_structs::{Bitcoin, DateIndex, Dollars, Height, Version};
use brk_vecs::{AnyCollectableVec, AnyIterableVec, Computation, Exit, File, Format};
use crate::{
UTXOCohortState,
vecs::{
Indexes, fetched, indexes, market,
stateful::{
common,
r#trait::{CohortVecs, DynCohortVecs},
},
Indexes, UTXOCohortState, indexes, market, price,
stateful::{
common,
r#trait::{CohortVecs, DynCohortVecs},
},
};
@@ -28,16 +25,18 @@ pub struct Vecs {
impl Vecs {
#[allow(clippy::too_many_arguments)]
pub fn forced_import(
path: &Path,
file: &Arc<File>,
cohort_name: Option<&str>,
computation: Computation,
format: Format,
version: Version,
fetched: Option<&fetched::Vecs>,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
states_path: &Path,
compute_relative_to_all: bool,
) -> color_eyre::Result<Self> {
let compute_dollars = fetched.is_some();
ratio_extended: bool,
) -> Result<Self> {
let compute_dollars = price.is_some();
Ok(Self {
starting_height: Height::ZERO,
@@ -49,13 +48,15 @@ impl Vecs {
)?,
inner: common::Vecs::forced_import(
path,
file,
cohort_name,
computation,
format,
version,
fetched,
indexes,
price,
compute_relative_to_all,
ratio_extended,
)?,
})
}
@@ -122,12 +123,12 @@ impl DynCohortVecs for Vecs {
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
fetched: Option<&fetched::Vecs>,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
exit: &Exit,
) -> color_eyre::Result<()> {
) -> Result<()> {
self.inner
.compute_rest_part1(indexer, indexes, fetched, starting_indexes, exit)
.compute_rest_part1(indexer, indexes, price, starting_indexes, exit)
}
fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
@@ -154,7 +155,7 @@ impl CohortVecs for Vecs {
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
fetched: Option<&fetched::Vecs>,
price: Option<&price::Vecs>,
starting_indexes: &Indexes,
market: &market::Vecs,
height_to_supply: &impl AnyIterableVec<Height, Bitcoin>,
@@ -162,11 +163,11 @@ impl CohortVecs for Vecs {
height_to_realized_cap: Option<&impl AnyIterableVec<Height, Dollars>>,
dateindex_to_realized_cap: Option<&impl AnyIterableVec<DateIndex, Dollars>>,
exit: &Exit,
) -> color_eyre::Result<()> {
) -> Result<()> {
self.inner.compute_rest_part2(
indexer,
indexes,
fetched,
price,
starting_indexes,
market,
height_to_supply,
@@ -0,0 +1,54 @@
use brk_structs::{EmptyAddressData, EmptyAddressIndex, LoadedAddressData, LoadedAddressIndex};
#[derive(Debug)]
pub enum WithAddressDataSource<T> {
New(T),
FromLoadedAddressDataVec((LoadedAddressIndex, T)),
FromEmptyAddressDataVec((EmptyAddressIndex, T)),
}
impl<T> WithAddressDataSource<T> {
pub fn is_new(&self) -> bool {
matches!(self, Self::New(_))
}
pub fn is_from_emptyaddressdata(&self) -> bool {
matches!(self, Self::FromEmptyAddressDataVec(_))
}
pub fn deref_mut(&mut self) -> &mut T {
match self {
Self::New(v) => v,
Self::FromLoadedAddressDataVec((_, v)) => v,
Self::FromEmptyAddressDataVec((_, v)) => v,
}
}
}
impl From<WithAddressDataSource<EmptyAddressData>> for WithAddressDataSource<LoadedAddressData> {
fn from(value: WithAddressDataSource<EmptyAddressData>) -> Self {
match value {
WithAddressDataSource::New(v) => Self::New(v.into()),
WithAddressDataSource::FromLoadedAddressDataVec((i, v)) => {
Self::FromLoadedAddressDataVec((i, v.into()))
}
WithAddressDataSource::FromEmptyAddressDataVec((i, v)) => {
Self::FromEmptyAddressDataVec((i, v.into()))
}
}
}
}
impl From<WithAddressDataSource<LoadedAddressData>> for WithAddressDataSource<EmptyAddressData> {
fn from(value: WithAddressDataSource<LoadedAddressData>) -> Self {
match value {
WithAddressDataSource::New(v) => Self::New(v.into()),
WithAddressDataSource::FromLoadedAddressDataVec((i, v)) => {
Self::FromLoadedAddressDataVec((i, v.into()))
}
WithAddressDataSource::FromEmptyAddressDataVec((i, v)) => {
Self::FromEmptyAddressDataVec((i, v.into()))
}
}
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
use std::ops::{Add, AddAssign, SubAssign};
use brk_core::{Dollars, Timestamp};
use brk_structs::{Dollars, Timestamp};
use super::SupplyState;
@@ -1,6 +1,7 @@
use std::path::Path;
use brk_core::{AddressData, Dollars, Height, Result, Sats};
use brk_error::Result;
use brk_structs::{Dollars, Height, LoadedAddressData, Sats};
use crate::SupplyState;
@@ -8,7 +9,7 @@ use super::CohortState;
#[derive(Clone)]
pub struct AddressCohortState {
pub address_count: usize,
pub address_count: u64,
pub inner: CohortState,
}
@@ -35,7 +36,7 @@ impl AddressCohortState {
#[allow(clippy::too_many_arguments)]
pub fn send(
&mut self,
addressdata: &mut AddressData,
addressdata: &mut LoadedAddressData,
value: Sats,
current_price: Option<Dollars>,
prev_price: Option<Dollars>,
@@ -47,14 +48,14 @@ impl AddressCohortState {
let prev_realized_price = compute_price.then(|| addressdata.realized_price());
let prev_supply_state = SupplyState {
utxos: addressdata.outputs_len as usize,
utxos: addressdata.outputs_len as u64,
value: addressdata.amount(),
};
addressdata.send(value, prev_price)?;
let supply_state = SupplyState {
utxos: addressdata.outputs_len as usize,
utxos: addressdata.outputs_len as u64,
value: addressdata.amount(),
};
@@ -72,19 +73,24 @@ impl AddressCohortState {
Ok(())
}
pub fn receive(&mut self, address_data: &mut AddressData, value: Sats, price: Option<Dollars>) {
pub fn receive(
&mut self,
address_data: &mut LoadedAddressData,
value: Sats,
price: Option<Dollars>,
) {
let compute_price = price.is_some();
let prev_realized_price = compute_price.then(|| address_data.realized_price());
let prev_supply_state = SupplyState {
utxos: address_data.outputs_len as usize,
utxos: address_data.outputs_len as u64,
value: address_data.amount(),
};
address_data.receive(value, price);
let supply_state = SupplyState {
utxos: address_data.outputs_len as usize,
utxos: address_data.outputs_len as u64,
value: address_data.amount(),
};
@@ -96,7 +102,7 @@ impl AddressCohortState {
);
}
pub fn add(&mut self, addressdata: &AddressData) {
pub fn add(&mut self, addressdata: &LoadedAddressData) {
self.address_count += 1;
self.inner.increment_(
&addressdata.into(),
@@ -105,7 +111,7 @@ impl AddressCohortState {
);
}
pub fn subtract(&mut self, addressdata: &AddressData) {
pub fn subtract(&mut self, addressdata: &LoadedAddressData) {
self.address_count = self.address_count.checked_sub(1).unwrap();
self.inner.decrement_(
&addressdata.into(),
@@ -1,6 +1,7 @@
use std::{cmp::Ordering, path::Path};
use brk_core::{CheckedSub, Dollars, Height, Result, Sats};
use brk_error::Result;
use brk_structs::{CheckedSub, Dollars, Height, Sats};
use crate::{PriceToAmount, RealizedState, SupplyState, UnrealizedState};
@@ -52,12 +53,12 @@ impl CohortState {
pub fn increment(&mut self, supply_state: &SupplyState, price: Option<Dollars>) {
self.supply += supply_state;
if supply_state.value > Sats::ZERO {
if let Some(realized) = self.realized.as_mut() {
let price = price.unwrap();
realized.increment(supply_state, price);
self.price_to_amount.increment(price, supply_state);
}
if supply_state.value > Sats::ZERO
&& let Some(realized) = self.realized.as_mut()
{
let price = price.unwrap();
realized.increment(supply_state, price);
self.price_to_amount.increment(price, supply_state);
}
}
@@ -69,23 +70,23 @@ impl CohortState {
) {
self.supply += supply_state;
if supply_state.value > Sats::ZERO {
if let Some(realized) = self.realized.as_mut() {
realized.increment_(realized_cap);
self.price_to_amount.increment(realized_price, supply_state);
}
if supply_state.value > Sats::ZERO
&& let Some(realized) = self.realized.as_mut()
{
realized.increment_(realized_cap);
self.price_to_amount.increment(realized_price, supply_state);
}
}
pub fn decrement(&mut self, supply_state: &SupplyState, price: Option<Dollars>) {
self.supply -= supply_state;
if supply_state.value > Sats::ZERO {
if let Some(realized) = self.realized.as_mut() {
let price = price.unwrap();
realized.decrement(supply_state, price);
self.price_to_amount.decrement(price, supply_state);
}
if supply_state.value > Sats::ZERO
&& let Some(realized) = self.realized.as_mut()
{
let price = price.unwrap();
realized.decrement(supply_state, price);
self.price_to_amount.decrement(price, supply_state);
}
}
@@ -97,11 +98,11 @@ impl CohortState {
) {
self.supply -= supply_state;
if supply_state.value > Sats::ZERO {
if let Some(realized) = self.realized.as_mut() {
realized.decrement_(realized_cap);
self.price_to_amount.decrement(realized_price, supply_state);
}
if supply_state.value > Sats::ZERO
&& let Some(realized) = self.realized.as_mut()
{
realized.decrement_(realized_cap);
self.price_to_amount.decrement(realized_price, supply_state);
}
}
@@ -123,21 +124,22 @@ impl CohortState {
) {
self.supply += supply_state;
if supply_state.value > Sats::ZERO {
if let Some(realized) = self.realized.as_mut() {
let price = price.unwrap();
realized.receive(supply_state, price);
if supply_state.value > Sats::ZERO
&& let Some(realized) = self.realized.as_mut()
{
let price = price.unwrap();
realized.receive(supply_state, price);
if let Some((price, supply)) = price_to_amount_increment
&& supply.value.is_not_zero()
{
self.price_to_amount.increment(price, supply);
}
if let Some((price, supply)) = price_to_amount_decrement
&& supply.value.is_not_zero()
{
self.price_to_amount.decrement(price, supply);
}
if let Some((price, supply)) = price_to_amount_increment
&& supply.value.is_not_zero()
{
self.price_to_amount.increment(price, supply);
}
if let Some((price, supply)) = price_to_amount_decrement
&& supply.value.is_not_zero()
{
self.price_to_amount.decrement(price, supply);
}
}
}
@@ -223,17 +225,15 @@ impl CohortState {
let update_state =
|price: Dollars, current_price: Dollars, sats: Sats, state: &mut UnrealizedState| {
match price.cmp(&current_price) {
Ordering::Equal => {
state.supply_even += sats;
}
Ordering::Less => {
state.supply_in_profit += sats;
if price > Dollars::ZERO && current_price > Dollars::ZERO {
let diff = current_price.checked_sub(price).unwrap();
if diff <= Dollars::ZERO {
dbg!(price, current_price, diff, sats);
panic!();
}
// Add back once in a while to verify, but generally not needed
// if diff <= Dollars::ZERO {
// dbg!(price, current_price, diff, sats);
// panic!();
// }
state.unrealized_profit += diff * sats;
}
}
@@ -241,13 +241,17 @@ impl CohortState {
state.supply_in_loss += sats;
if price > Dollars::ZERO && current_price > Dollars::ZERO {
let diff = price.checked_sub(current_price).unwrap();
if diff <= Dollars::ZERO {
dbg!(price, current_price, diff, sats);
panic!();
}
// Add back once in a while to verify, but generally not needed
// if diff <= Dollars::ZERO {
// dbg!(price, current_price, diff, sats);
// panic!();
// }
state.unrealized_loss += diff * sats;
}
}
Ordering::Equal => {
state.supply_even += sats;
}
}
};
@@ -1,6 +1,7 @@
use std::path::Path;
use brk_core::{Height, Result};
use brk_error::Result;
use brk_structs::Height;
use derive_deref::{Deref, DerefMut};
use super::CohortState;
@@ -1,14 +1,15 @@
use std::{
collections::BTreeMap,
fs::{self, File},
io::{BufReader, BufWriter},
fs,
io::{Cursor, Read},
path::{Path, PathBuf},
};
use bincode::{Decode, Encode, config, decode_from_std_read, encode_into_std_write};
use brk_core::{Dollars, Height, Result, Sats};
use brk_error::{Error, Result};
use brk_structs::{Dollars, Height, Sats};
use derive_deref::{Deref, DerefMut};
use serde::{Deserialize, Serialize};
use zerocopy::{FromBytes, IntoBytes};
use crate::states::SupplyState;
@@ -19,15 +20,15 @@ pub struct PriceToAmount {
state: State,
}
#[derive(Clone, Default, Debug, Deref, DerefMut, Serialize, Deserialize, Encode, Decode)]
struct State(BTreeMap<Dollars, Sats>);
impl PriceToAmount {
pub fn forced_import(path: &Path, name: &str) -> Self {
Self::import(path, name).unwrap_or_else(|_| Self {
pathbuf: Self::path_(path, name),
height: None,
state: State::default(),
Self::import(path, name).unwrap_or_else(|_| {
// dbg!(e);
Self {
pathbuf: Self::path_(path, name),
height: None,
state: State::default(),
}
})
}
@@ -35,10 +36,7 @@ impl PriceToAmount {
let path = Self::path_(path, name);
fs::create_dir_all(&path)?;
let config = config::standard();
let file = File::open(Self::path_state_(&path))?;
let mut reader = BufReader::new(file);
let state = decode_from_std_read(&mut reader, config)?;
let state = State::deserialize(&fs::read(Self::path_state_(&path))?)?;
Ok(Self {
height: Height::try_from(Self::path_height_(&path).as_path()).ok(),
@@ -68,10 +66,14 @@ impl PriceToAmount {
}
pub fn decrement(&mut self, price: Dollars, supply_state: &SupplyState) {
let amount = self.state.get_mut(&price).unwrap();
*amount -= supply_state.value;
if *amount == Sats::ZERO {
self.state.remove(&price);
if let Some(amount) = self.state.get_mut(&price) {
*amount -= supply_state.value;
if *amount == Sats::ZERO {
self.state.remove(&price);
}
} else {
dbg!(&self.state, price, &self.pathbuf);
unreachable!();
}
}
@@ -86,13 +88,7 @@ impl PriceToAmount {
pub fn flush(&mut self, height: Height) -> Result<()> {
self.height = Some(height);
height.write(&self.path_height())?;
let config = config::standard();
let file = File::create(self.path_state()).inspect_err(|_| {
dbg!(self.path_state());
})?;
let mut writer = BufWriter::new(file);
encode_into_std_write(&self.state, &mut writer, config)?;
fs::write(self.path_state(), self.state.serialize())?;
Ok(())
}
@@ -118,3 +114,47 @@ impl PriceToAmount {
path.join("height")
}
}
#[derive(Clone, Default, Debug, Deref, DerefMut, Serialize, Deserialize)]
struct State(BTreeMap<Dollars, Sats>);
impl State {
fn serialize(&self) -> Vec<u8> {
let len = self.len();
let mut buffer = Vec::with_capacity(8 + len * 16);
buffer.extend(len.as_bytes());
self.iter().for_each(|(key, value)| {
buffer.extend(key.as_bytes());
buffer.extend(value.as_bytes());
});
buffer
}
fn deserialize(data: &[u8]) -> Result<Self> {
let mut cursor = Cursor::new(data);
let mut buffer = [0u8; 8];
cursor
.read_exact(&mut buffer)
.map_err(|_| Error::Str("Failed to read entry count"))?;
let entry_count = usize::read_from_bytes(&buffer)?;
let mut map = BTreeMap::new();
for _ in 0..entry_count {
cursor.read_exact(&mut buffer)?;
let key = Dollars::read_from_bytes(&buffer)?;
cursor.read_exact(&mut buffer)?;
let value = Sats::read_from_bytes(&buffer)?;
map.insert(key, value);
}
Ok(Self(map))
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
use std::cmp::Ordering;
use brk_core::{CheckedSub, Dollars};
use brk_structs::{CheckedSub, Dollars};
use super::SupplyState;
+5 -5
View File
@@ -1,12 +1,12 @@
use std::ops::{Add, AddAssign, SubAssign};
use brk_core::{AddressData, CheckedSub, Sats};
use brk_structs::{CheckedSub, LoadedAddressData, Sats};
use serde::Serialize;
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
#[derive(Debug, Default, Clone, FromBytes, Immutable, IntoBytes, KnownLayout, Serialize)]
pub struct SupplyState {
pub utxos: usize,
pub utxos: u64,
pub value: Sats,
}
@@ -40,10 +40,10 @@ impl SubAssign<&SupplyState> for SupplyState {
}
}
impl From<&AddressData> for SupplyState {
fn from(value: &AddressData) -> Self {
impl From<&LoadedAddressData> for SupplyState {
fn from(value: &LoadedAddressData) -> Self {
Self {
utxos: value.outputs_len as usize,
utxos: value.outputs_len as u64,
value: value.amount(),
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
use std::ops::{Add, AddAssign};
use brk_core::{ByAmountRange, GroupedByType, OutputType, Sats};
use brk_structs::{ByAmountRange, GroupedByType, OutputType, Sats};
use super::SupplyState;
+1 -1
View File
@@ -1,4 +1,4 @@
use brk_core::{Dollars, Sats};
use brk_structs::{Dollars, Sats};
#[derive(Debug, Default, Clone)]
pub struct UnrealizedState {
-647
View File
@@ -1,647 +0,0 @@
use std::{path::Path, thread};
use brk_core::{
AddressData, ByAddressType, EmptyAddressData, Height, OutputType, P2AAddressIndex,
P2PK33AddressIndex, P2PK65AddressIndex, P2PKHAddressIndex, P2SHAddressIndex, P2TRAddressIndex,
P2WPKHAddressIndex, P2WSHAddressIndex, Result, TypeIndex, Version,
};
use brk_store::{AnyStore, Store};
use fjall::{PersistMode, TransactionalKeyspace};
use log::info;
use crate::vecs::stateful::{AddressTypeToTypeIndexTree, WithAddressDataSource};
const VERSION: Version = Version::ZERO;
#[derive(Clone)]
pub struct Stores {
keyspace: TransactionalKeyspace,
pub p2aaddressindex_to_addressdata: Store<P2AAddressIndex, AddressData>,
pub p2aaddressindex_to_emptyaddressdata: Store<P2AAddressIndex, EmptyAddressData>,
pub p2pk33addressindex_to_addressdata: Store<P2PK33AddressIndex, AddressData>,
pub p2pk33addressindex_to_emptyaddressdata: Store<P2PK33AddressIndex, EmptyAddressData>,
pub p2pk65addressindex_to_addressdata: Store<P2PK65AddressIndex, AddressData>,
pub p2pk65addressindex_to_emptyaddressdata: Store<P2PK65AddressIndex, EmptyAddressData>,
pub p2pkhaddressindex_to_addressdata: Store<P2PKHAddressIndex, AddressData>,
pub p2pkhaddressindex_to_emptyaddressdata: Store<P2PKHAddressIndex, EmptyAddressData>,
pub p2shaddressindex_to_addressdata: Store<P2SHAddressIndex, AddressData>,
pub p2shaddressindex_to_emptyaddressdata: Store<P2SHAddressIndex, EmptyAddressData>,
pub p2traddressindex_to_addressdata: Store<P2TRAddressIndex, AddressData>,
pub p2traddressindex_to_emptyaddressdata: Store<P2TRAddressIndex, EmptyAddressData>,
pub p2wpkhaddressindex_to_addressdata: Store<P2WPKHAddressIndex, AddressData>,
pub p2wpkhaddressindex_to_emptyaddressdata: Store<P2WPKHAddressIndex, EmptyAddressData>,
pub p2wshaddressindex_to_addressdata: Store<P2WSHAddressIndex, AddressData>,
pub p2wshaddressindex_to_emptyaddressdata: Store<P2WSHAddressIndex, EmptyAddressData>,
}
impl Stores {
pub fn import(
path: &Path,
version: Version,
keyspace: &TransactionalKeyspace,
) -> color_eyre::Result<Self> {
let (
(p2aaddressindex_to_addressdata, p2aaddressindex_to_emptyaddressdata),
(p2pk33addressindex_to_addressdata, p2pk33addressindex_to_emptyaddressdata),
(p2pk65addressindex_to_addressdata, p2pk65addressindex_to_emptyaddressdata),
(p2pkhaddressindex_to_addressdata, p2pkhaddressindex_to_emptyaddressdata),
(p2shaddressindex_to_addressdata, p2shaddressindex_to_emptyaddressdata),
(p2traddressindex_to_addressdata, p2traddressindex_to_emptyaddressdata),
(p2wpkhaddressindex_to_addressdata, p2wpkhaddressindex_to_emptyaddressdata),
(p2wshaddressindex_to_addressdata, p2wshaddressindex_to_emptyaddressdata),
) = thread::scope(|scope| {
let p2a = scope.spawn(|| {
(
Store::import(
keyspace,
path,
"p2aaddressindex_to_addressdata",
version + VERSION + Version::ZERO,
None,
)
.unwrap(),
Store::import(
keyspace,
path,
"p2aaddressindex_to_emptyaddressdata",
version + VERSION + Version::ZERO,
None,
)
.unwrap(),
)
});
let p2pk33 = scope.spawn(|| {
(
Store::import(
keyspace,
path,
"p2pk33addressindex_to_addressdata",
version + VERSION + Version::ZERO,
None,
)
.unwrap(),
Store::import(
keyspace,
path,
"p2pk33addressindex_to_emptyaddressdata",
version + VERSION + Version::ZERO,
None,
)
.unwrap(),
)
});
let p2pk65 = scope.spawn(|| {
(
Store::import(
keyspace,
path,
"p2pk65addressindex_to_addressdata",
version + VERSION + Version::ZERO,
None,
)
.unwrap(),
Store::import(
keyspace,
path,
"p2pk65addressindex_to_emptyaddressdata",
version + VERSION + Version::ZERO,
None,
)
.unwrap(),
)
});
let p2pkh = scope.spawn(|| {
(
Store::import(
keyspace,
path,
"p2pkhaddressindex_to_addressdata",
version + VERSION + Version::ZERO,
None,
)
.unwrap(),
Store::import(
keyspace,
path,
"p2pkhaddressindex_to_emptyaddressdata",
version + VERSION + Version::ZERO,
None,
)
.unwrap(),
)
});
let p2sh = scope.spawn(|| {
(
Store::import(
keyspace,
path,
"p2shaddressindex_to_addressdata",
version + VERSION + Version::ZERO,
None,
)
.unwrap(),
Store::import(
keyspace,
path,
"p2shaddressindex_to_emptyaddressdata",
version + VERSION + Version::ZERO,
None,
)
.unwrap(),
)
});
let p2tr = scope.spawn(|| {
(
Store::import(
keyspace,
path,
"p2traddressindex_to_addressdata",
version + VERSION + Version::ZERO,
None,
)
.unwrap(),
Store::import(
keyspace,
path,
"p2traddressindex_to_emptyaddressdata",
version + VERSION + Version::ZERO,
None,
)
.unwrap(),
)
});
let p2wpkh = scope.spawn(|| {
(
Store::import(
keyspace,
path,
"p2wpkhaddressindex_to_addressdata",
version + VERSION + Version::ZERO,
None,
)
.unwrap(),
Store::import(
keyspace,
path,
"p2wpkhaddressindex_to_emptyaddressdata",
version + VERSION + Version::ZERO,
None,
)
.unwrap(),
)
});
let p2wsh = scope.spawn(|| {
(
Store::import(
keyspace,
path,
"p2wshaddressindex_to_addressdata",
version + VERSION + Version::ZERO,
None,
)
.unwrap(),
Store::import(
keyspace,
path,
"p2wshaddressindex_to_emptyaddressdata",
version + VERSION + Version::ZERO,
None,
)
.unwrap(),
)
});
(
p2a.join().unwrap(),
p2pk33.join().unwrap(),
p2pk65.join().unwrap(),
p2pkh.join().unwrap(),
p2sh.join().unwrap(),
p2tr.join().unwrap(),
p2wpkh.join().unwrap(),
p2wsh.join().unwrap(),
)
});
Ok(Self {
keyspace: keyspace.clone(),
p2aaddressindex_to_addressdata,
p2aaddressindex_to_emptyaddressdata,
p2pk33addressindex_to_addressdata,
p2pk33addressindex_to_emptyaddressdata,
p2pk65addressindex_to_addressdata,
p2pk65addressindex_to_emptyaddressdata,
p2pkhaddressindex_to_addressdata,
p2pkhaddressindex_to_emptyaddressdata,
p2shaddressindex_to_addressdata,
p2shaddressindex_to_emptyaddressdata,
p2traddressindex_to_addressdata,
p2traddressindex_to_emptyaddressdata,
p2wpkhaddressindex_to_addressdata,
p2wpkhaddressindex_to_emptyaddressdata,
p2wshaddressindex_to_addressdata,
p2wshaddressindex_to_emptyaddressdata,
})
}
pub fn starting_height(&self) -> Height {
self.as_slice()
.into_iter()
.map(|store| store.height().map(Height::incremented).unwrap_or_default())
.min()
.unwrap()
}
pub fn reset(&mut self) -> Result<()> {
info!("Resetting stores...");
info!("> If it gets stuck here, stop the program and start it again");
self.as_mut_slice()
.into_iter()
.try_for_each(|store| store.reset())?;
self.keyspace
.persist(PersistMode::SyncAll)
.map_err(|e| e.into())
}
pub fn get_addressdata(
&self,
address_type: OutputType,
type_index: TypeIndex,
) -> Result<Option<AddressData>> {
Ok(match address_type {
OutputType::P2A => self
.p2aaddressindex_to_addressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2PK33 => self
.p2pk33addressindex_to_addressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2PK65 => self
.p2pk65addressindex_to_addressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2PKH => self
.p2pkhaddressindex_to_addressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2SH => self
.p2shaddressindex_to_addressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2TR => self
.p2traddressindex_to_addressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2WPKH => self
.p2wpkhaddressindex_to_addressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2WSH => self
.p2wshaddressindex_to_addressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
_ => unreachable!(),
})
}
pub fn get_emptyaddressdata(
&self,
address_type: OutputType,
type_index: TypeIndex,
) -> Result<Option<EmptyAddressData>> {
Ok(match address_type {
OutputType::P2A => self
.p2aaddressindex_to_emptyaddressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2PK33 => self
.p2pk33addressindex_to_emptyaddressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2PK65 => self
.p2pk65addressindex_to_emptyaddressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2PKH => self
.p2pkhaddressindex_to_emptyaddressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2SH => self
.p2shaddressindex_to_emptyaddressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2TR => self
.p2traddressindex_to_emptyaddressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2WPKH => self
.p2wpkhaddressindex_to_emptyaddressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
OutputType::P2WSH => self
.p2wshaddressindex_to_emptyaddressdata
.get(&type_index.into())?
.map(|c| c.into_owned()),
_ => unreachable!(),
})
}
pub fn commit(
&mut self,
height: Height,
addresstype_to_typeindex_to_addressdata: AddressTypeToTypeIndexTree<
WithAddressDataSource<AddressData>,
>,
addresstype_to_typeindex_to_emptyaddressdata: AddressTypeToTypeIndexTree<
WithAddressDataSource<EmptyAddressData>,
>,
) -> Result<()> {
let ByAddressType {
p2pk65,
p2pk33,
p2pkh,
p2sh,
p2wpkh,
p2wsh,
p2tr,
p2a,
} = addresstype_to_typeindex_to_addressdata.unwrap();
let ByAddressType {
p2pk65: empty_p2pk65,
p2pk33: empty_p2pk33,
p2pkh: empty_p2pkh,
p2sh: empty_p2sh,
p2wpkh: empty_p2wpkh,
p2wsh: empty_p2wsh,
p2tr: empty_p2tr,
p2a: empty_p2a,
} = addresstype_to_typeindex_to_emptyaddressdata.unwrap();
thread::scope(|s| {
s.spawn(|| {
self.p2aaddressindex_to_addressdata.commit_(
height,
empty_p2a
.iter()
.filter(|(_, addressdata)| addressdata.is_from_addressdata())
.map(|(typeindex, _)| (*typeindex).into()),
p2a.iter().map(|(typeindex, addressdata)| {
((*typeindex).into(), addressdata.deref().clone())
}),
)
});
s.spawn(|| {
self.p2pk33addressindex_to_addressdata.commit_(
height,
empty_p2pk33
.iter()
.filter(|(_, addressdata)| addressdata.is_from_addressdata())
.map(|(typeindex, _)| (*typeindex).into()),
p2pk33.iter().map(|(typeindex, addressdata)| {
((*typeindex).into(), addressdata.deref().clone())
}),
)
});
s.spawn(|| {
self.p2pk65addressindex_to_addressdata.commit_(
height,
empty_p2pk65
.iter()
.filter(|(_, addressdata)| addressdata.is_from_addressdata())
.map(|(typeindex, _)| (*typeindex).into()),
p2pk65.iter().map(|(typeindex, addressdata)| {
((*typeindex).into(), addressdata.deref().clone())
}),
)
});
s.spawn(|| {
self.p2pkhaddressindex_to_addressdata.commit_(
height,
empty_p2pkh
.iter()
.filter(|(_, addressdata)| addressdata.is_from_addressdata())
.map(|(typeindex, _)| (*typeindex).into()),
p2pkh.iter().map(|(typeindex, addressdata)| {
((*typeindex).into(), addressdata.deref().clone())
}),
)
});
s.spawn(|| {
self.p2shaddressindex_to_addressdata.commit_(
height,
empty_p2sh
.iter()
.filter(|(_, addressdata)| addressdata.is_from_addressdata())
.map(|(typeindex, _)| (*typeindex).into()),
p2sh.iter().map(|(typeindex, addressdata)| {
((*typeindex).into(), addressdata.deref().clone())
}),
)
});
s.spawn(|| {
self.p2traddressindex_to_addressdata.commit_(
height,
empty_p2tr
.iter()
.filter(|(_, addressdata)| addressdata.is_from_addressdata())
.map(|(typeindex, _)| (*typeindex).into()),
p2tr.iter().map(|(typeindex, addressdata)| {
((*typeindex).into(), addressdata.deref().clone())
}),
)
});
s.spawn(|| {
self.p2wpkhaddressindex_to_addressdata.commit_(
height,
empty_p2wpkh
.iter()
.filter(|(_, addressdata)| addressdata.is_from_addressdata())
.map(|(typeindex, _)| (*typeindex).into()),
p2wpkh.iter().map(|(typeindex, addressdata)| {
((*typeindex).into(), addressdata.deref().clone())
}),
)
});
s.spawn(|| {
self.p2wshaddressindex_to_addressdata.commit_(
height,
empty_p2wsh
.iter()
.filter(|(_, addressdata)| addressdata.is_from_addressdata())
.map(|(typeindex, _)| (*typeindex).into()),
p2wsh.iter().map(|(typeindex, addressdata)| {
((*typeindex).into(), addressdata.deref().clone())
}),
)
});
});
thread::scope(|scope| {
scope.spawn(|| {
self.p2aaddressindex_to_emptyaddressdata.commit_(
height,
p2a.iter()
.filter(|(_, addressdata)| addressdata.is_from_emptyaddressdata())
.map(|(typeindex, _)| (*typeindex).into()),
empty_p2a.iter().map(|(typeindex, addressdata)| {
((*typeindex).into(), addressdata.deref().clone())
}),
)
});
scope.spawn(|| {
self.p2pk33addressindex_to_emptyaddressdata.commit_(
height,
p2pk33
.iter()
.filter(|(_, addressdata)| addressdata.is_from_emptyaddressdata())
.map(|(typeindex, _)| (*typeindex).into()),
empty_p2pk33.iter().map(|(typeindex, addressdata)| {
((*typeindex).into(), addressdata.deref().clone())
}),
)
});
scope.spawn(|| {
self.p2pk65addressindex_to_emptyaddressdata.commit_(
height,
p2pk65
.iter()
.filter(|(_, addressdata)| addressdata.is_from_emptyaddressdata())
.map(|(typeindex, _)| (*typeindex).into()),
empty_p2pk65.iter().map(|(typeindex, addressdata)| {
((*typeindex).into(), addressdata.deref().clone())
}),
)
});
scope.spawn(|| {
self.p2pkhaddressindex_to_emptyaddressdata.commit_(
height,
p2pkh
.iter()
.filter(|(_, addressdata)| addressdata.is_from_emptyaddressdata())
.map(|(typeindex, _)| (*typeindex).into()),
empty_p2pkh.iter().map(|(typeindex, addressdata)| {
((*typeindex).into(), addressdata.deref().clone())
}),
)
});
scope.spawn(|| {
self.p2shaddressindex_to_emptyaddressdata.commit_(
height,
p2sh.iter()
.filter(|(_, addressdata)| addressdata.is_from_emptyaddressdata())
.map(|(typeindex, _)| (*typeindex).into()),
empty_p2sh.iter().map(|(typeindex, addressdata)| {
((*typeindex).into(), addressdata.deref().clone())
}),
)
});
scope.spawn(|| {
self.p2traddressindex_to_emptyaddressdata.commit_(
height,
p2tr.iter()
.filter(|(_, addressdata)| addressdata.is_from_emptyaddressdata())
.map(|(typeindex, _)| (*typeindex).into()),
empty_p2tr.iter().map(|(typeindex, addressdata)| {
((*typeindex).into(), addressdata.deref().clone())
}),
)
});
scope.spawn(|| {
self.p2wpkhaddressindex_to_emptyaddressdata.commit_(
height,
p2wpkh
.iter()
.filter(|(_, addressdata)| addressdata.is_from_emptyaddressdata())
.map(|(typeindex, _)| (*typeindex).into()),
empty_p2wpkh.iter().map(|(typeindex, addressdata)| {
((*typeindex).into(), addressdata.deref().clone())
}),
)
});
scope.spawn(|| {
self.p2wshaddressindex_to_emptyaddressdata.commit_(
height,
p2wsh
.iter()
.filter(|(_, addressdata)| addressdata.is_from_emptyaddressdata())
.map(|(typeindex, _)| (*typeindex).into()),
empty_p2wsh.iter().map(|(typeindex, addressdata)| {
((*typeindex).into(), addressdata.deref().clone())
}),
)
});
});
self.keyspace
.persist(PersistMode::SyncAll)
.map_err(|e| e.into())
}
pub fn rotate_memtables(&self) {
self.as_slice()
.into_iter()
.for_each(|store| store.rotate_memtable());
}
pub fn as_slice(&self) -> [&(dyn AnyStore + Send + Sync); 16] {
[
&self.p2aaddressindex_to_addressdata,
&self.p2aaddressindex_to_emptyaddressdata,
&self.p2pk33addressindex_to_addressdata,
&self.p2pk33addressindex_to_emptyaddressdata,
&self.p2pk65addressindex_to_addressdata,
&self.p2pk65addressindex_to_emptyaddressdata,
&self.p2pkhaddressindex_to_addressdata,
&self.p2pkhaddressindex_to_emptyaddressdata,
&self.p2shaddressindex_to_addressdata,
&self.p2shaddressindex_to_emptyaddressdata,
&self.p2traddressindex_to_addressdata,
&self.p2traddressindex_to_emptyaddressdata,
&self.p2wpkhaddressindex_to_addressdata,
&self.p2wpkhaddressindex_to_emptyaddressdata,
&self.p2wshaddressindex_to_addressdata,
&self.p2wshaddressindex_to_emptyaddressdata,
]
}
fn as_mut_slice(&mut self) -> [&mut (dyn AnyStore + Send + Sync); 16] {
[
&mut self.p2aaddressindex_to_addressdata,
&mut self.p2aaddressindex_to_emptyaddressdata,
&mut self.p2pk33addressindex_to_addressdata,
&mut self.p2pk33addressindex_to_emptyaddressdata,
&mut self.p2pk65addressindex_to_addressdata,
&mut self.p2pk65addressindex_to_emptyaddressdata,
&mut self.p2pkhaddressindex_to_addressdata,
&mut self.p2pkhaddressindex_to_emptyaddressdata,
&mut self.p2shaddressindex_to_addressdata,
&mut self.p2shaddressindex_to_emptyaddressdata,
&mut self.p2traddressindex_to_addressdata,
&mut self.p2traddressindex_to_emptyaddressdata,
&mut self.p2wpkhaddressindex_to_addressdata,
&mut self.p2wpkhaddressindex_to_emptyaddressdata,
&mut self.p2wshaddressindex_to_addressdata,
&mut self.p2wshaddressindex_to_emptyaddressdata,
]
}
}
+316
View File
@@ -0,0 +1,316 @@
use brk_error::Result;
use brk_structs::{Bitcoin, CheckedSub, Close, Date, DateIndex, Dollars, Sats, StoredF32};
use brk_vecs::{
AnyIterableVec, AnyStoredVec, AnyVec, EagerVec, Exit, GenericStoredVec, StoredIndex,
VecIterator, Version,
};
const DCA_AMOUNT: Dollars = Dollars::mint(100.0);
pub trait ComputeDCAStackViaLen {
fn compute_dca_stack_via_len(
&mut self,
max_from: DateIndex,
closes: &impl AnyIterableVec<DateIndex, Close<Dollars>>,
len: usize,
exit: &Exit,
) -> Result<()>;
fn compute_dca_stack_via_from(
&mut self,
max_from: DateIndex,
closes: &impl AnyIterableVec<DateIndex, Close<Dollars>>,
from: DateIndex,
exit: &Exit,
) -> Result<()>;
}
impl ComputeDCAStackViaLen for EagerVec<DateIndex, Sats> {
fn compute_dca_stack_via_len(
&mut self,
max_from: DateIndex,
closes: &impl AnyIterableVec<DateIndex, Close<Dollars>>,
len: usize,
exit: &Exit,
) -> Result<()> {
self.validate_computed_version_or_reset_file(
Version::ZERO + self.inner_version() + closes.version(),
)?;
let mut other_iter = closes.iter();
let mut prev = None;
let index = max_from.min(DateIndex::from(self.len()));
closes.iter_at(index).try_for_each(|(i, closes)| {
let price = *closes.into_owned();
let i_usize = i.unwrap_to_usize();
if prev.is_none() {
if i_usize == 0 {
prev.replace(Sats::ZERO);
} else {
prev.replace(self.into_iter().unwrap_get_inner_(i_usize - 1));
}
}
let mut stack = Sats::ZERO;
if price != Dollars::ZERO {
stack = prev.unwrap() + Sats::from(Bitcoin::from(DCA_AMOUNT / price));
if i_usize >= len {
let prev_price = *other_iter.unwrap_get_inner_(i_usize - len);
if prev_price != Dollars::ZERO {
stack = stack
.checked_sub(Sats::from(Bitcoin::from(DCA_AMOUNT / prev_price)))
.unwrap();
}
}
}
prev.replace(stack);
self.forced_push_at(i, stack, exit)
})?;
self.safe_flush(exit)?;
Ok(())
}
fn compute_dca_stack_via_from(
&mut self,
max_from: DateIndex,
closes: &impl AnyIterableVec<DateIndex, Close<Dollars>>,
from: DateIndex,
exit: &Exit,
) -> Result<()> {
self.validate_computed_version_or_reset_file(
Version::ZERO + self.inner_version() + closes.version(),
)?;
let mut prev = None;
let index = max_from.min(DateIndex::from(self.len()));
closes.iter_at(index).try_for_each(|(i, closes)| {
let price = *closes.into_owned();
let i_usize = i.unwrap_to_usize();
if prev.is_none() {
if i_usize == 0 {
prev.replace(Sats::ZERO);
} else {
prev.replace(self.into_iter().unwrap_get_inner_(i_usize - 1));
}
}
let mut stack = Sats::ZERO;
if price != Dollars::ZERO && i >= from {
stack = prev.unwrap() + Sats::from(Bitcoin::from(DCA_AMOUNT / price));
}
prev.replace(stack);
self.forced_push_at(i, stack, exit)
})?;
self.safe_flush(exit)?;
Ok(())
}
}
pub trait ComputeDCAAveragePriceViaLen {
fn compute_dca_avg_price_via_len(
&mut self,
max_from: DateIndex,
stacks: &impl AnyIterableVec<DateIndex, Sats>,
len: usize,
exit: &Exit,
) -> Result<()>;
fn compute_dca_avg_price_via_from(
&mut self,
max_from: DateIndex,
stacks: &impl AnyIterableVec<DateIndex, Sats>,
from: DateIndex,
exit: &Exit,
) -> Result<()>;
}
impl ComputeDCAAveragePriceViaLen for EagerVec<DateIndex, Dollars> {
fn compute_dca_avg_price_via_len(
&mut self,
max_from: DateIndex,
stacks: &impl AnyIterableVec<DateIndex, Sats>,
len: usize,
exit: &Exit,
) -> Result<()> {
self.validate_computed_version_or_reset_file(
Version::ONE + self.inner_version() + stacks.version(),
)?;
let index = max_from.min(DateIndex::from(self.len()));
let first_price_date = DateIndex::try_from(Date::new(2010, 7, 12)).unwrap();
stacks.iter_at(index).try_for_each(|(i, stack)| {
let stack = stack.into_owned();
let mut avg_price = Dollars::from(f64::NAN);
if i > first_price_date {
avg_price = DCA_AMOUNT
* len
.min(i.unwrap_to_usize() + 1)
.min(i.checked_sub(first_price_date).unwrap().unwrap_to_usize() + 1)
/ Bitcoin::from(stack);
}
self.forced_push_at(i, avg_price, exit)
})?;
self.safe_flush(exit)?;
Ok(())
}
fn compute_dca_avg_price_via_from(
&mut self,
max_from: DateIndex,
stacks: &impl AnyIterableVec<DateIndex, Sats>,
from: DateIndex,
exit: &Exit,
) -> Result<()> {
self.validate_computed_version_or_reset_file(
Version::ZERO + self.inner_version() + stacks.version(),
)?;
let index = max_from.min(DateIndex::from(self.len()));
let from_usize = from.unwrap_to_usize();
stacks.iter_at(index).try_for_each(|(i, stack)| {
let stack = stack.into_owned();
let mut avg_price = Dollars::from(f64::NAN);
if i >= from {
avg_price =
DCA_AMOUNT * (i.unwrap_to_usize() + 1 - from_usize) / Bitcoin::from(stack);
}
self.forced_push_at(i, avg_price, exit)
})?;
self.safe_flush(exit)?;
Ok(())
}
}
pub trait ComputeFromSats<I> {
fn compute_from_sats(
&mut self,
max_from: I,
sats: &impl AnyIterableVec<I, Sats>,
exit: &Exit,
) -> Result<()>;
}
impl<I> ComputeFromSats<I> for EagerVec<I, Bitcoin>
where
I: StoredIndex,
{
fn compute_from_sats(
&mut self,
max_from: I,
sats: &impl AnyIterableVec<I, Sats>,
exit: &Exit,
) -> Result<()> {
self.validate_computed_version_or_reset_file(
Version::ZERO + self.inner_version() + sats.version(),
)?;
let index = max_from.min(I::from(self.len()));
sats.iter_at(index).try_for_each(|(i, sats)| {
let (i, v) = (i, Bitcoin::from(sats.into_owned()));
self.forced_push_at(i, v, exit)
})?;
self.safe_flush(exit)?;
Ok(())
}
}
pub trait ComputeFromBitcoin<I> {
fn compute_from_bitcoin(
&mut self,
max_from: I,
bitcoin: &impl AnyIterableVec<I, Bitcoin>,
price: &impl AnyIterableVec<I, Close<Dollars>>,
exit: &Exit,
) -> Result<()>;
}
impl<I> ComputeFromBitcoin<I> for EagerVec<I, Dollars>
where
I: StoredIndex,
{
fn compute_from_bitcoin(
&mut self,
max_from: I,
bitcoin: &impl AnyIterableVec<I, Bitcoin>,
price: &impl AnyIterableVec<I, Close<Dollars>>,
exit: &Exit,
) -> Result<()> {
self.validate_computed_version_or_reset_file(
Version::ZERO + self.inner_version() + bitcoin.version(),
)?;
let mut price_iter = price.iter();
let index = max_from.min(I::from(self.len()));
bitcoin.iter_at(index).try_for_each(|(i, bitcoin)| {
let dollars = price_iter.unwrap_get_inner(i);
let (i, v) = (i, *dollars * bitcoin.into_owned());
self.forced_push_at(i, v, exit)
})?;
self.safe_flush(exit)?;
Ok(())
}
}
pub trait ComputeDrawdown<I> {
fn compute_drawdown(
&mut self,
max_from: I,
close: &impl AnyIterableVec<I, Close<Dollars>>,
ath: &impl AnyIterableVec<I, Dollars>,
exit: &Exit,
) -> Result<()>;
}
impl<I> ComputeDrawdown<I> for EagerVec<I, StoredF32>
where
I: StoredIndex,
{
fn compute_drawdown(
&mut self,
max_from: I,
close: &impl AnyIterableVec<I, Close<Dollars>>,
ath: &impl AnyIterableVec<I, Dollars>,
exit: &Exit,
) -> Result<()> {
self.validate_computed_version_or_reset_file(
Version::ZERO + self.inner_version() + ath.version() + close.version(),
)?;
let index = max_from.min(I::from(self.len()));
let mut close_iter = close.iter();
ath.iter_at(index).try_for_each(|(i, ath)| {
let ath = ath.into_owned();
if ath == Dollars::ZERO {
self.forced_push_at(i, StoredF32::default(), exit)
} else {
let close = *close_iter.unwrap_get_inner(i);
let drawdown = StoredF32::from((*ath - *close) / *ath * -100.0);
self.forced_push_at(i, drawdown, exit)
}
})?;
self.safe_flush(exit)?;
Ok(())
}
}
@@ -1,106 +1,103 @@
use std::path::Path;
use std::{path::Path, sync::Arc};
use brk_core::{
CheckedSub, Feerate, HalvingEpoch, Height, InputIndex, OutputIndex, Sats, StoredU32,
StoredUsize, TxIndex, TxVersion, Version, Weight,
};
use brk_exit::Exit;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_vec::{
AnyCollectableVec, AnyIterableVec, CloneableAnyIterableVec, Computation, ComputedVec,
ComputedVecFrom1, ComputedVecFrom2, ComputedVecFrom3, Format, StoredIndex, VecIterator,
use brk_structs::{
CheckedSub, Feerate, HalvingEpoch, Height, InputIndex, OutputIndex, Sats, StoredBool,
StoredU32, StoredU64, TxIndex, TxVersion, Version, Weight,
};
use brk_vecs::{
AnyCloneableIterableVec, AnyCollectableVec, AnyIterableVec, Computation, ComputedVec,
ComputedVecFrom1, ComputedVecFrom2, ComputedVecFrom3, Exit, File, Format, PAGE_SIZE,
StoredIndex, VecIterator,
};
use super::{
Indexes, fetched,
grouped::{
ComputedValueVecsFromHeight, ComputedValueVecsFromTxindex, ComputedVecsFromHeight,
ComputedVecsFromTxindex, StorableVecGeneatorOptions,
},
indexes,
use crate::grouped::{
ComputedValueVecsFromHeight, ComputedValueVecsFromTxindex, ComputedVecsFromHeight,
ComputedVecsFromTxindex, Source, VecBuilderOptions,
};
use super::{Indexes, indexes, price};
const VERSION: Version = Version::ZERO;
#[derive(Clone)]
pub struct Vecs {
file: Arc<File>,
// pub txindex_to_is_v1: LazyVec<Txindex, bool>,
// pub txindex_to_is_v2: LazyVec<Txindex, bool>,
// pub txindex_to_is_v3: LazyVec<Txindex, bool>,
pub indexes_to_coinbase: ComputedValueVecsFromHeight,
pub indexes_to_emptyoutput_count: ComputedVecsFromHeight<StoredUsize>,
pub indexes_to_emptyoutput_count: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_fee: ComputedValueVecsFromTxindex,
pub indexes_to_feerate: ComputedVecsFromTxindex<Feerate>,
/// Value == 0 when Coinbase
pub txindex_to_input_value: ComputedVecFrom3<
TxIndex,
Sats,
TxIndex,
InputIndex,
TxIndex,
StoredUsize,
InputIndex,
Sats,
>,
pub txindex_to_input_value:
ComputedVecFrom3<TxIndex, Sats, TxIndex, InputIndex, TxIndex, StoredU64, InputIndex, Sats>,
// pub indexes_to_input_value: ComputedVecsFromTxindex<Sats>,
pub indexes_to_opreturn_count: ComputedVecsFromHeight<StoredUsize>,
pub indexes_to_opreturn_count: ComputedVecsFromHeight<StoredU64>,
pub txindex_to_output_value: ComputedVecFrom3<
TxIndex,
Sats,
TxIndex,
OutputIndex,
TxIndex,
StoredUsize,
StoredU64,
OutputIndex,
Sats,
>,
// pub indexes_to_output_value: ComputedVecsFromTxindex<Sats>,
pub indexes_to_p2a_count: ComputedVecsFromHeight<StoredUsize>,
pub indexes_to_p2ms_count: ComputedVecsFromHeight<StoredUsize>,
pub indexes_to_p2pk33_count: ComputedVecsFromHeight<StoredUsize>,
pub indexes_to_p2pk65_count: ComputedVecsFromHeight<StoredUsize>,
pub indexes_to_p2pkh_count: ComputedVecsFromHeight<StoredUsize>,
pub indexes_to_p2sh_count: ComputedVecsFromHeight<StoredUsize>,
pub indexes_to_p2tr_count: ComputedVecsFromHeight<StoredUsize>,
pub indexes_to_p2wpkh_count: ComputedVecsFromHeight<StoredUsize>,
pub indexes_to_p2wsh_count: ComputedVecsFromHeight<StoredUsize>,
pub indexes_to_p2a_count: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_p2ms_count: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_p2pk33_count: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_p2pk65_count: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_p2pkh_count: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_p2sh_count: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_p2tr_count: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_p2wpkh_count: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_p2wsh_count: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_subsidy: ComputedValueVecsFromHeight,
pub indexes_to_unclaimed_rewards: ComputedValueVecsFromHeight,
pub indexes_to_tx_count: ComputedVecsFromHeight<StoredUsize>,
pub indexes_to_tx_v1: ComputedVecsFromHeight<StoredUsize>,
pub indexes_to_tx_v2: ComputedVecsFromHeight<StoredUsize>,
pub indexes_to_tx_v3: ComputedVecsFromHeight<StoredUsize>,
pub indexes_to_tx_vsize: ComputedVecsFromTxindex<StoredUsize>,
pub indexes_to_tx_count: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_tx_v1: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_tx_v2: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_tx_v3: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_tx_vsize: ComputedVecsFromTxindex<StoredU64>,
pub indexes_to_tx_weight: ComputedVecsFromTxindex<Weight>,
pub indexes_to_unknownoutput_count: ComputedVecsFromHeight<StoredUsize>,
pub indexes_to_unknownoutput_count: ComputedVecsFromHeight<StoredU64>,
pub inputindex_to_value:
ComputedVecFrom2<InputIndex, Sats, InputIndex, OutputIndex, OutputIndex, Sats>,
pub indexes_to_input_count: ComputedVecsFromTxindex<StoredUsize>,
pub txindex_to_is_coinbase: ComputedVecFrom2<TxIndex, bool, TxIndex, Height, Height, TxIndex>,
pub indexes_to_output_count: ComputedVecsFromTxindex<StoredUsize>,
pub txindex_to_vsize: ComputedVecFrom1<TxIndex, StoredUsize, TxIndex, Weight>,
pub indexes_to_input_count: ComputedVecsFromTxindex<StoredU64>,
pub txindex_to_is_coinbase:
ComputedVecFrom2<TxIndex, StoredBool, TxIndex, Height, Height, TxIndex>,
pub indexes_to_output_count: ComputedVecsFromTxindex<StoredU64>,
pub txindex_to_vsize: ComputedVecFrom1<TxIndex, StoredU64, TxIndex, Weight>,
pub txindex_to_weight:
ComputedVecFrom2<TxIndex, Weight, TxIndex, StoredU32, TxIndex, StoredU32>,
pub txindex_to_fee: ComputedVecFrom2<TxIndex, Sats, TxIndex, Sats, TxIndex, Sats>,
pub txindex_to_feerate: ComputedVecFrom2<TxIndex, Feerate, TxIndex, Sats, TxIndex, StoredUsize>,
pub indexes_to_exact_utxo_count: ComputedVecsFromHeight<StoredUsize>,
pub txindex_to_feerate: ComputedVecFrom2<TxIndex, Feerate, TxIndex, Sats, TxIndex, StoredU64>,
pub indexes_to_exact_utxo_count: ComputedVecsFromHeight<StoredU64>,
}
impl Vecs {
pub fn forced_import(
path: &Path,
parent: &Path,
version: Version,
indexer: &Indexer,
indexes: &indexes::Vecs,
computation: Computation,
format: Format,
fetched: Option<&fetched::Vecs>,
) -> color_eyre::Result<Self> {
let compute_dollars = fetched.is_some();
price: Option<&price::Vecs>,
) -> Result<Self> {
let file = Arc::new(File::open(&parent.join("transactions"))?);
file.set_min_len(PAGE_SIZE * 10_000_000)?;
let compute_dollars = price.is_some();
let inputindex_to_value = ComputedVec::forced_import_or_init_from_2(
computation,
path,
&file,
"value",
version + VERSION + Version::ZERO,
format,
@@ -127,7 +124,7 @@ impl Vecs {
let txindex_to_weight = ComputedVec::forced_import_or_init_from_2(
computation,
path,
&file,
"weight",
version + VERSION + Version::ZERO,
format,
@@ -155,7 +152,7 @@ impl Vecs {
let txindex_to_vsize = ComputedVec::forced_import_or_init_from_1(
computation,
path,
&file,
"vsize",
version + VERSION + Version::ZERO,
format,
@@ -163,7 +160,7 @@ impl Vecs {
|index: TxIndex, iter| {
let index = index.unwrap_to_usize();
iter.next_at(index).map(|(_, weight)| {
StoredUsize::from(
StoredU64::from(
bitcoin::Weight::from(weight.into_owned()).to_vbytes_ceil() as usize
)
})
@@ -172,7 +169,7 @@ impl Vecs {
let txindex_to_is_coinbase = ComputedVec::forced_import_or_init_from_2(
computation,
path,
&file,
"is_coinbase",
version + VERSION + Version::ZERO,
format,
@@ -188,15 +185,14 @@ impl Vecs {
.unwrap()
.1
.into_owned();
index == txindex
StoredBool::from(index == txindex)
})
},
)?;
let txindex_to_input_value = ComputedVec::forced_import_or_init_from_3(
computation,
path,
&file,
"input_value",
version + VERSION + Version::ZERO,
format,
@@ -217,7 +213,7 @@ impl Vecs {
.unwrap()
.1
.into_owned();
let range = first_index..first_index + count;
let range = first_index..first_index + count as usize;
range.into_iter().fold(Sats::ZERO, |total, inputindex| {
total
+ inputindex_to_value_iter
@@ -232,12 +228,13 @@ impl Vecs {
// let indexes_to_input_value: ComputedVecsFromTxindex<Sats> =
// ComputedVecsFromTxindex::forced_import(
// path,
// file,
// "input_value",
// true,
// version + VERSION + Version::ZERO,
// format,
// StorableVecGeneatorOptions::default()
// computation,
// StorableVecGeneatorOptions::default()
// .add_average()
// .add_sum()
// .add_cumulative(),
@@ -245,7 +242,7 @@ impl Vecs {
let txindex_to_output_value = ComputedVec::forced_import_or_init_from_3(
computation,
path,
&file,
"output_value",
version + VERSION + Version::ZERO,
format,
@@ -266,7 +263,7 @@ impl Vecs {
.unwrap()
.1
.into_owned();
let range = first_index..first_index + count;
let range = first_index..first_index + count as usize;
range.into_iter().fold(Sats::ZERO, |total, outputindex| {
total
+ outputindex_to_value_iter
@@ -281,20 +278,21 @@ impl Vecs {
// let indexes_to_output_value: ComputedVecsFromTxindex<Sats> =
// ComputedVecsFromTxindex::forced_import(
// path,
// file,
// "output_value",
// true,
// version + VERSION + Version::ZERO,
// format,
// StorableVecGeneatorOptions::default()
// computation,
// StorableVecGeneatorOptions::default()
// .add_average()
// .add_sum()
// .add_cumulative(),
// )?;
let txindex_to_fee = ComputedVecFrom2::forced_import_or_init_from_2(
computation,
path,
Computation::Eager,
&file,
"fee",
version + VERSION + Version::ZERO,
format,
@@ -316,8 +314,8 @@ impl Vecs {
)?;
let txindex_to_feerate = ComputedVecFrom2::forced_import_or_init_from_2(
computation,
path,
Computation::Eager,
&file,
"feerate",
version + VERSION + Version::ZERO,
format,
@@ -337,12 +335,14 @@ impl Vecs {
Ok(Self {
indexes_to_tx_count: ComputedVecsFromHeight::forced_import(
path,
&file,
"tx_count",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
computation,
indexes,
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
@@ -350,12 +350,14 @@ impl Vecs {
.add_cumulative(),
)?,
indexes_to_input_count: ComputedVecsFromTxindex::forced_import(
path,
&file,
"input_count",
false,
Source::None,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
computation,
indexes,
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
@@ -363,12 +365,14 @@ impl Vecs {
.add_cumulative(),
)?,
indexes_to_output_count: ComputedVecsFromTxindex::forced_import(
path,
&file,
"output_count",
false,
Source::None,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
computation,
indexes,
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
@@ -376,45 +380,45 @@ impl Vecs {
.add_cumulative(),
)?,
indexes_to_tx_v1: ComputedVecsFromHeight::forced_import(
path,
&file,
"tx_v1",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
.add_sum()
.add_cumulative(),
computation,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
)?,
indexes_to_tx_v2: ComputedVecsFromHeight::forced_import(
path,
&file,
"tx_v2",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
.add_sum()
.add_cumulative(),
computation,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
)?,
indexes_to_tx_v3: ComputedVecsFromHeight::forced_import(
path,
&file,
"tx_v3",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
.add_sum()
.add_cumulative(),
computation,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
)?,
indexes_to_fee: ComputedValueVecsFromTxindex::forced_import(
path,
&file,
"fee",
indexes,
Some(txindex_to_fee.boxed_clone()),
Source::Vec(txindex_to_fee.boxed_clone()),
version + VERSION + Version::ZERO,
computation,
format,
fetched,
StorableVecGeneatorOptions::default()
price,
VecBuilderOptions::default()
.add_sum()
.add_cumulative()
.add_percentiles()
@@ -422,84 +426,96 @@ impl Vecs {
.add_average(),
)?,
indexes_to_feerate: ComputedVecsFromTxindex::forced_import(
path,
&file,
"feerate",
false,
Source::None,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
computation,
indexes,
VecBuilderOptions::default()
.add_percentiles()
.add_minmax()
.add_average(),
)?,
indexes_to_tx_vsize: ComputedVecsFromTxindex::forced_import(
path,
&file,
"tx_vsize",
false,
Source::None,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
computation,
indexes,
VecBuilderOptions::default()
.add_percentiles()
.add_minmax()
.add_average(),
)?,
indexes_to_tx_weight: ComputedVecsFromTxindex::forced_import(
path,
&file,
"tx_weight",
false,
Source::None,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
computation,
indexes,
VecBuilderOptions::default()
.add_percentiles()
.add_minmax()
.add_average(),
)?,
indexes_to_subsidy: ComputedValueVecsFromHeight::forced_import(
path,
&file,
"subsidy",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
computation,
VecBuilderOptions::default()
.add_percentiles()
.add_sum()
.add_cumulative()
.add_minmax()
.add_average(),
compute_dollars,
indexes,
)?,
indexes_to_coinbase: ComputedValueVecsFromHeight::forced_import(
path,
&file,
"coinbase",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
computation,
VecBuilderOptions::default()
.add_sum()
.add_cumulative()
.add_percentiles()
.add_minmax()
.add_average(),
compute_dollars,
indexes,
)?,
indexes_to_unclaimed_rewards: ComputedValueVecsFromHeight::forced_import(
path,
&file,
"unclaimed_rewards",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
.add_sum()
.add_cumulative(),
computation,
VecBuilderOptions::default().add_sum().add_cumulative(),
compute_dollars,
indexes,
)?,
indexes_to_p2a_count: ComputedVecsFromHeight::forced_import(
path,
&file,
"p2a_count",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
computation,
indexes,
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
@@ -507,12 +523,14 @@ impl Vecs {
.add_cumulative(),
)?,
indexes_to_p2ms_count: ComputedVecsFromHeight::forced_import(
path,
&file,
"p2ms_count",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
computation,
indexes,
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
@@ -520,12 +538,14 @@ impl Vecs {
.add_cumulative(),
)?,
indexes_to_p2pk33_count: ComputedVecsFromHeight::forced_import(
path,
&file,
"p2pk33_count",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
computation,
indexes,
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
@@ -533,12 +553,14 @@ impl Vecs {
.add_cumulative(),
)?,
indexes_to_p2pk65_count: ComputedVecsFromHeight::forced_import(
path,
&file,
"p2pk65_count",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
computation,
indexes,
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
@@ -546,12 +568,14 @@ impl Vecs {
.add_cumulative(),
)?,
indexes_to_p2pkh_count: ComputedVecsFromHeight::forced_import(
path,
&file,
"p2pkh_count",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
computation,
indexes,
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
@@ -559,12 +583,14 @@ impl Vecs {
.add_cumulative(),
)?,
indexes_to_p2sh_count: ComputedVecsFromHeight::forced_import(
path,
&file,
"p2sh_count",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
computation,
indexes,
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
@@ -572,12 +598,14 @@ impl Vecs {
.add_cumulative(),
)?,
indexes_to_p2tr_count: ComputedVecsFromHeight::forced_import(
path,
&file,
"p2tr_count",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
computation,
indexes,
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
@@ -585,12 +613,14 @@ impl Vecs {
.add_cumulative(),
)?,
indexes_to_p2wpkh_count: ComputedVecsFromHeight::forced_import(
path,
&file,
"p2wpkh_count",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
computation,
indexes,
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
@@ -598,12 +628,14 @@ impl Vecs {
.add_cumulative(),
)?,
indexes_to_p2wsh_count: ComputedVecsFromHeight::forced_import(
path,
&file,
"p2wsh_count",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
computation,
indexes,
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
@@ -611,12 +643,14 @@ impl Vecs {
.add_cumulative(),
)?,
indexes_to_opreturn_count: ComputedVecsFromHeight::forced_import(
path,
&file,
"opreturn_count",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
computation,
indexes,
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
@@ -624,12 +658,14 @@ impl Vecs {
.add_cumulative(),
)?,
indexes_to_unknownoutput_count: ComputedVecsFromHeight::forced_import(
path,
&file,
"unknownoutput_count",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
computation,
indexes,
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
@@ -637,12 +673,14 @@ impl Vecs {
.add_cumulative(),
)?,
indexes_to_emptyoutput_count: ComputedVecsFromHeight::forced_import(
path,
&file,
"emptyoutput_count",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default()
computation,
indexes,
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
@@ -650,12 +688,14 @@ impl Vecs {
.add_cumulative(),
)?,
indexes_to_exact_utxo_count: ComputedVecsFromHeight::forced_import(
path,
&file,
"exact_utxo_count",
true,
Source::Compute,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_last(),
computation,
indexes,
VecBuilderOptions::default().add_last(),
)?,
txindex_to_is_coinbase,
inputindex_to_value,
@@ -667,6 +707,8 @@ impl Vecs {
txindex_to_feerate,
txindex_to_vsize,
txindex_to_weight,
file,
})
}
@@ -675,9 +717,22 @@ impl Vecs {
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
fetched: Option<&fetched::Vecs>,
price: Option<&price::Vecs>,
exit: &Exit,
) -> color_eyre::Result<()> {
) -> Result<()> {
self.compute_(indexer, indexes, starting_indexes, price, exit)?;
self.file.flush_then_punch()?;
Ok(())
}
fn compute_(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
price: Option<&price::Vecs>,
exit: &Exit,
) -> Result<()> {
self.indexes_to_tx_count.compute_all(
indexer,
indexes,
@@ -689,7 +744,8 @@ impl Vecs {
&indexer.vecs.height_to_first_txindex,
&indexer.vecs.txindex_to_txid,
exit,
)
)?;
Ok(())
},
)?;
@@ -710,7 +766,7 @@ impl Vecs {
)?;
let compute_indexes_to_tx_vany =
|indexes_to_tx_vany: &mut ComputedVecsFromHeight<StoredUsize>, txversion| {
|indexes_to_tx_vany: &mut ComputedVecsFromHeight<StoredU64>, txversion| {
let mut txindex_to_txversion_iter = indexer.vecs.txindex_to_txversion.iter();
indexes_to_tx_vany.compute_all(
indexer,
@@ -727,7 +783,8 @@ impl Vecs {
v == txversion
},
exit,
)
)?;
Ok(())
},
)
};
@@ -821,7 +878,7 @@ impl Vecs {
starting_indexes,
exit,
Some(&self.txindex_to_fee),
fetched,
price,
)?;
self.indexes_to_feerate.compute_rest(
@@ -851,7 +908,7 @@ impl Vecs {
self.indexes_to_coinbase.compute_all(
indexer,
indexes,
fetched,
price,
starting_indexes,
exit,
|vec, indexer, _, starting_indexes, exit| {
@@ -868,23 +925,23 @@ impl Vecs {
.unwrap_to_usize();
let output_count = txindex_to_output_count_iter.unwrap_get_inner(txindex);
let mut sats = Sats::ZERO;
(first_outputindex..first_outputindex + *output_count).for_each(
|outputindex| {
(first_outputindex..first_outputindex + usize::from(output_count))
.for_each(|outputindex| {
sats += outputindex_to_value_iter
.unwrap_get_inner(OutputIndex::from(outputindex));
},
);
});
(height, sats)
},
exit,
)
)?;
Ok(())
},
)?;
self.indexes_to_subsidy.compute_all(
indexer,
indexes,
fetched,
price,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
@@ -898,14 +955,15 @@ impl Vecs {
(height, coinbase.checked_sub(fees).unwrap())
},
exit,
)
)?;
Ok(())
},
)?;
self.indexes_to_unclaimed_rewards.compute_all(
indexer,
indexes,
fetched,
price,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
@@ -919,7 +977,8 @@ impl Vecs {
(height, expected.checked_sub(subsidy).unwrap())
},
exit,
)
)?;
Ok(())
},
)?;
@@ -934,7 +993,8 @@ impl Vecs {
&indexer.vecs.height_to_first_p2aaddressindex,
&indexer.vecs.p2aaddressindex_to_p2abytes,
exit,
)
)?;
Ok(())
},
)?;
@@ -949,7 +1009,8 @@ impl Vecs {
&indexer.vecs.height_to_first_p2msoutputindex,
&indexer.vecs.p2msoutputindex_to_txindex,
exit,
)
)?;
Ok(())
},
)?;
@@ -964,7 +1025,8 @@ impl Vecs {
&indexer.vecs.height_to_first_p2pk33addressindex,
&indexer.vecs.p2pk33addressindex_to_p2pk33bytes,
exit,
)
)?;
Ok(())
},
)?;
@@ -979,7 +1041,8 @@ impl Vecs {
&indexer.vecs.height_to_first_p2pk65addressindex,
&indexer.vecs.p2pk65addressindex_to_p2pk65bytes,
exit,
)
)?;
Ok(())
},
)?;
@@ -994,7 +1057,8 @@ impl Vecs {
&indexer.vecs.height_to_first_p2pkhaddressindex,
&indexer.vecs.p2pkhaddressindex_to_p2pkhbytes,
exit,
)
)?;
Ok(())
},
)?;
@@ -1009,7 +1073,8 @@ impl Vecs {
&indexer.vecs.height_to_first_p2shaddressindex,
&indexer.vecs.p2shaddressindex_to_p2shbytes,
exit,
)
)?;
Ok(())
},
)?;
@@ -1024,7 +1089,8 @@ impl Vecs {
&indexer.vecs.height_to_first_p2traddressindex,
&indexer.vecs.p2traddressindex_to_p2trbytes,
exit,
)
)?;
Ok(())
},
)?;
@@ -1039,7 +1105,8 @@ impl Vecs {
&indexer.vecs.height_to_first_p2wpkhaddressindex,
&indexer.vecs.p2wpkhaddressindex_to_p2wpkhbytes,
exit,
)
)?;
Ok(())
},
)?;
@@ -1054,7 +1121,8 @@ impl Vecs {
&indexer.vecs.height_to_first_p2wshaddressindex,
&indexer.vecs.p2wshaddressindex_to_p2wshbytes,
exit,
)
)?;
Ok(())
},
)?;
@@ -1069,7 +1137,8 @@ impl Vecs {
&indexer.vecs.height_to_first_opreturnindex,
&indexer.vecs.opreturnindex_to_txindex,
exit,
)
)?;
Ok(())
},
)?;
@@ -1084,7 +1153,8 @@ impl Vecs {
&indexer.vecs.height_to_first_unknownoutputindex,
&indexer.vecs.unknownoutputindex_to_txindex,
exit,
)
)?;
Ok(())
},
)?;
@@ -1099,7 +1169,8 @@ impl Vecs {
&indexer.vecs.height_to_first_emptyoutputindex,
&indexer.vecs.emptyoutputindex_to_txindex,
exit,
)
)?;
Ok(())
},
)?;
@@ -1125,7 +1196,7 @@ impl Vecs {
|(h, output_count, ..)| {
let input_count = input_count_iter.unwrap_get_inner(h);
let opreturn_count = opreturn_count_iter.unwrap_get_inner(h);
let block_count = usize::from(h + 1_usize);
let block_count = u64::from(h + 1_usize);
// -1 > genesis output is unspendable
let mut utxo_count =
*output_count - (*input_count - block_count) - *opreturn_count - 1;
@@ -1148,10 +1219,11 @@ impl Vecs {
utxo_count -= 1;
}
(h, StoredUsize::from(utxo_count))
(h, StoredU64::from(utxo_count))
},
exit,
)
)?;
Ok(())
},
)?;
@@ -1,218 +0,0 @@
use std::path::Path;
use brk_core::{
DateIndex, DecadeIndex, MonthIndex, QuarterIndex, Result, Version, WeekIndex, YearIndex,
};
use brk_exit::Exit;
use brk_indexer::Indexer;
use brk_vec::{AnyCollectableVec, AnyIterableVec, EagerVec, Format};
use crate::vecs::{Indexes, indexes};
use super::{ComputedType, ComputedVecBuilder, StorableVecGeneatorOptions};
#[derive(Clone)]
pub struct ComputedVecsFromDateIndex<T>
where
T: ComputedType + PartialOrd,
{
pub dateindex: Option<EagerVec<DateIndex, T>>,
pub dateindex_extra: ComputedVecBuilder<DateIndex, T>,
pub weekindex: ComputedVecBuilder<WeekIndex, T>,
pub monthindex: ComputedVecBuilder<MonthIndex, T>,
pub quarterindex: ComputedVecBuilder<QuarterIndex, T>,
pub yearindex: ComputedVecBuilder<YearIndex, T>,
pub decadeindex: ComputedVecBuilder<DecadeIndex, T>,
}
const VERSION: Version = Version::ZERO;
impl<T> ComputedVecsFromDateIndex<T>
where
T: ComputedType,
{
pub fn forced_import(
path: &Path,
name: &str,
compute_source: bool,
version: Version,
format: Format,
options: StorableVecGeneatorOptions,
) -> color_eyre::Result<Self> {
let dateindex = compute_source.then(|| {
EagerVec::forced_import(path, name, version + VERSION + Version::ZERO, format).unwrap()
});
let dateindex_extra = ComputedVecBuilder::forced_import(
path,
name,
version + VERSION + Version::ZERO,
format,
options.copy_self_extra(),
)?;
let options = options.remove_percentiles();
Ok(Self {
dateindex,
dateindex_extra,
weekindex: ComputedVecBuilder::forced_import(
path,
name,
version + VERSION + Version::ZERO,
format,
options,
)?,
monthindex: ComputedVecBuilder::forced_import(
path,
name,
version + VERSION + Version::ZERO,
format,
options,
)?,
quarterindex: ComputedVecBuilder::forced_import(
path,
name,
version + VERSION + Version::ZERO,
format,
options,
)?,
yearindex: ComputedVecBuilder::forced_import(
path,
name,
version + VERSION + Version::ZERO,
format,
options,
)?,
decadeindex: ComputedVecBuilder::forced_import(
path,
name,
version + VERSION + Version::ZERO,
format,
options,
)?,
})
}
pub fn compute_all<F>(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
mut compute: F,
) -> color_eyre::Result<()>
where
F: FnMut(
&mut EagerVec<DateIndex, T>,
&Indexer,
&indexes::Vecs,
&Indexes,
&Exit,
) -> Result<()>,
{
compute(
self.dateindex.as_mut().unwrap(),
indexer,
indexes,
starting_indexes,
exit,
)?;
let dateindex: Option<&EagerVec<DateIndex, T>> = None;
self.compute_rest(indexes, starting_indexes, exit, dateindex)
}
pub fn compute_rest(
&mut self,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
dateindex: Option<&impl AnyIterableVec<DateIndex, T>>,
) -> color_eyre::Result<()> {
if let Some(dateindex) = dateindex {
self.dateindex_extra
.extend(starting_indexes.dateindex, dateindex, exit)?;
self.weekindex.compute(
starting_indexes.weekindex,
dateindex,
&indexes.weekindex_to_first_dateindex,
&indexes.weekindex_to_dateindex_count,
exit,
)?;
self.monthindex.compute(
starting_indexes.monthindex,
dateindex,
&indexes.monthindex_to_first_dateindex,
&indexes.monthindex_to_dateindex_count,
exit,
)?;
} else {
let dateindex = self.dateindex.as_ref().unwrap();
self.dateindex_extra
.extend(starting_indexes.dateindex, dateindex, exit)?;
self.weekindex.compute(
starting_indexes.weekindex,
dateindex,
&indexes.weekindex_to_first_dateindex,
&indexes.weekindex_to_dateindex_count,
exit,
)?;
self.monthindex.compute(
starting_indexes.monthindex,
dateindex,
&indexes.monthindex_to_first_dateindex,
&indexes.monthindex_to_dateindex_count,
exit,
)?;
}
self.quarterindex.from_aligned(
starting_indexes.quarterindex,
&self.monthindex,
&indexes.quarterindex_to_first_monthindex,
&indexes.quarterindex_to_monthindex_count,
exit,
)?;
self.yearindex.from_aligned(
starting_indexes.yearindex,
&self.monthindex,
&indexes.yearindex_to_first_monthindex,
&indexes.yearindex_to_monthindex_count,
exit,
)?;
self.decadeindex.from_aligned(
starting_indexes.decadeindex,
&self.yearindex,
&indexes.decadeindex_to_first_yearindex,
&indexes.decadeindex_to_yearindex_count,
exit,
)?;
Ok(())
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
[
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.yearindex.vecs(),
self.decadeindex.vecs(),
]
.into_iter()
.flatten()
.collect::<Vec<_>>()
}
}
File diff suppressed because it is too large Load Diff
@@ -1,13 +0,0 @@
use std::ops::{Add, Div};
use brk_vec::StoredType;
pub trait ComputedType
where
Self: StoredType + From<usize> + Div<usize, Output = Self> + Add<Output = Self> + Ord,
{
}
impl<T> ComputedType for T where
T: StoredType + From<usize> + Div<usize, Output = Self> + Add<Output = Self> + Ord
{
}
-216
View File
@@ -1,216 +0,0 @@
use std::path::Path;
use brk_core::Version;
use brk_exit::Exit;
use brk_fetcher::Fetcher;
use brk_indexer::Indexer;
use brk_vec::{AnyCollectableVec, Computation, Format};
pub mod blocks;
pub mod cointime;
pub mod constants;
pub mod fetched;
pub mod grouped;
pub mod indexes;
pub mod market;
pub mod mining;
pub mod stateful;
pub mod transactions;
pub use indexes::Indexes;
use log::info;
use crate::stores::Stores;
const VERSION: Version = Version::ONE;
#[derive(Clone)]
pub struct Vecs {
pub indexes: indexes::Vecs,
pub constants: constants::Vecs,
pub blocks: blocks::Vecs,
pub mining: mining::Vecs,
pub market: market::Vecs,
pub transactions: transactions::Vecs,
pub stateful: stateful::Vecs,
pub fetched: Option<fetched::Vecs>,
pub cointime: cointime::Vecs,
}
impl Vecs {
pub fn import(
path: &Path,
version: Version,
indexer: &Indexer,
fetch: bool,
computation: Computation,
format: Format,
) -> color_eyre::Result<Self> {
let indexes = indexes::Vecs::forced_import(
path,
version + VERSION + Version::ZERO,
indexer,
computation,
format,
)?;
let fetched = fetch.then(|| {
fetched::Vecs::forced_import(
path,
version + VERSION + Version::ZERO,
computation,
format,
)
.unwrap()
});
Ok(Self {
blocks: blocks::Vecs::forced_import(
path,
version + VERSION + Version::ZERO,
computation,
format,
)?,
mining: mining::Vecs::forced_import(
path,
version + VERSION + Version::ZERO,
computation,
format,
)?,
constants: constants::Vecs::forced_import(
path,
version + VERSION + Version::ZERO,
computation,
format,
)?,
market: market::Vecs::forced_import(
path,
version + VERSION + Version::ZERO,
computation,
format,
)?,
stateful: stateful::Vecs::forced_import(
path,
version + VERSION + Version::ZERO,
computation,
format,
fetched.as_ref(),
)?,
transactions: transactions::Vecs::forced_import(
path,
version + VERSION + Version::ZERO,
indexer,
&indexes,
computation,
format,
fetched.as_ref(),
)?,
cointime: cointime::Vecs::forced_import(
path,
version + VERSION + Version::ZERO,
computation,
format,
fetched.as_ref(),
)?,
indexes,
fetched,
})
}
pub fn compute(
&mut self,
indexer: &Indexer,
starting_indexes: brk_indexer::Indexes,
fetcher: Option<&mut Fetcher>,
exit: &Exit,
stores: &mut Stores,
) -> color_eyre::Result<()> {
info!("Computing indexes...");
let mut starting_indexes = self.indexes.compute(indexer, starting_indexes, exit)?;
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)?;
if let Some(fetched) = self.fetched.as_mut() {
info!("Computing fetched...");
fetched.compute(
indexer,
&self.indexes,
&starting_indexes,
fetcher.unwrap(),
exit,
)?;
}
info!("Computing transactions...");
self.transactions.compute(
indexer,
&self.indexes,
&starting_indexes,
self.fetched.as_ref(),
exit,
)?;
if let Some(fetched) = self.fetched.as_ref() {
info!("Computing market...");
self.market.compute(
indexer,
&self.indexes,
fetched,
&mut self.transactions,
&starting_indexes,
exit,
)?;
}
info!("Computing stateful...");
self.stateful.compute(
indexer,
&self.indexes,
&self.transactions,
self.fetched.as_ref(),
&self.market,
&mut starting_indexes,
exit,
stores,
)?;
self.cointime.compute(
indexer,
&self.indexes,
&starting_indexes,
self.fetched.as_ref(),
&self.transactions,
&self.stateful,
exit,
)?;
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()),
]
.into_iter()
.flatten()
.collect::<Vec<_>>()
}
}
@@ -1,30 +0,0 @@
use std::mem;
use derive_deref::{Deref, DerefMut};
use super::ByAddressType;
#[derive(Debug, Default, Deref, DerefMut)]
pub struct AddressTypeToVec<T>(ByAddressType<Vec<T>>);
impl<T> AddressTypeToVec<T> {
pub fn merge(&mut self, mut other: Self) {
Self::merge_(&mut self.p2pk65, &mut other.p2pk65);
Self::merge_(&mut self.p2pk33, &mut other.p2pk33);
Self::merge_(&mut self.p2pkh, &mut other.p2pkh);
Self::merge_(&mut self.p2sh, &mut other.p2sh);
Self::merge_(&mut self.p2wpkh, &mut other.p2wpkh);
Self::merge_(&mut self.p2wsh, &mut other.p2wsh);
Self::merge_(&mut self.p2tr, &mut other.p2tr);
Self::merge_(&mut self.p2a, &mut other.p2a);
}
fn merge_(own: &mut Vec<T>, other: &mut Vec<T>) {
if own.len() >= other.len() {
own.append(other);
} else {
other.append(own);
mem::swap(own, other);
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,62 +0,0 @@
use brk_core::{AddressData, EmptyAddressData};
#[derive(Debug)]
pub enum WithAddressDataSource<T> {
New(T),
FromAddressDataStore(T),
FromEmptyAddressDataStore(T),
}
impl<T> WithAddressDataSource<T> {
pub fn is_new(&self) -> bool {
matches!(self, Self::New(_))
}
pub fn is_from_addressdata(&self) -> bool {
matches!(self, Self::FromAddressDataStore(_))
}
pub fn is_from_emptyaddressdata(&self) -> bool {
matches!(self, Self::FromEmptyAddressDataStore(_))
}
pub fn deref(&self) -> &T {
match self {
Self::New(v) => v,
Self::FromAddressDataStore(v) => v,
Self::FromEmptyAddressDataStore(v) => v,
}
}
pub fn deref_mut(&mut self) -> &mut T {
match self {
Self::New(v) => v,
Self::FromAddressDataStore(v) => v,
Self::FromEmptyAddressDataStore(v) => v,
}
}
}
impl From<WithAddressDataSource<EmptyAddressData>> for WithAddressDataSource<AddressData> {
fn from(value: WithAddressDataSource<EmptyAddressData>) -> Self {
match value {
WithAddressDataSource::New(v) => Self::New(v.into()),
WithAddressDataSource::FromAddressDataStore(v) => Self::FromAddressDataStore(v.into()),
WithAddressDataSource::FromEmptyAddressDataStore(v) => {
Self::FromEmptyAddressDataStore(v.into())
}
}
}
}
impl From<WithAddressDataSource<AddressData>> for WithAddressDataSource<EmptyAddressData> {
fn from(value: WithAddressDataSource<AddressData>) -> Self {
match value {
WithAddressDataSource::New(v) => Self::New(v.into()),
WithAddressDataSource::FromAddressDataStore(v) => Self::FromAddressDataStore(v.into()),
WithAddressDataSource::FromEmptyAddressDataStore(v) => {
Self::FromEmptyAddressDataStore(v.into())
}
}
}
}
-142
View File
@@ -1,142 +0,0 @@
use std::{
fmt::{self, Debug},
io, result, time,
};
use crate::Version;
pub type Result<T, E = Error> = result::Result<T, E>;
#[derive(Debug)]
pub enum Error {
IO(io::Error),
SerdeJson(serde_json::Error),
Jiff(jiff::Error),
Fjall(fjall::Error),
SystemTimeError(time::SystemTimeError),
ZeroCopyError,
BincodeEncodeError(bincode::error::EncodeError),
BincodeDecodeError(bincode::error::DecodeError),
WrongEndian,
DifferentVersion { found: Version, expected: Version },
UnexpectedData,
MmapsVecIsTooSmall,
IndexTooHigh,
EmptyVec,
IndexTooLow,
ExpectFileToHaveIndex,
ExpectVecToHaveIndex,
FailedKeyTryIntoUsize,
UnsupportedUnflushedState,
RangeFromAfterTo(usize, usize),
DifferentCompressionMode,
WrongLength,
WrongAddressType,
UnindexableDate,
String(&'static str),
}
impl From<time::SystemTimeError> for Error {
fn from(value: time::SystemTimeError) -> Self {
Self::SystemTimeError(value)
}
}
impl From<io::Error> for Error {
fn from(value: io::Error) -> Self {
Self::IO(value)
}
}
impl From<jiff::Error> for Error {
fn from(value: jiff::Error) -> Self {
Self::Jiff(value)
}
}
impl From<fjall::Error> for Error {
fn from(value: fjall::Error) -> Self {
Self::Fjall(value)
}
}
impl<A, B, C> From<zerocopy::error::ConvertError<A, B, C>> for Error {
fn from(_: zerocopy::error::ConvertError<A, B, C>) -> Self {
Self::ZeroCopyError
}
}
impl<A, B> From<zerocopy::error::SizeError<A, B>> for Error {
fn from(_: zerocopy::error::SizeError<A, B>) -> Self {
Self::ZeroCopyError
}
}
impl From<serde_json::Error> for Error {
fn from(error: serde_json::Error) -> Self {
Self::SerdeJson(error)
}
}
impl From<bincode::error::DecodeError> for Error {
fn from(error: bincode::error::DecodeError) -> Self {
Self::BincodeDecodeError(error)
}
}
impl From<bincode::error::EncodeError> for Error {
fn from(error: bincode::error::EncodeError) -> Self {
Self::BincodeEncodeError(error)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::IO(error) => Debug::fmt(&error, f),
Error::SystemTimeError(error) => Debug::fmt(&error, f),
Error::SerdeJson(error) => Debug::fmt(&error, f),
Error::Jiff(error) => Debug::fmt(&error, f),
Error::Fjall(error) => Debug::fmt(&error, f),
Error::BincodeDecodeError(error) => Debug::fmt(&error, f),
Error::BincodeEncodeError(error) => Debug::fmt(&error, f),
Error::ZeroCopyError => write!(f, "ZeroCopy error"),
Error::UnexpectedData => write!(f, "Unexpected data"),
Error::WrongEndian => write!(f, "Wrong endian"),
Error::DifferentVersion { found, expected } => {
write!(
f,
"Different version found: {found:?}, expected: {expected:?}"
)
}
Error::MmapsVecIsTooSmall => write!(f, "Mmaps vec is too small"),
Error::IndexTooHigh => write!(f, "Index too high"),
Error::IndexTooLow => write!(f, "Index too low"),
Error::ExpectFileToHaveIndex => write!(f, "Expect file to have index"),
Error::ExpectVecToHaveIndex => write!(f, "Expect vec to have index"),
Error::FailedKeyTryIntoUsize => write!(f, "Failed to convert key to usize"),
Error::UnsupportedUnflushedState => {
write!(
f,
"Unsupported unflush state, please flush before using this function"
)
}
Error::RangeFromAfterTo(from, to) => write!(f, "Range, from {from} is after to {to}"),
Error::DifferentCompressionMode => write!(f, "Different compression mode chosen"),
Error::EmptyVec => write!(f, "The Vec is empty, maybe wait for a bit"),
Error::WrongLength => write!(f, "Wrong length"),
Error::WrongAddressType => write!(f, "Wrong address type"),
Error::UnindexableDate => write!(
f,
"Date cannot be indexed, must be 2009-01-03, 2009-01-09 or greater"
),
Error::String(s) => write!(f, "{s}"),
}
}
}
impl std::error::Error for Error {}
@@ -1,89 +0,0 @@
use std::ops::Add;
use byteview::ByteView;
use serde::Serialize;
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
use crate::Error;
#[derive(
Debug,
PartialEq,
Eq,
PartialOrd,
Ord,
Clone,
Copy,
Default,
FromBytes,
Immutable,
IntoBytes,
KnownLayout,
Serialize,
)]
pub struct AddressIndex(u32);
impl AddressIndex {
pub const BYTES: usize = size_of::<Self>();
pub fn increment(&mut self) {
self.0 += 1;
}
pub fn incremented(self) -> Self {
Self(self.0 + 1)
}
}
impl From<u32> for AddressIndex {
fn from(value: u32) -> Self {
Self(value)
}
}
impl From<u64> for AddressIndex {
fn from(value: u64) -> Self {
Self(value as u32)
}
}
impl From<AddressIndex> for u64 {
fn from(value: AddressIndex) -> Self {
value.0 as u64
}
}
impl From<usize> for AddressIndex {
fn from(value: usize) -> Self {
Self(value as u32)
}
}
impl From<AddressIndex> for usize {
fn from(value: AddressIndex) -> Self {
value.0 as usize
}
}
impl From<ByteView> for AddressIndex {
fn from(value: ByteView) -> Self {
Ok(Self::read_from_bytes(&value)?)
}
}
impl From<AddressIndex> for ByteView {
fn from(value: AddressIndex) -> Self {
Self::new(value.as_bytes())
}
}
impl Add<usize> for AddressIndex {
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
Self(self.0 + rhs as u32)
}
}
impl Add<AddressIndex> for AddressIndex {
type Output = Self;
fn add(self, rhs: AddressIndex) -> Self::Output {
Self(self.0 + rhs.0)
}
}
@@ -1,27 +0,0 @@
use byteview::ByteView;
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
use crate::Error;
use super::{AddressIndex, Outputindex};
#[derive(
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Immutable, IntoBytes, KnownLayout, FromBytes,
)]
#[repr(C)]
pub struct AddressIndexOutputIndex {
addressindex: AddressIndex,
_padding: u32,
outputindex: Outputindex,
}
impl From<ByteView> for AddressIndexOutputIndex {
fn from(value: ByteView) -> Self {
Ok(Self::read_from_bytes(&value)?)
}
}
impl From<AddressIndexOutputIndex> for ByteView {
fn from(value: AddressIndexOutputIndex) -> Self {
Self::new(value.as_bytes())
}
}
@@ -1,48 +0,0 @@
use serde::Serialize;
use zerocopy_derive::{Immutable, IntoBytes, KnownLayout, TryFromBytes};
use super::OutputType;
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
TryFromBytes,
Immutable,
IntoBytes,
KnownLayout,
Serialize,
)]
#[repr(u8)]
pub enum AddressType {
P2PK65,
P2PK33,
P2PKH,
P2SH,
P2WPKH,
P2WSH,
P2TR,
P2A,
}
impl From<OutputType> for AddressType {
fn from(value: OutputType) -> Self {
match value {
OutputType::P2A => Self::P2A,
OutputType::P2PK33 => Self::P2PK33,
OutputType::P2PK65 => Self::P2PK65,
OutputType::P2PKH => Self::P2PKH,
OutputType::P2SH => Self::P2SH,
OutputType::P2TR => Self::P2TR,
OutputType::P2WPKH => Self::P2WPKH,
OutputType::P2WSH => Self::P2WSH,
OutputType::Empty | OutputType::OpReturn | OutputType::P2MS | OutputType::Unknown => {
unreachable!()
}
}
}
}
-105
View File
@@ -1,105 +0,0 @@
use std::{
fmt,
ops::{Add, Rem},
};
use serde::Serialize;
// use color_eyre::eyre::eyre;
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
use crate::{CheckedSub, Error, Printable};
use super::Date;
#[derive(
Debug,
Default,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
FromBytes,
Immutable,
IntoBytes,
KnownLayout,
Serialize,
)]
pub struct DateIndex(u16);
impl DateIndex {
pub const BYTES: usize = size_of::<Self>();
}
impl From<DateIndex> for usize {
fn from(value: DateIndex) -> Self {
value.0 as usize
}
}
impl From<usize> for DateIndex {
fn from(value: usize) -> Self {
Self(value as u16)
}
}
impl From<DateIndex> for i64 {
fn from(value: DateIndex) -> Self {
value.0 as i64
}
}
impl Add<usize> for DateIndex {
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
Self(self.0 + rhs as u16)
}
}
impl TryFrom<Date> for DateIndex {
type Error = Error;
fn try_from(value: Date) -> Result<Self, Self::Error> {
let value_ = jiff::civil::Date::from(value);
if value_ < Date::INDEX_ZERO_ {
Err(Error::UnindexableDate)
} else if value == Date::INDEX_ZERO {
Ok(Self(0))
} else if value_ < Date::INDEX_ONE_ {
Err(Error::UnindexableDate)
} else if value == Date::INDEX_ONE {
Ok(Self(1))
} else {
Ok(Self(Date::INDEX_ONE_.until(value_)?.get_days() as u16 + 1))
}
}
}
impl CheckedSub for DateIndex {
fn checked_sub(self, rhs: Self) -> Option<Self> {
self.0.checked_sub(rhs.0).map(Self)
}
}
impl Rem<usize> for DateIndex {
type Output = Self;
fn rem(self, rhs: usize) -> Self::Output {
Self(self.0 % rhs as u16)
}
}
impl fmt::Display for DateIndex {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl Printable for DateIndex {
fn to_string() -> &'static str {
"dateindex"
}
fn to_possible_strings() -> &'static [&'static str] {
&["d", "date", "dateindex"]
}
}
@@ -1,44 +0,0 @@
use byteview::ByteView;
use zerocopy::{FromBytes, IntoBytes};
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
use crate::{AddressData, Sats};
#[derive(Debug, Default, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
pub struct EmptyAddressData {
pub transfered: Sats,
}
impl From<AddressData> for EmptyAddressData {
fn from(value: AddressData) -> Self {
Self::from(&value)
}
}
impl From<&AddressData> for EmptyAddressData {
fn from(value: &AddressData) -> Self {
if value.sent != value.received {
dbg!(&value);
panic!("Trying to convert not empty wallet to empty !");
}
Self {
transfered: value.sent,
}
}
}
impl From<ByteView> for EmptyAddressData {
fn from(value: ByteView) -> Self {
Self::read_from_bytes(&value).unwrap()
}
}
impl From<EmptyAddressData> for ByteView {
fn from(value: EmptyAddressData) -> Self {
Self::from(&value)
}
}
impl From<&EmptyAddressData> for ByteView {
fn from(value: &EmptyAddressData) -> Self {
Self::new(value.as_bytes())
}
}
-135
View File
@@ -1,135 +0,0 @@
use bitcoin::{ScriptBuf, opcodes::all::OP_PUSHBYTES_2};
use serde::Serialize;
use zerocopy_derive::{Immutable, IntoBytes, KnownLayout, TryFromBytes};
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
TryFromBytes,
Immutable,
IntoBytes,
KnownLayout,
Serialize,
)]
#[repr(u8)]
pub enum OutputType {
P2PK65,
P2PK33,
P2PKH,
P2MS,
P2SH,
OpReturn,
P2WPKH,
P2WSH,
P2TR,
P2A,
Empty = 254,
Unknown = 255,
}
impl OutputType {
pub fn is_spendable(&self) -> bool {
match self {
Self::P2PK65 => true,
Self::P2PK33 => true,
Self::P2PKH => true,
Self::P2MS => true,
Self::P2SH => true,
Self::OpReturn => false,
Self::P2WPKH => true,
Self::P2WSH => true,
Self::P2TR => true,
Self::P2A => true,
Self::Empty => true,
Self::Unknown => true,
}
}
pub fn is_address(&self) -> bool {
match self {
Self::P2PK65 => true,
Self::P2PK33 => true,
Self::P2PKH => true,
Self::P2MS => false,
Self::P2SH => true,
Self::OpReturn => false,
Self::P2WPKH => true,
Self::P2WSH => true,
Self::P2TR => true,
Self::P2A => true,
Self::Empty => false,
Self::Unknown => false,
}
}
pub fn is_not_address(&self) -> bool {
!self.is_address()
}
pub fn is_unspendable(&self) -> bool {
!self.is_spendable()
}
pub fn as_vec() -> Vec<Self> {
vec![
Self::P2PK65,
Self::P2PK33,
Self::P2PKH,
Self::P2MS,
Self::P2SH,
Self::OpReturn,
Self::P2WPKH,
Self::P2WSH,
Self::P2TR,
Self::P2A,
Self::Empty,
Self::Unknown,
]
}
}
impl From<&ScriptBuf> for OutputType {
fn from(script: &ScriptBuf) -> Self {
if script.is_p2pk() {
let bytes = script.as_bytes();
match bytes.len() {
67 => Self::P2PK65,
35 => Self::P2PK33,
_ => {
dbg!(bytes);
unreachable!()
}
}
} else if script.is_p2pkh() {
Self::P2PKH
} else if script.is_multisig() {
Self::P2MS
} else if script.is_p2sh() {
Self::P2SH
} else if script.is_op_return() {
Self::OpReturn
} else if script.is_p2wpkh() {
Self::P2WPKH
} else if script.is_p2wsh() {
Self::P2WSH
} else if script.is_p2tr() {
Self::P2TR
} else if script.witness_version() == Some(bitcoin::WitnessVersion::V1)
&& script.len() == 4
&& script.as_bytes()[1] == OP_PUSHBYTES_2.to_u8()
&& script.as_bytes()[2..4] == [78, 115]
{
Self::P2A
} else if script.is_empty() {
Self::Empty
} else {
Self::Unknown
}
}
}
-109
View File
@@ -1,109 +0,0 @@
use std::ops::{Add, Div};
use derive_deref::Deref;
use serde::Serialize;
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
use crate::{CheckedSub, Printable};
use super::{InputIndex, OutputIndex, TxIndex};
#[derive(
Debug,
Deref,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
FromBytes,
Immutable,
IntoBytes,
KnownLayout,
Serialize,
)]
pub struct StoredU64(u64);
impl StoredU64 {
pub const ZERO: Self = Self(0);
pub fn new(counter: u64) -> Self {
Self(counter)
}
}
impl From<u64> for StoredU64 {
fn from(value: u64) -> Self {
Self(value)
}
}
impl From<usize> for StoredU64 {
fn from(value: usize) -> Self {
Self(value as u64)
}
}
impl CheckedSub<StoredU64> for StoredU64 {
fn checked_sub(self, rhs: Self) -> Option<Self> {
self.0.checked_sub(rhs.0).map(Self)
}
}
impl Div<usize> for StoredU64 {
type Output = Self;
fn div(self, rhs: usize) -> Self::Output {
Self(self.0 / rhs as u64)
}
}
impl Add for StoredU64 {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0)
}
}
impl From<f64> for StoredU64 {
fn from(value: f64) -> Self {
if value < 0.0 || value > u32::MAX as f64 {
panic!()
}
Self(value as u64)
}
}
impl From<StoredU64> for f64 {
fn from(value: StoredU64) -> Self {
value.0 as f64
}
}
impl From<TxIndex> for StoredU64 {
fn from(value: TxIndex) -> Self {
Self(*value as u64)
}
}
impl From<InputIndex> for StoredU64 {
fn from(value: InputIndex) -> Self {
Self(*value)
}
}
impl From<OutputIndex> for StoredU64 {
fn from(value: OutputIndex) -> Self {
Self(*value)
}
}
impl Printable for StoredU64 {
fn to_string() -> &'static str {
"u64"
}
fn to_possible_strings() -> &'static [&'static str] {
&["u64"]
}
}
-211
View File
@@ -1,211 +0,0 @@
use std::ops::{Add, Div};
use derive_deref::{Deref, DerefMut};
use serde::Serialize;
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
use crate::{CheckedSub, Printable};
use super::{
DateIndex, EmptyOutputIndex, Height, InputIndex, MonthIndex, OpReturnIndex, OutputIndex,
P2AAddressIndex, P2MSOutputIndex, P2PK33AddressIndex, P2PK65AddressIndex, P2PKHAddressIndex,
P2SHAddressIndex, P2TRAddressIndex, P2WPKHAddressIndex, P2WSHAddressIndex, TxIndex,
UnknownOutputIndex, YearIndex,
};
#[derive(
Debug,
Deref,
DerefMut,
Clone,
Default,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
FromBytes,
Immutable,
IntoBytes,
KnownLayout,
Serialize,
)]
pub struct StoredUsize(usize);
impl StoredUsize {
pub const ZERO: Self = Self(0);
pub fn new(counter: usize) -> Self {
Self(counter)
}
}
impl From<usize> for StoredUsize {
fn from(value: usize) -> Self {
Self(value)
}
}
impl From<StoredUsize> for usize {
fn from(value: StoredUsize) -> Self {
*value
}
}
impl CheckedSub<StoredUsize> for StoredUsize {
fn checked_sub(self, rhs: Self) -> Option<Self> {
self.0.checked_sub(rhs.0).map(Self)
}
}
impl Div<usize> for StoredUsize {
type Output = Self;
fn div(self, rhs: usize) -> Self::Output {
Self(self.0 / rhs)
}
}
impl Add for StoredUsize {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0)
}
}
impl From<f64> for StoredUsize {
fn from(value: f64) -> Self {
if value < 0.0 || value > u32::MAX as f64 {
panic!()
}
Self(value as usize)
}
}
impl From<StoredUsize> for f64 {
fn from(value: StoredUsize) -> Self {
value.0 as f64
}
}
impl From<Height> for StoredUsize {
fn from(value: Height) -> Self {
Self::from(usize::from(value))
}
}
impl From<DateIndex> for StoredUsize {
fn from(value: DateIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<MonthIndex> for StoredUsize {
fn from(value: MonthIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<YearIndex> for StoredUsize {
fn from(value: YearIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<OutputIndex> for StoredUsize {
fn from(value: OutputIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<InputIndex> for StoredUsize {
fn from(value: InputIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<TxIndex> for StoredUsize {
fn from(value: TxIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<P2PK65AddressIndex> for StoredUsize {
fn from(value: P2PK65AddressIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<P2PK33AddressIndex> for StoredUsize {
fn from(value: P2PK33AddressIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<P2PKHAddressIndex> for StoredUsize {
fn from(value: P2PKHAddressIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<OpReturnIndex> for StoredUsize {
fn from(value: OpReturnIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<P2MSOutputIndex> for StoredUsize {
fn from(value: P2MSOutputIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<P2SHAddressIndex> for StoredUsize {
fn from(value: P2SHAddressIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<P2WSHAddressIndex> for StoredUsize {
fn from(value: P2WSHAddressIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<P2WPKHAddressIndex> for StoredUsize {
fn from(value: P2WPKHAddressIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<P2TRAddressIndex> for StoredUsize {
fn from(value: P2TRAddressIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<P2AAddressIndex> for StoredUsize {
fn from(value: P2AAddressIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<UnknownOutputIndex> for StoredUsize {
fn from(value: UnknownOutputIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<EmptyOutputIndex> for StoredUsize {
fn from(value: EmptyOutputIndex) -> Self {
Self::from(usize::from(value))
}
}
impl Printable for StoredUsize {
fn to_string() -> &'static str {
"usize"
}
fn to_possible_strings() -> &'static [&'static str] {
&["usize"]
}
}
-3
View File
@@ -1,3 +0,0 @@
mod printable;
pub use printable::*;
-4
View File
@@ -1,4 +0,0 @@
pub trait Printable {
fn to_string() -> &'static str;
fn to_possible_strings() -> &'static [&'static str];
}
-27
View File
@@ -1,27 +0,0 @@
use crate::{Error, Result};
#[allow(clippy::result_unit_err)]
pub fn copy_first_4bytes(slice: &[u8]) -> Result<[u8; 4]> {
let mut buf: [u8; 4] = [0; 4];
let buf_len = buf.len();
if slice.len() < buf_len {
return Err(Error::String("Buffer is too small to convert to 8 bytes"));
}
slice.iter().take(buf_len).enumerate().for_each(|(i, r)| {
buf[i] = *r;
});
Ok(buf)
}
#[allow(clippy::result_unit_err)]
pub fn copy_first_8bytes(slice: &[u8]) -> Result<[u8; 8]> {
let mut buf: [u8; 8] = [0; 8];
let buf_len = buf.len();
if slice.len() < buf_len {
return Err(Error::String("Buffer is too small to convert to 8 bytes"));
}
slice.iter().take(buf_len).enumerate().for_each(|(i, r)| {
buf[i] = *r;
});
Ok(buf)
}

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