mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-24 21:24:29 -07:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b1dcad86b4 | |||
| 9b6124074d | |||
| 02cbaa1e80 | |||
| a12f1321c7 | |||
| 8b67f592ac | |||
| 319d17b337 | |||
| 476eaa85da | |||
| d26099855c | |||
| e47456da17 | |||
| a464d5d0b6 | |||
| 1cfb7b5615 | |||
| ac7c2f3d03 | |||
| 638d9e6e01 | |||
| 8b9df2a396 | |||
| d7fe911bde | |||
| 0acc3d511b | |||
| 4cf465f419 | |||
| b686d317a9 | |||
| dcef541852 | |||
| abdd733f11 | |||
| 942431e882 | |||
| 1c75ea046c | |||
| f32b6daa51 | |||
| 3736d6ba5e | |||
| 9788b01f35 | |||
| 9aec991da6 | |||
| 910701ce04 | |||
| 34b462d511 | |||
| 139e93b2f0 | |||
| 0dd7e9359e | |||
| 41cf0225e3 | |||
| 962254e511 | |||
| a7f2b24bac | |||
| 1323d988af | |||
| 7c49e5c749 | |||
| cd69ec4fa3 | |||
| 4c7e9fbee2 | |||
| 1639df5616 | |||
| 810cdbd790 | |||
| 0d4f4aec4e | |||
| 6b1863d3b4 | |||
| 27f5a3b16b | |||
| 876cd8291b |
@@ -0,0 +1,291 @@
|
||||
# This file was autogenerated by dist: https://opensource.axo.dev/cargo-dist/
|
||||
#
|
||||
# Copyright 2022-2024, axodotdev
|
||||
# SPDX-License-Identifier: MIT or Apache-2.0
|
||||
#
|
||||
# CI that:
|
||||
#
|
||||
# * checks for a Git Tag that looks like a release
|
||||
# * builds artifacts with dist (archives, installers, hashes)
|
||||
# * uploads those artifacts to temporary workflow zip
|
||||
# * on success, uploads the artifacts to a GitHub Release
|
||||
#
|
||||
# Note that the GitHub Release will be created with a generated
|
||||
# title/body based on your changelogs.
|
||||
|
||||
name: Release
|
||||
permissions:
|
||||
"contents": "write"
|
||||
|
||||
# This task will run whenever you push a git tag that looks like a version
|
||||
# like "1.0.0", "v0.1.0-prerelease.1", "my-app/0.1.0", "releases/v1.0.0", etc.
|
||||
# Various formats will be parsed into a VERSION and an optional PACKAGE_NAME, where
|
||||
# PACKAGE_NAME must be the name of a Cargo package in your workspace, and VERSION
|
||||
# must be a Cargo-style SemVer Version (must have at least major.minor.patch).
|
||||
#
|
||||
# If PACKAGE_NAME is specified, then the announcement will be for that
|
||||
# package (erroring out if it doesn't have the given version or isn't dist-able).
|
||||
#
|
||||
# If PACKAGE_NAME isn't specified, then the announcement will be for all
|
||||
# (dist-able) packages in the workspace with that version (this mode is
|
||||
# intended for workspaces with only one dist-able package, or with all dist-able
|
||||
# packages versioned/released in lockstep).
|
||||
#
|
||||
# If you push multiple tags at once, separate instances of this workflow will
|
||||
# spin up, creating an independent announcement for each one. However, GitHub
|
||||
# will hard limit this to 3 tags per commit, as it will assume more tags is a
|
||||
# mistake.
|
||||
#
|
||||
# If there's a prerelease-style suffix to the version, then the release(s)
|
||||
# will be marked as a prerelease.
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
tags:
|
||||
- '**[0-9]+.[0-9]+.[0-9]+*'
|
||||
|
||||
jobs:
|
||||
# Run 'dist plan' (or host) to determine what tasks we need to do
|
||||
plan:
|
||||
runs-on: "ubuntu-latest"
|
||||
outputs:
|
||||
val: ${{ steps.plan.outputs.manifest }}
|
||||
tag: ${{ !github.event.pull_request && github.ref_name || '' }}
|
||||
tag-flag: ${{ !github.event.pull_request && format('--tag={0}', github.ref_name) || '' }}
|
||||
publishing: ${{ !github.event.pull_request }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
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"
|
||||
- name: Cache dist
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cargo-dist-cache
|
||||
path: ~/.cargo/bin/dist
|
||||
# sure would be cool if github gave us proper conditionals...
|
||||
# so here's a doubly-nested ternary-via-truthiness to try to provide the best possible
|
||||
# functionality based on whether this is a pull_request, and whether it's from a fork.
|
||||
# (PRs run on the *source* but secrets are usually on the *target* -- that's *good*
|
||||
# but also really annoying to build CI around when it needs secrets to work right.)
|
||||
- id: plan
|
||||
run: |
|
||||
dist ${{ (!github.event.pull_request && format('host --steps=create --tag={0}', github.ref_name)) || 'plan' }} --output-format=json > plan-dist-manifest.json
|
||||
echo "dist ran successfully"
|
||||
cat plan-dist-manifest.json
|
||||
echo "manifest=$(jq -c "." plan-dist-manifest.json)" >> "$GITHUB_OUTPUT"
|
||||
- name: "Upload dist-manifest.json"
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: artifacts-plan-dist-manifest
|
||||
path: plan-dist-manifest.json
|
||||
|
||||
# Build and packages all the platform-specific things
|
||||
build-local-artifacts:
|
||||
name: build-local-artifacts (${{ join(matrix.targets, ', ') }})
|
||||
# Let the initial task tell us to not run (currently very blunt)
|
||||
needs:
|
||||
- plan
|
||||
if: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix.include != null && (needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
# Target platforms/runners are computed by dist in create-release.
|
||||
# Each member of the matrix has the following arguments:
|
||||
#
|
||||
# - runner: the github runner
|
||||
# - dist-args: cli flags to pass to dist
|
||||
# - install-dist: expression to run to install dist on the runner
|
||||
#
|
||||
# Typically there will be:
|
||||
# - 1 "global" task that builds universal installers
|
||||
# - N "local" tasks that build each platform's binaries and platform-specific installers
|
||||
matrix: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix }}
|
||||
runs-on: ${{ matrix.runner }}
|
||||
container: ${{ matrix.container && matrix.container.image || null }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json
|
||||
steps:
|
||||
- name: enable windows longpaths
|
||||
run: |
|
||||
git config --global core.longpaths true
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install Rust non-interactively if not already installed
|
||||
if: ${{ matrix.container }}
|
||||
run: |
|
||||
if ! command -v cargo > /dev/null 2>&1; then
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
|
||||
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
|
||||
fi
|
||||
- name: Install dist
|
||||
run: ${{ matrix.install_dist.run }}
|
||||
# Get the dist-manifest
|
||||
- name: Fetch local artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: artifacts-*
|
||||
path: target/distrib/
|
||||
merge-multiple: true
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
${{ matrix.packages_install }}
|
||||
- name: Build artifacts
|
||||
run: |
|
||||
# Actually do builds and make zips and whatnot
|
||||
dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json
|
||||
echo "dist ran successfully"
|
||||
- id: cargo-dist
|
||||
name: Post-build
|
||||
# We force bash here just because github makes it really hard to get values up
|
||||
# to "real" actions without writing to env-vars, and writing to env-vars has
|
||||
# inconsistent syntax between shell and powershell.
|
||||
shell: bash
|
||||
run: |
|
||||
# Parse out what we just built and upload it to scratch storage
|
||||
echo "paths<<EOF" >> "$GITHUB_OUTPUT"
|
||||
dist print-upload-files-from-manifest --manifest dist-manifest.json >> "$GITHUB_OUTPUT"
|
||||
echo "EOF" >> "$GITHUB_OUTPUT"
|
||||
|
||||
cp dist-manifest.json "$BUILD_MANIFEST_NAME"
|
||||
- name: "Upload artifacts"
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: artifacts-build-local-${{ join(matrix.targets, '_') }}
|
||||
path: |
|
||||
${{ steps.cargo-dist.outputs.paths }}
|
||||
${{ env.BUILD_MANIFEST_NAME }}
|
||||
|
||||
# Build and package all the platform-agnostic(ish) things
|
||||
build-global-artifacts:
|
||||
needs:
|
||||
- plan
|
||||
- build-local-artifacts
|
||||
runs-on: "ubuntu-latest"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install cached dist
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cargo-dist-cache
|
||||
path: ~/.cargo/bin/
|
||||
- run: chmod +x ~/.cargo/bin/dist
|
||||
# Get all the local artifacts for the global tasks to use (for e.g. checksums)
|
||||
- name: Fetch local artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: artifacts-*
|
||||
path: target/distrib/
|
||||
merge-multiple: true
|
||||
- id: cargo-dist
|
||||
shell: bash
|
||||
run: |
|
||||
dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json
|
||||
echo "dist ran successfully"
|
||||
|
||||
# Parse out what we just built and upload it to scratch storage
|
||||
echo "paths<<EOF" >> "$GITHUB_OUTPUT"
|
||||
jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT"
|
||||
echo "EOF" >> "$GITHUB_OUTPUT"
|
||||
|
||||
cp dist-manifest.json "$BUILD_MANIFEST_NAME"
|
||||
- name: "Upload artifacts"
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: artifacts-build-global
|
||||
path: |
|
||||
${{ steps.cargo-dist.outputs.paths }}
|
||||
${{ env.BUILD_MANIFEST_NAME }}
|
||||
# Determines if we should publish/announce
|
||||
host:
|
||||
needs:
|
||||
- plan
|
||||
- build-local-artifacts
|
||||
- build-global-artifacts
|
||||
# Only run if we're "publishing", and only if local and global didn't fail (skipped is fine)
|
||||
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"
|
||||
outputs:
|
||||
val: ${{ steps.host.outputs.manifest }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install cached dist
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cargo-dist-cache
|
||||
path: ~/.cargo/bin/
|
||||
- run: chmod +x ~/.cargo/bin/dist
|
||||
# Fetch artifacts from scratch-storage
|
||||
- name: Fetch artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: artifacts-*
|
||||
path: target/distrib/
|
||||
merge-multiple: true
|
||||
- id: host
|
||||
shell: bash
|
||||
run: |
|
||||
dist host ${{ needs.plan.outputs.tag-flag }} --steps=upload --steps=release --output-format=json > dist-manifest.json
|
||||
echo "artifacts uploaded and released successfully"
|
||||
cat dist-manifest.json
|
||||
echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT"
|
||||
- name: "Upload dist-manifest.json"
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
# Overwrite the previous copy
|
||||
name: artifacts-dist-manifest
|
||||
path: dist-manifest.json
|
||||
# Create a GitHub Release while uploading all files to it
|
||||
- name: "Download GitHub Artifacts"
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: artifacts-*
|
||||
path: artifacts
|
||||
merge-multiple: true
|
||||
- name: Cleanup
|
||||
run: |
|
||||
# Remove the granular manifests
|
||||
rm -f artifacts/*-dist-manifest.json
|
||||
- name: Create GitHub Release
|
||||
env:
|
||||
PRERELEASE_FLAG: "${{ fromJson(steps.host.outputs.manifest).announcement_is_prerelease && '--prerelease' || '' }}"
|
||||
ANNOUNCEMENT_TITLE: "${{ fromJson(steps.host.outputs.manifest).announcement_title }}"
|
||||
ANNOUNCEMENT_BODY: "${{ fromJson(steps.host.outputs.manifest).announcement_github_body }}"
|
||||
RELEASE_COMMIT: "${{ github.sha }}"
|
||||
run: |
|
||||
# Write and read notes from a file to avoid quoting breaking things
|
||||
echo "$ANNOUNCEMENT_BODY" > $RUNNER_TEMP/notes.txt
|
||||
|
||||
gh release create "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file "$RUNNER_TEMP/notes.txt" artifacts/*
|
||||
|
||||
announce:
|
||||
needs:
|
||||
- plan
|
||||
- host
|
||||
# use "always() && ..." to allow us to wait for all publish jobs while
|
||||
# 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"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
+7
-7
@@ -36,7 +36,7 @@ Added git tags for each version though Markdown won't display formatted on Githu
|
||||
Moved Sanakirja database wrapper to its own crate (`snkrj`) and added a robust auto defragmentation to improve disk usage without the need for user's intervention.
|
||||
Since it's not used anymore it will moved out of the repository relatively soon.
|
||||
|
||||
# [v0.5.0](https://github.com/kibo-money/kibo/tree/eea56d394bf92c62c81da8b78b8c47ea730683f5) | [873199](https://mempool.space/block/0000000000000000000270925aa6a565be92e13164565a3f7994ca1966e48050) - 2024/12/04
|
||||
# [kibo-v0.5.0](https://github.com/kibo-money/kibo/tree/eea56d394bf92c62c81da8b78b8c47ea730683f5) | [873199](https://mempool.space/block/0000000000000000000270925aa6a565be92e13164565a3f7994ca1966e48050) - 2024/12/04
|
||||
|
||||

|
||||
|
||||
@@ -103,7 +103,7 @@ Since it's not used anymore it will moved out of the repository relatively soon.
|
||||
|
||||
- Moved back to this repo
|
||||
|
||||
# [v0.4.0](https://github.com/kibo-money/kibo/tree/a64c544815d9ef785e2fc1323582f774f16b9200) | [861950](https://mempool.space/block/00000000000000000000530d0e30ccf7deeace122dcc99f2668a06c6dad83629) - 2024/09/19
|
||||
# [kibo-v0.4.0](https://github.com/kibo-money/kibo/tree/a64c544815d9ef785e2fc1323582f774f16b9200) | [861950](https://mempool.space/block/00000000000000000000530d0e30ccf7deeace122dcc99f2668a06c6dad83629) - 2024/09/19
|
||||
|
||||

|
||||
|
||||
@@ -140,7 +140,7 @@ Since it's not used anymore it will moved out of the repository relatively soon.
|
||||
- Added serving of the website
|
||||
- Improved `Cache-Control` behavior
|
||||
|
||||
# [v0.3.0](https://github.com/kibo-money/kibo/tree/b68b016091c45b071218fba01bac5b76e8eaf18c) | [853930](https://mempool.space/block/00000000000000000002eb5e9a7950ca2d5d98bd1ed28fc9098aa630d417985d) - 2024/07/26
|
||||
# [kibo-v0.3.0](https://github.com/kibo-money/kibo/tree/b68b016091c45b071218fba01bac5b76e8eaf18c) | [853930](https://mempool.space/block/00000000000000000002eb5e9a7950ca2d5d98bd1ed28fc9098aa630d417985d) - 2024/07/26
|
||||
|
||||

|
||||
|
||||
@@ -219,7 +219,7 @@ Since it's not used anymore it will moved out of the repository relatively soon.
|
||||
- Only run with a watcher if `cargo watch` is available
|
||||
- Removed id_to_path file in favor for only `paths.d.ts` in `app/src/types`
|
||||
|
||||
# [v0.2.0](https://github.com/kibo-money/kibo/tree/248187889283597c5dbb806292297453c25e97b8) | [851286](https://mempool.space/block/0000000000000000000281ca7f1bf8c50702bfca168c7af1bdc67c977c1ac8ed) - 2024/07/08
|
||||
# [kibo-v0.2.0](https://github.com/kibo-money/kibo/tree/248187889283597c5dbb806292297453c25e97b8) | [851286](https://mempool.space/block/0000000000000000000281ca7f1bf8c50702bfca168c7af1bdc67c977c1ac8ed) - 2024/07/08
|
||||
|
||||

|
||||
|
||||
@@ -255,7 +255,7 @@ Since it's not used anymore it will moved out of the repository relatively soon.
|
||||
|
||||
- Fixed ulimit only being run in Mac OS instead of whenever the program is detected
|
||||
|
||||
# [v0.1.1](https://github.com/kibo-money/kibo/tree/e55b5195a9de9aea306903c94ed63cb1720fda5f) | [849240](https://mempool.space/block/000000000000000000002b8653988655071c07bb5f7181c038f9326bc86db741) - 2024/06/24
|
||||
# [kibo-v0.1.1](https://github.com/kibo-money/kibo/tree/e55b5195a9de9aea306903c94ed63cb1720fda5f) | [849240](https://mempool.space/block/000000000000000000002b8653988655071c07bb5f7181c038f9326bc86db741) - 2024/06/24
|
||||
|
||||

|
||||
|
||||
@@ -305,10 +305,10 @@ Since it's not used anymore it will moved out of the repository relatively soon.
|
||||
|
||||
- Deleted old price datasets and their backups
|
||||
|
||||
# [v0.1.0](https://github.com/kibo-money/kibo/tree/a1a576d088c8f83ed32d48753a7611f70a964574) | [848642](https://mempool.space/block/000000000000000000020be5761d70751252219a9557f55e91ecdfb86c4e026a) - 2024/06/19
|
||||
# [kibo-v0.1.0](https://github.com/kibo-money/kibo/tree/a1a576d088c8f83ed32d48753a7611f70a964574) | [848642](https://mempool.space/block/000000000000000000020be5761d70751252219a9557f55e91ecdfb86c4e026a) - 2024/06/19
|
||||
|
||||

|
||||
|
||||
# v0.0.1 | [835444](https://mempool.space/block/000000000000000000009f93907a0dd83c080d5585cc7ec82c076d45f6d7c872) - 2024/03/20
|
||||
# kibo-v0.0.1 | [835444](https://mempool.space/block/000000000000000000009f93907a0dd83c080d5585cc7ec82c076d45f6d7c872) - 2024/03/20
|
||||
|
||||

|
||||
|
||||
Generated
+119
-162
@@ -138,6 +138,12 @@ dependencies = [
|
||||
"derive_arbitrary",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.6"
|
||||
@@ -368,7 +374,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk"
|
||||
version = "0.0.16"
|
||||
version = "0.0.27"
|
||||
dependencies = [
|
||||
"brk_cli",
|
||||
"brk_computer",
|
||||
@@ -385,7 +391,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_cli"
|
||||
version = "0.0.16"
|
||||
version = "0.0.27"
|
||||
dependencies = [
|
||||
"brk_computer",
|
||||
"brk_core",
|
||||
@@ -406,7 +412,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_computer"
|
||||
version = "0.0.16"
|
||||
version = "0.0.27"
|
||||
dependencies = [
|
||||
"brk_core",
|
||||
"brk_exit",
|
||||
@@ -421,7 +427,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_core"
|
||||
version = "0.0.16"
|
||||
version = "0.0.27"
|
||||
dependencies = [
|
||||
"bitcoin",
|
||||
"bitcoincore-rpc",
|
||||
@@ -438,7 +444,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_exit"
|
||||
version = "0.0.16"
|
||||
version = "0.0.27"
|
||||
dependencies = [
|
||||
"brk_logger",
|
||||
"ctrlc",
|
||||
@@ -447,7 +453,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_fetcher"
|
||||
version = "0.0.16"
|
||||
version = "0.0.27"
|
||||
dependencies = [
|
||||
"brk_core",
|
||||
"brk_logger",
|
||||
@@ -460,7 +466,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_indexer"
|
||||
version = "0.0.16"
|
||||
version = "0.0.27"
|
||||
dependencies = [
|
||||
"bitcoin",
|
||||
"bitcoincore-rpc",
|
||||
@@ -479,7 +485,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_logger"
|
||||
version = "0.0.16"
|
||||
version = "0.0.27"
|
||||
dependencies = [
|
||||
"color-eyre",
|
||||
"env_logger",
|
||||
@@ -489,7 +495,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_parser"
|
||||
version = "0.0.16"
|
||||
version = "0.0.27"
|
||||
dependencies = [
|
||||
"bitcoin",
|
||||
"bitcoincore-rpc",
|
||||
@@ -504,7 +510,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_query"
|
||||
version = "0.0.16"
|
||||
version = "0.0.27"
|
||||
dependencies = [
|
||||
"brk_computer",
|
||||
"brk_indexer",
|
||||
@@ -520,7 +526,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_server"
|
||||
version = "0.0.16"
|
||||
version = "0.0.27"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"brk_computer",
|
||||
@@ -541,14 +547,15 @@ dependencies = [
|
||||
"tokio",
|
||||
"tower-http",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brk_vec"
|
||||
version = "0.0.16"
|
||||
version = "0.0.27"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"axum",
|
||||
"memmap2",
|
||||
"rayon",
|
||||
"serde",
|
||||
@@ -570,9 +577,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brotli-decompressor"
|
||||
version = "4.0.2"
|
||||
version = "4.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37"
|
||||
checksum = "a334ef7c9e23abf0ce748e8cd309037da93e606ad52eb372e4ce327a0dcfbdfd"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
@@ -641,9 +648,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.18"
|
||||
version = "1.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
|
||||
checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
@@ -687,9 +694,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.35"
|
||||
version = "4.5.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944"
|
||||
checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -697,9 +704,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.35"
|
||||
version = "4.5.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9"
|
||||
checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -844,9 +851,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.14"
|
||||
version = "0.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471"
|
||||
checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
@@ -972,9 +979,9 @@ checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b"
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.4.1"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28cfac68e08048ae1883171632c2aef3ebc555621ae56fbccce1cbf22dd7f058"
|
||||
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
"serde",
|
||||
@@ -1122,7 +1129,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide 0.8.7",
|
||||
"miniz_oxide 0.8.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1131,6 +1138,12 @@ version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
@@ -1245,6 +1258,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1413,9 +1428,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.8.0"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
|
||||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.15.2",
|
||||
@@ -1463,9 +1478,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||
|
||||
[[package]]
|
||||
name = "jiff"
|
||||
version = "0.2.5"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c102670231191d07d37a35af3eb77f1f0dbf7a71be51a962dcd57ea607be7260"
|
||||
checksum = "e5ad87c89110f55e4cd4dc2893a9790820206729eaf221555f742d540b0724a0"
|
||||
dependencies = [
|
||||
"jiff-static",
|
||||
"jiff-tzdb-platform",
|
||||
@@ -1478,9 +1493,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "jiff-static"
|
||||
version = "0.2.5"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cdde31a9d349f1b1f51a0b3714a5940ac022976f4b49485fc04be052b183b4c"
|
||||
checksum = "d076d5b64a7e2fe6f0743f02c43ca4a6725c0f904203bfe276a5b3e793103605"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1542,15 +1557,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.171"
|
||||
version = "0.2.172"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.9.3"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
|
||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
@@ -1562,12 +1577,6 @@ dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lockfree-object-pool"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.27"
|
||||
@@ -1663,18 +1672,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.7"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430"
|
||||
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minreq"
|
||||
version = "2.13.3"
|
||||
version = "2.13.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567496f13503d6cae8c9f961f34536850275f396307d7a6b981eef1464032f53"
|
||||
checksum = "f0d2aaba477837b46ec1289588180fabfccf0c3b1d1a0c6b1866240cd6cd5ce9"
|
||||
dependencies = [
|
||||
"log",
|
||||
"rustls",
|
||||
@@ -1713,16 +1722,6 @@ version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51"
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
|
||||
dependencies = [
|
||||
"overload",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
@@ -1778,12 +1777,6 @@ version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e"
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "owo-colors"
|
||||
version = "3.5.0"
|
||||
@@ -1798,9 +1791,9 @@ checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564"
|
||||
|
||||
[[package]]
|
||||
name = "oxc"
|
||||
version = "0.62.0"
|
||||
version = "0.64.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c274a11ab2471eea5f970d943ecb7b64dc9fa21d89ac5c968fc0f48ca9971196"
|
||||
checksum = "548086420c5c78546c7417384689af59ed11dbe9462e8bfef42636be0f545b96"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
@@ -1841,9 +1834,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_allocator"
|
||||
version = "0.62.0"
|
||||
version = "0.64.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fef6db9c542af8b1b0889c4fdbc4dfd0a13c5bec0f94ef39bb826084465d6b1e"
|
||||
checksum = "acaf33eacde1fca8fdb26655d7486842a8106916bc3855265607db2b4a4eaec4"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"bumpalo",
|
||||
@@ -1855,9 +1848,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_ast"
|
||||
version = "0.62.0"
|
||||
version = "0.64.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c269cf713bed18d74e957045d2b1cf57827333a66aad2b2c136c9f8b79940bd2"
|
||||
checksum = "3044daf0f6b02f27330954141d799f9206e04b9175a3f4fa199f78c5ef46b2b4"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cow-utils",
|
||||
@@ -1872,9 +1865,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_ast_macros"
|
||||
version = "0.62.0"
|
||||
version = "0.64.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1d8afe9d7e4aed37d6e8906250db4872f514c15a244268ce3da09ccb4017900"
|
||||
checksum = "7ee5d1546ecb309530b30b48f1aefefad7e6d53b8502e7b91b20d6a523af270e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1883,9 +1876,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_ast_visit"
|
||||
version = "0.62.0"
|
||||
version = "0.64.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d360f012f970b3e79f8f9863abb83b373014eb9d1a23fecd7ce33e555cc3151"
|
||||
checksum = "b29d0e9e05d2638317c39470b5a528e268fc088ae1e3fda26b049661f2de25ad"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
@@ -1895,9 +1888,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_cfg"
|
||||
version = "0.62.0"
|
||||
version = "0.64.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17a48085dd0ca7e8f3ad946a131d8229af783be65cbf4965ff6379e432f6b625"
|
||||
checksum = "7b3740da43d597136474fa738bafb697c8469b8ecd9c256819ae443ec91a67aa"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"itertools",
|
||||
@@ -1910,9 +1903,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_codegen"
|
||||
version = "0.62.0"
|
||||
version = "0.64.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1e6d4e1c953205c62effeb61c1da684dd1668feaf21b4fe15c2b603526355f6"
|
||||
checksum = "ee5e197f8bed070bcc6e9744a7a5f91bc4ff250543f07849567e6e602383c7db"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cow-utils",
|
||||
@@ -1931,15 +1924,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_data_structures"
|
||||
version = "0.62.0"
|
||||
version = "0.64.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e2866696e6bb90151c5687a961c3ff1fa2726436869d42eea14cf2d5c663590"
|
||||
checksum = "9ca20f4fc9af4f462bfc6bbca60e3f4c2ca9c4f09e99363c0c85d90bb936641c"
|
||||
|
||||
[[package]]
|
||||
name = "oxc_diagnostics"
|
||||
version = "0.62.0"
|
||||
version = "0.64.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d7800336d376a2baeafb9d2bcdc9fbef254863c33810e6d1cc4a431cd0048ef"
|
||||
checksum = "50e5ef1106d01ade76eec600e5b0da38932f555d1cb661f0d5ec7f3d717da22d"
|
||||
dependencies = [
|
||||
"cow-utils",
|
||||
"oxc-miette",
|
||||
@@ -1947,9 +1940,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_ecmascript"
|
||||
version = "0.62.0"
|
||||
version = "0.64.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0edf650adfacf84768cdfeca874d8f5ffebfd108ee8a44959c0eca82b04321c6"
|
||||
checksum = "76b1ea0ef90fda6b68127181b3b136b21041a595e8c2028c4e08fcf85f99a10c"
|
||||
dependencies = [
|
||||
"cow-utils",
|
||||
"num-bigint",
|
||||
@@ -1961,9 +1954,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_estree"
|
||||
version = "0.62.0"
|
||||
version = "0.64.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd77f6588d373c1b753588b784de380a7418f8e46776e25c4564739994b9a5a6"
|
||||
checksum = "6b9ce9584683d43622ef4b66bd605ce9878f3bf7468b9b59ad041f33af13c34d"
|
||||
|
||||
[[package]]
|
||||
name = "oxc_index"
|
||||
@@ -1973,9 +1966,9 @@ checksum = "2fa07b0cfa997730afed43705766ef27792873fdf5215b1391949fec678d2392"
|
||||
|
||||
[[package]]
|
||||
name = "oxc_mangler"
|
||||
version = "0.62.0"
|
||||
version = "0.64.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02f00ca9e544230f01d37de50ba710136763a13804303bcf70cf22d8155f9db5"
|
||||
checksum = "20c80a552dc097088d466679bcaba2576bbe88a430ca9c5b0cb67e23787aaa7a"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"itertools",
|
||||
@@ -1990,9 +1983,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_minifier"
|
||||
version = "0.62.0"
|
||||
version = "0.64.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8670c4452b9f78012b9ede921e40f91686ad9a1af1c40aab8ee3a5f4ef8380ef"
|
||||
checksum = "e5e504ac83f23ff755eae4ebd6291258b44e05cf58379e1fe1c00b1007e41f29"
|
||||
dependencies = [
|
||||
"cow-utils",
|
||||
"oxc_allocator",
|
||||
@@ -2012,9 +2005,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_parser"
|
||||
version = "0.62.0"
|
||||
version = "0.64.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8eaebe1ac01073b2a43a8848ae7ec24fdad3813855d72bb1942908632654f94"
|
||||
checksum = "688491b2dfe8049a6410bc6b92f71e75bebfe9a1f352a64084a62069cd644e7f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cow-utils",
|
||||
@@ -2035,9 +2028,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_regular_expression"
|
||||
version = "0.62.0"
|
||||
version = "0.64.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9ad8833ffba010e9f4cced1482297282728b0dc1c410cd716f206d214250f3f"
|
||||
checksum = "3be6231edf43b8ca0fa8edad93b0b8e9067a3991ea2d8aa9f22a4c8fa464f267"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast_macros",
|
||||
@@ -2051,9 +2044,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_semantic"
|
||||
version = "0.62.0"
|
||||
version = "0.64.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0523c9521e3ee63d6e0b463941e030b482977d7c323ee802eebacac8e5227bc8"
|
||||
checksum = "8f5c80c996fafc27a8444732bbba06f1de3eb488c585d65293a4b40b089ff564"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"oxc_allocator",
|
||||
@@ -2087,9 +2080,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_span"
|
||||
version = "0.62.0"
|
||||
version = "0.64.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bcfa55b4e3de93d39528b4ac616c00918dc73b6f6828403b3c56a7dde7af23b"
|
||||
checksum = "bce0a945765d00dd9ee0bfdc38fa265008e66f919157894c0383c525d026511f"
|
||||
dependencies = [
|
||||
"compact_str",
|
||||
"oxc-miette",
|
||||
@@ -2100,9 +2093,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_syntax"
|
||||
version = "0.62.0"
|
||||
version = "0.64.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7bc0d1f63b254791867280db5e582d7411c112f0798eee50bfdb8cdd2ef80c93"
|
||||
checksum = "12b876a00908cb1fc6648823d7d8579a69af1c5a5c6d4cf6135040e09f41d116"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cow-utils",
|
||||
@@ -2121,9 +2114,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_traverse"
|
||||
version = "0.62.0"
|
||||
version = "0.64.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a1f5183b3db89b3b3c7621741d5e2b9c13996dec5be4ad5e7adf86fdcfd24f0"
|
||||
checksum = "a9c25f3da54211abd4b6ff1390a0f28d42b2128cb33f4b38edbdc5cb71bc3d3c"
|
||||
dependencies = [
|
||||
"compact_str",
|
||||
"itoa",
|
||||
@@ -2208,12 +2201,14 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.7.1"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
|
||||
checksum = "7a98c6720655620a521dcc722d0ad66cd8afd5d86e34a89ef691c50b7b24de06"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"indexmap 2.8.0",
|
||||
"hashbrown 0.15.2",
|
||||
"indexmap 2.9.0",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2330,18 +2325,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.94"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
|
||||
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick_cache"
|
||||
version = "0.6.12"
|
||||
version = "0.6.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f8ed0655cbaf18a26966142ad23b95d8ab47221c50c4f73a1db7d0d2d6e3da8"
|
||||
checksum = "287e56aac5a2b4fb25a6fb050961d157635924c8696305a5c937a76f29841a0f"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.15.2",
|
||||
@@ -2420,9 +2415,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.10"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1"
|
||||
checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
@@ -2583,9 +2578,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "self_cell"
|
||||
version = "1.1.0"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2fdfc24bc566f839a2da4c4295b82db7d25a24253867d5c64355abb5799bdbe"
|
||||
checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749"
|
||||
|
||||
[[package]]
|
||||
name = "seq-macro"
|
||||
@@ -2675,7 +2670,7 @@ dependencies = [
|
||||
"chrono",
|
||||
"hex",
|
||||
"indexmap 1.9.3",
|
||||
"indexmap 2.8.0",
|
||||
"indexmap 2.9.0",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
@@ -2750,9 +2745,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.14.0"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
|
||||
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
||||
|
||||
[[package]]
|
||||
name = "smawk"
|
||||
@@ -2932,9 +2927,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.44.1"
|
||||
version = "1.44.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a"
|
||||
checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
@@ -2999,7 +2994,7 @@ version = "0.22.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
|
||||
dependencies = [
|
||||
"indexmap 2.8.0",
|
||||
"indexmap 2.9.0",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
@@ -3097,29 +3092,15 @@ dependencies = [
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
|
||||
dependencies = [
|
||||
"nu-ansi-term",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3284,28 +3265,6 @@ version = "0.25.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.61.0"
|
||||
@@ -3449,9 +3408,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.4"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36"
|
||||
checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -3522,9 +3481,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "2.6.0"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "febbe83a485467affa75a75d28dc7494acd2f819e549536c47d46b3089b56164"
|
||||
checksum = "1dcb24d0152526ae49b9b96c1dcf71850ca1e0b882e4e28ed898a93c41334744"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"arbitrary",
|
||||
@@ -3536,7 +3495,7 @@ dependencies = [
|
||||
"flate2",
|
||||
"getrandom 0.3.2",
|
||||
"hmac",
|
||||
"indexmap 2.8.0",
|
||||
"indexmap 2.9.0",
|
||||
"lzma-rs",
|
||||
"memchr",
|
||||
"pbkdf2",
|
||||
@@ -3550,15 +3509,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zopfli"
|
||||
version = "0.8.1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946"
|
||||
checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"crc32fast",
|
||||
"lockfree-object-pool",
|
||||
"log",
|
||||
"once_cell",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
|
||||
+33
-4
@@ -4,7 +4,7 @@ members = ["crates/*"]
|
||||
package.description = "The Bitcoin Research Kit is a suite of tools designed to extract, compute and display data stored on a Bitcoin Core node"
|
||||
package.license = "MIT"
|
||||
package.edition = "2024"
|
||||
package.version = "0.0.16"
|
||||
package.version = "0.0.27"
|
||||
package.repository = "https://github.com/bitcoinresearchkit/brk"
|
||||
|
||||
[profile.release]
|
||||
@@ -12,7 +12,11 @@ lto = "fat"
|
||||
codegen-units = 1
|
||||
panic = "abort"
|
||||
|
||||
[profile.dist]
|
||||
inherits = "release"
|
||||
|
||||
[workspace.dependencies]
|
||||
axum = "0.8.3"
|
||||
bitcoin = { version = "0.32.5", features = ["serde"] }
|
||||
bitcoincore-rpc = "0.19.0"
|
||||
brk_cli = { version = "0", path = "crates/brk_cli" }
|
||||
@@ -27,15 +31,40 @@ brk_query = { version = "0", path = "crates/brk_query" }
|
||||
brk_server = { version = "0", path = "crates/brk_server" }
|
||||
brk_vec = { version = "0", path = "crates/brk_vec" }
|
||||
byteview = "0.6.1"
|
||||
clap = { version = "4.5.35", features = ["derive", "string"] }
|
||||
clap = { version = "4.5.36", features = ["derive", "string"] }
|
||||
color-eyre = "0.6.3"
|
||||
derive_deref = "1.1.1"
|
||||
fjall = "2.8.0"
|
||||
jiff = "0.2.5"
|
||||
jiff = "0.2.8"
|
||||
log = { version = "0.4.27" }
|
||||
minreq = { version = "2.13.3", features = ["https", "serde_json"] }
|
||||
minreq = { version = "2.13.4", features = ["https", "serde_json"] }
|
||||
rayon = "1.10.0"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
serde_json = { version = "1.0.140", features = ["float_roundtrip"] }
|
||||
tabled = "0.18.0"
|
||||
zerocopy = { version = "0.8.24", features = ["derive"] }
|
||||
|
||||
[workspace.metadata.release]
|
||||
shared-version = true
|
||||
tag-name = "v{{version}}"
|
||||
pre-release-commit-message = "release: v{{version}}"
|
||||
tag-message = "release: v{{version}}"
|
||||
|
||||
[workspace.metadata.dist]
|
||||
cargo-dist-version = "0.28.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" }
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<a href="https://deps.rs/crate/brk">
|
||||
<img src="https://deps.rs/crate/brk/latest/status.svg" alt="Dependency status">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cvrwpv3zEG">
|
||||
<a href="https://discord.gg/HaR3wpH3nr">
|
||||
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
|
||||
@@ -35,7 +35,7 @@
|
||||
</p>
|
||||
|
||||
> **WARNING**
|
||||
>
|
||||
>
|
||||
> This project is still a work in progress and while it's much better in many ways than its previous version ([kibo v0.5](https://github.com/kibo-money/kibo)), it doesn't yet include all of those datasets. If you're interested in having everything right now, please use the latter until feature parity is achieved.
|
||||
>
|
||||
> The explorer part (mempool.space/electrs) is also not viable just yet.
|
||||
@@ -58,6 +58,7 @@ The toolkit can be used in various ways to accommodate as many needs as possible
|
||||
For more information visit: [`brk_cli`](https://crates.io/crates/brk_cli)
|
||||
- **[Crates](https://crates.io/crates/brk)** \
|
||||
Rust developers have access to a wide range crates, each built upon one another with its own specific purpose, enabling independent use and offering great flexibility.
|
||||
PRs are welcome, especially if their goal is to introduce additional datasets.
|
||||
|
||||
The primary goal of this project is to be fully-featured and accessible for everyone, regardless of their background or financial situation - whether that person is an enthusiast, researcher, miner, analyst, or simply curious.
|
||||
|
||||
@@ -76,7 +77,7 @@ In contrast, existing alternatives tend to be either [very costly](https://studi
|
||||
- [`brk_parser`](https://crates.io/crates/brk_parser): A very fast Bitcoin Core block parser and iterator built on top of bitcoin-rust
|
||||
- [`brk_query`](https://crates.io/crates/brk_query): A library that finds requested datasets.
|
||||
- [`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_vec`](https://crates.io/crates/brk_vec): A very small, fast, efficient and simple storable Vec.
|
||||
- [`brk_vec`](https://crates.io/crates/brk_vec): A push-only, truncable, compressable, saveable Vec
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
|
||||
@@ -26,3 +26,6 @@ toml = "0.8.20"
|
||||
[[bin]]
|
||||
name = "brk"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.dist]
|
||||
dist = false
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<a href="https://deps.rs/crate/brk_cli">
|
||||
<img src="https://deps.rs/crate/brk_cli/latest/status.svg" alt="Dependency status">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cvrwpv3zEG">
|
||||
<a href="https://discord.gg/HaR3wpH3nr">
|
||||
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
|
||||
@@ -59,16 +59,28 @@ To be determined
|
||||
- Unix based operating system (Mac OS or Linux)
|
||||
- Ubuntu users need to install `open-ssl` via `sudo apt install libssl-dev pkg-config`
|
||||
|
||||
## Install
|
||||
## Download
|
||||
|
||||
### Binaries
|
||||
|
||||
You can find a pre-built binary for your operating system on the releases page ([link](https://github.com/bitcoinresearchkit/brk/releases/latest)).
|
||||
|
||||
### Cargo
|
||||
|
||||
```bash
|
||||
# Install
|
||||
cargo install brk # 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
|
||||
```
|
||||
|
||||
## Update
|
||||
### Source
|
||||
|
||||
```bash
|
||||
cargo install brk # or `cargo install-update -a` if you have `cargo-update` installed
|
||||
git clone https://github.com/bitcoinresearchkit/brk.git
|
||||
cd brk/crates/brk
|
||||
cargo run -r
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -58,10 +58,28 @@ pub fn run(config: RunConfig) -> color_eyre::Result<()> {
|
||||
};
|
||||
|
||||
if config.process() {
|
||||
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(())
|
||||
};
|
||||
|
||||
loop {
|
||||
wait_for_synced_node()?;
|
||||
|
||||
let block_count = rpc.get_block_count()?;
|
||||
|
||||
info!("{block_count} blocks found.");
|
||||
info!("{} blocks found.", block_count + 1);
|
||||
|
||||
let starting_indexes = indexer.index(&parser, rpc, &exit)?;
|
||||
|
||||
@@ -272,9 +290,10 @@ impl RunConfig {
|
||||
}
|
||||
|
||||
fn read(path: &Path) -> Self {
|
||||
fs::read_to_string(path).map_or(RunConfig::default(), |contents| {
|
||||
toml::from_str(&contents).unwrap_or_default()
|
||||
})
|
||||
fs::read_to_string(path).map_or_else(
|
||||
|_| RunConfig::default(),
|
||||
|contents| toml::from_str(&contents).unwrap_or_default(),
|
||||
)
|
||||
}
|
||||
|
||||
fn write(&self, path: &Path) -> std::io::Result<()> {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<a href="https://deps.rs/crate/brk_computer">
|
||||
<img src="https://deps.rs/crate/brk_computer/latest/status.svg" alt="Dependency status">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cvrwpv3zEG">
|
||||
<a href="https://discord.gg/HaR3wpH3nr">
|
||||
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
|
||||
|
||||
@@ -13,9 +13,9 @@ pub struct Stores {
|
||||
impl Stores {
|
||||
pub fn import(path: &Path) -> color_eyre::Result<Self> {
|
||||
let address_to_utxos_received =
|
||||
Store::import(&path.join("address_to_utxos_received"), Version::ONE)?;
|
||||
Store::import(&path.join("address_to_utxos_received"), Version::ZERO)?;
|
||||
let address_to_utxos_spent =
|
||||
Store::import(&path.join("address_to_utxos_spent"), Version::ONE)?;
|
||||
Store::import(&path.join("address_to_utxos_spent"), Version::ZERO)?;
|
||||
|
||||
Ok(Self {
|
||||
address_to_utxos_received,
|
||||
|
||||
@@ -2,38 +2,48 @@ use core::error;
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
fmt::Debug,
|
||||
io,
|
||||
ops::{Add, Sub},
|
||||
ops::Add,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use brk_core::CheckedSub;
|
||||
use brk_core::{Bitcoin, CheckedSub, Close, Dollars, Height, Sats, Txindex};
|
||||
use brk_exit::Exit;
|
||||
use brk_vec::{AnyStorableVec, Compressed, Error, Result, StoredIndex, StoredType, Version};
|
||||
use brk_vec::{
|
||||
Compressed, DynamicVec, Error, GenericVec, Result, StoredIndex, StoredType, StoredVec, Version,
|
||||
};
|
||||
use log::info;
|
||||
|
||||
const FLUSH_EVERY: usize = 10_000;
|
||||
const ONE_KIB: usize = 1024;
|
||||
const ONE_MIB: usize = ONE_KIB * ONE_KIB;
|
||||
const MAX_CACHE_SIZE: usize = 210 * ONE_MIB;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StorableVec<I, T> {
|
||||
computed_version: Option<Version>,
|
||||
vec: brk_vec::StorableVec<I, T>,
|
||||
}
|
||||
|
||||
impl<I, T> StorableVec<I, T>
|
||||
pub struct ComputedVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
computed_version: Option<Version>,
|
||||
inner: StoredVec<I, T>,
|
||||
}
|
||||
|
||||
impl<I, T> ComputedVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
const SIZE_OF: usize = size_of::<T>();
|
||||
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
version: Version,
|
||||
compressed: Compressed,
|
||||
) -> brk_vec::Result<Self> {
|
||||
let vec = brk_vec::StorableVec::forced_import(path, version, compressed)?;
|
||||
let inner = StoredVec::forced_import(path, version, compressed)?;
|
||||
|
||||
Ok(Self {
|
||||
computed_version: None,
|
||||
vec,
|
||||
inner,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -42,7 +52,7 @@ where
|
||||
return Ok(());
|
||||
}
|
||||
exit.block();
|
||||
self.vec.truncate_if_needed(index)?;
|
||||
self.inner.truncate_if_needed(index)?;
|
||||
exit.release();
|
||||
Ok(())
|
||||
}
|
||||
@@ -57,102 +67,122 @@ where
|
||||
if ord == Ordering::Greater {
|
||||
self.safe_truncate_if_needed(index, exit)?;
|
||||
}
|
||||
self.vec.push(value);
|
||||
self.inner.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
if self.vec.pushed_len() >= FLUSH_EVERY {
|
||||
Ok(self.safe_flush(exit)?)
|
||||
if self.inner.pushed_len() * Self::SIZE_OF >= MAX_CACHE_SIZE {
|
||||
self.safe_flush(exit)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn safe_flush(&mut self, exit: &Exit) -> io::Result<()> {
|
||||
pub fn safe_flush(&mut self, exit: &Exit) -> Result<()> {
|
||||
if exit.triggered() {
|
||||
return Ok(());
|
||||
}
|
||||
exit.block();
|
||||
self.vec.flush()?;
|
||||
self.inner.flush()?;
|
||||
exit.release();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn version(&self) -> Version {
|
||||
self.vec.version()
|
||||
self.inner.version()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.vec.len()
|
||||
self.inner.len()
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.inner.is_empty()
|
||||
}
|
||||
|
||||
pub fn vec(&self) -> &brk_vec::StorableVec<I, T> {
|
||||
&self.vec
|
||||
fn file_name(&self) -> String {
|
||||
self.inner.file_name()
|
||||
}
|
||||
|
||||
pub fn mut_vec(&mut self) -> &mut brk_vec::StorableVec<I, T> {
|
||||
&mut self.vec
|
||||
pub fn vec(&self) -> &StoredVec<I, T> {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub fn any_vec(&self) -> &dyn AnyStorableVec {
|
||||
&self.vec
|
||||
pub fn mut_vec(&mut self) -> &mut StoredVec<I, T> {
|
||||
&mut self.inner
|
||||
}
|
||||
|
||||
pub fn mut_any_vec(&mut self) -> &mut dyn AnyStorableVec {
|
||||
&mut self.vec
|
||||
pub fn any_vec(&self) -> &dyn brk_vec::AnyStoredVec {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub fn get(&mut self, index: I) -> Result<Option<&T>> {
|
||||
self.vec.get(index)
|
||||
pub fn mut_any_vec(&mut self) -> &mut dyn brk_vec::AnyStoredVec {
|
||||
&mut self.inner
|
||||
}
|
||||
|
||||
pub fn collect_range(&self, from: Option<i64>, to: Option<i64>) -> Result<Vec<T>> {
|
||||
self.vec.collect_range(from, to)
|
||||
pub fn unwrap_cached_get(&mut self, index: I) -> Option<T> {
|
||||
self.inner.unwrap_cached_get(index)
|
||||
}
|
||||
#[inline]
|
||||
pub fn double_unwrap_cached_get(&mut self, index: I) -> T {
|
||||
self.inner.double_unwrap_cached_get(index)
|
||||
}
|
||||
|
||||
pub fn collect_inclusive_range(&self, from: I, to: I) -> Result<Vec<T>> {
|
||||
self.inner.collect_inclusive_range(from, to)
|
||||
}
|
||||
|
||||
pub fn path(&self) -> &Path {
|
||||
self.inner.path()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn path_computed_version(&self) -> PathBuf {
|
||||
self.vec.path().join("computed_version")
|
||||
self.inner.path().join("computed_version")
|
||||
}
|
||||
|
||||
fn validate_computed_version_or_reset_file(&mut self, version: Version) -> Result<()> {
|
||||
let path = self.path_computed_version();
|
||||
if version.validate(path.as_ref()).is_err() {
|
||||
self.vec.reset()?;
|
||||
self.inner.reset()?;
|
||||
}
|
||||
version.write(path.as_ref())?;
|
||||
|
||||
if self.is_empty() {
|
||||
info!("Computing {}...", self.file_name())
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute_transform<A, B, F>(
|
||||
&mut self,
|
||||
max_from: A,
|
||||
other: &mut brk_vec::StorableVec<A, B>,
|
||||
other: &mut StoredVec<A, B>,
|
||||
mut t: F,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
A: StoredIndex,
|
||||
B: StoredType,
|
||||
F: FnMut((A, B, &mut Self, &mut brk_vec::StorableVec<A, B>)) -> (I, T),
|
||||
F: FnMut((A, B, &mut Self, &mut dyn DynamicVec<I = A, T = B>)) -> (I, T),
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + other.version(),
|
||||
)?;
|
||||
|
||||
let index = max_from.min(A::from(self.len()));
|
||||
other.iter_from_cloned(index, |(a, b, other)| {
|
||||
other.iter_from(index, |(a, b, other)| {
|
||||
let (i, v) = t((a, b, self, other));
|
||||
self.forced_push_at(i, v, exit)
|
||||
})?;
|
||||
|
||||
Ok(self.safe_flush(exit)?)
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
|
||||
pub fn compute_inverse_more_to_less(
|
||||
&mut self,
|
||||
max_from: T,
|
||||
other: &mut brk_vec::StorableVec<T, I>,
|
||||
other: &mut StoredVec<T, I>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
@@ -163,24 +193,27 @@ where
|
||||
Version::ZERO + self.version() + other.version(),
|
||||
)?;
|
||||
|
||||
let index = max_from.min(self.vec.get_last()?.cloned().unwrap_or_default());
|
||||
let index = max_from.min(
|
||||
self.inner
|
||||
.cached_get_last()?
|
||||
.map_or_else(T::default, |v| v.into_inner()),
|
||||
);
|
||||
other.iter_from(index, |(v, i, ..)| {
|
||||
let i = *i;
|
||||
if self.get(i).unwrap().is_none_or(|old_v| *old_v > v) {
|
||||
if self.unwrap_cached_get(i).is_none_or(|old_v| old_v > v) {
|
||||
self.forced_push_at(i, v, exit)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(self.safe_flush(exit)?)
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
|
||||
pub fn compute_inverse_less_to_more(
|
||||
&mut self,
|
||||
max_from: T,
|
||||
first_indexes: &mut brk_vec::StorableVec<T, I>,
|
||||
last_indexes: &mut brk_vec::StorableVec<T, I>,
|
||||
first_indexes: &mut StoredVec<T, I>,
|
||||
last_indexes: &mut StoredVec<T, I>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
@@ -194,18 +227,18 @@ where
|
||||
let index = max_from.min(T::from(self.len()));
|
||||
first_indexes.iter_from(index, |(value, first_index, ..)| {
|
||||
let first_index = (first_index).to_usize()?;
|
||||
let last_index = (last_indexes.get(value)?.unwrap()).to_usize()?;
|
||||
let last_index = (last_indexes.double_unwrap_cached_get(value)).to_usize()?;
|
||||
(first_index..last_index)
|
||||
.try_for_each(|index| self.forced_push_at(I::from(index), value, exit))
|
||||
})?;
|
||||
|
||||
Ok(self.safe_flush(exit)?)
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
|
||||
pub fn compute_last_index_from_first(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
first_indexes: &mut brk_vec::StorableVec<I, T>,
|
||||
first_indexes: &mut StoredVec<I, T>,
|
||||
final_len: usize,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
@@ -219,11 +252,12 @@ where
|
||||
let index = max_from.min(I::from(self.len()));
|
||||
let one = T::from(1);
|
||||
let mut prev_index: Option<I> = None;
|
||||
first_indexes.iter_from(index, |(i, v, ..)| {
|
||||
first_indexes.iter_from(index, |(index, v, ..)| {
|
||||
if let Some(prev_index) = prev_index.take() {
|
||||
self.forced_push_at(prev_index, v.checked_sub(one).unwrap(), exit)?;
|
||||
let value = v.checked_sub(one).unwrap();
|
||||
self.forced_push_at(prev_index, value, exit)?;
|
||||
}
|
||||
prev_index.replace(i);
|
||||
prev_index.replace(index);
|
||||
Ok(())
|
||||
})?;
|
||||
if let Some(prev_index) = prev_index {
|
||||
@@ -234,19 +268,77 @@ where
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(self.safe_flush(exit)?)
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
|
||||
pub fn compute_count_from_indexes<T2>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
first_indexes: &mut brk_vec::StorableVec<I, T2>,
|
||||
last_indexes: &mut brk_vec::StorableVec<I, T2>,
|
||||
first_indexes: &mut StoredVec<I, T2>,
|
||||
last_indexes: &mut StoredVec<I, T2>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
T: From<T2>,
|
||||
T2: StoredType + Copy + Add<usize, Output = T2> + CheckedSub<T2> + TryInto<T> + Default,
|
||||
T2: StoredType
|
||||
+ StoredIndex
|
||||
+ Copy
|
||||
+ Add<usize, Output = T2>
|
||||
+ CheckedSub<T2>
|
||||
+ TryInto<T>
|
||||
+ Default,
|
||||
<T2 as TryInto<T>>::Error: error::Error + 'static,
|
||||
{
|
||||
let opt: Option<Box<dyn FnMut(T2) -> bool>> = None;
|
||||
self.compute_filtered_count_from_indexes_(max_from, first_indexes, last_indexes, opt, exit)
|
||||
}
|
||||
|
||||
pub fn compute_filtered_count_from_indexes<T2, F>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
first_indexes: &mut StoredVec<I, T2>,
|
||||
last_indexes: &mut StoredVec<I, T2>,
|
||||
filter: F,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
T: From<T2>,
|
||||
T2: StoredType
|
||||
+ StoredIndex
|
||||
+ Copy
|
||||
+ Add<usize, Output = T2>
|
||||
+ CheckedSub<T2>
|
||||
+ TryInto<T>
|
||||
+ Default,
|
||||
<T2 as TryInto<T>>::Error: error::Error + 'static,
|
||||
F: FnMut(T2) -> bool,
|
||||
{
|
||||
self.compute_filtered_count_from_indexes_(
|
||||
max_from,
|
||||
first_indexes,
|
||||
last_indexes,
|
||||
Some(Box::new(filter)),
|
||||
exit,
|
||||
)
|
||||
}
|
||||
|
||||
fn compute_filtered_count_from_indexes_<T2>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
first_indexes: &mut StoredVec<I, T2>,
|
||||
last_indexes: &mut StoredVec<I, T2>,
|
||||
mut filter: Option<Box<dyn FnMut(T2) -> bool + '_>>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
T: From<T2>,
|
||||
T2: StoredType
|
||||
+ StoredIndex
|
||||
+ Copy
|
||||
+ Add<usize, Output = T2>
|
||||
+ CheckedSub<T2>
|
||||
+ TryInto<T>
|
||||
+ Default,
|
||||
<T2 as TryInto<T>>::Error: error::Error + 'static,
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
@@ -255,21 +347,24 @@ where
|
||||
|
||||
let index = max_from.min(I::from(self.len()));
|
||||
first_indexes.iter_from(index, |(i, first_index, ..)| {
|
||||
let last_index = last_indexes.get(i)?.unwrap();
|
||||
let count = (*last_index + 1_usize)
|
||||
.checked_sub(*first_index)
|
||||
.unwrap_or_default();
|
||||
self.forced_push_at(i, count.into(), exit)
|
||||
let last_index = last_indexes.double_unwrap_cached_get(i);
|
||||
let range = first_index.unwrap_to_usize()..=last_index.unwrap_to_usize();
|
||||
let count = if let Some(filter) = filter.as_mut() {
|
||||
range.into_iter().filter(|i| filter(T2::from(*i))).count()
|
||||
} else {
|
||||
range.count()
|
||||
};
|
||||
self.forced_push_at(i, T::from(T2::from(count)), exit)
|
||||
})?;
|
||||
|
||||
Ok(self.safe_flush(exit)?)
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
|
||||
pub fn compute_is_first_ordered<A>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
self_to_other: &mut brk_vec::StorableVec<I, A>,
|
||||
other_to_self: &mut brk_vec::StorableVec<A, I>,
|
||||
self_to_other: &mut StoredVec<I, A>,
|
||||
other_to_self: &mut StoredVec<A, I>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
@@ -283,40 +378,120 @@ where
|
||||
|
||||
let index = max_from.min(I::from(self.len()));
|
||||
self_to_other.iter_from(index, |(i, other, ..)| {
|
||||
self.forced_push_at(i, T::from(other_to_self.get(*other)?.unwrap() == &i), exit)
|
||||
self.forced_push_at(
|
||||
i,
|
||||
T::from(other_to_self.double_unwrap_cached_get(other) == i),
|
||||
exit,
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(self.safe_flush(exit)?)
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
|
||||
pub fn compute_sum_from_indexes<T2>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
first_indexes: &mut brk_vec::StorableVec<I, T2>,
|
||||
last_indexes: &mut brk_vec::StorableVec<I, T2>,
|
||||
first_indexes: &mut StoredVec<I, T2>,
|
||||
last_indexes: &mut StoredVec<I, T2>,
|
||||
source: &mut StoredVec<T2, T>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
T: From<T2>,
|
||||
T2: StoredType + Copy + Add<usize, Output = T2> + Sub<T2, Output = T2> + TryInto<T>,
|
||||
<T2 as TryInto<T>>::Error: error::Error + 'static,
|
||||
T: From<usize> + Add<T, Output = T>,
|
||||
T2: StoredIndex + StoredType,
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + first_indexes.version() + last_indexes.version(),
|
||||
)?;
|
||||
|
||||
let index = max_from.min(I::from(self.len()));
|
||||
first_indexes.iter_from(index, |(index, first_index, ..)| {
|
||||
let last_index = last_indexes.get(index)?.unwrap();
|
||||
let count = *last_index + 1_usize - *first_index;
|
||||
self.forced_push_at(index, count.into(), exit)
|
||||
first_indexes.iter_from(index, |(i, first_index, ..)| {
|
||||
let last_index = last_indexes.double_unwrap_cached_get(i);
|
||||
let range = first_index.unwrap_to_usize()..=last_index.unwrap_to_usize();
|
||||
let mut sum = T::from(0_usize);
|
||||
range.into_iter().for_each(|i| {
|
||||
sum = sum.clone() + source.double_unwrap_cached_get(T2::from(i));
|
||||
});
|
||||
self.forced_push_at(i, sum, exit)
|
||||
})?;
|
||||
|
||||
Ok(self.safe_flush(exit)?)
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> Clone for StorableVec<I, T>
|
||||
impl<I> ComputedVec<I, Bitcoin>
|
||||
where
|
||||
I: StoredIndex,
|
||||
{
|
||||
pub fn compute_from_sats(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
sats: &mut StoredVec<I, Sats>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + sats.version(),
|
||||
)?;
|
||||
|
||||
let index = max_from.min(I::from(self.len()));
|
||||
sats.iter_from(index, |(i, sats, ..)| {
|
||||
let (i, v) = (i, Bitcoin::from(sats));
|
||||
self.forced_push_at(i, v, exit)
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
}
|
||||
|
||||
impl ComputedVec<Height, Dollars> {
|
||||
pub fn compute_from_bitcoin(
|
||||
&mut self,
|
||||
max_from: Height,
|
||||
bitcoin: &mut StoredVec<Height, Bitcoin>,
|
||||
price: &mut StoredVec<Height, Close<Dollars>>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + bitcoin.version(),
|
||||
)?;
|
||||
|
||||
let index = max_from.min(Height::from(self.len()));
|
||||
bitcoin.iter_from(index, |(i, bitcoin, ..)| {
|
||||
let dollars = price.double_unwrap_cached_get(i);
|
||||
let (i, v) = (i, *dollars * bitcoin);
|
||||
self.forced_push_at(i, v, exit)
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
}
|
||||
|
||||
impl ComputedVec<Txindex, Dollars> {
|
||||
pub fn compute_from_bitcoin(
|
||||
&mut self,
|
||||
max_from: Txindex,
|
||||
bitcoin: &mut StoredVec<Txindex, Bitcoin>,
|
||||
i_to_height: &mut StoredVec<Txindex, Height>,
|
||||
price: &mut StoredVec<Height, Close<Dollars>>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + bitcoin.version(),
|
||||
)?;
|
||||
|
||||
let index = max_from.min(Txindex::from(self.len()));
|
||||
bitcoin.iter_from(index, |(i, bitcoin, ..)| {
|
||||
let height = i_to_height.double_unwrap_cached_get(i);
|
||||
let dollars = price.double_unwrap_cached_get(height);
|
||||
let (i, v) = (i, *dollars * bitcoin);
|
||||
self.forced_push_at(i, v, exit)
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> Clone for ComputedVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
@@ -324,7 +499,7 @@ where
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
computed_version: self.computed_version,
|
||||
vec: self.vec.clone(),
|
||||
inner: self.inner.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use brk_core::{CheckedSub, Dateindex, Height, Timestamp};
|
||||
use brk_core::{CheckedSub, Height, StoredU32, StoredU64, StoredUsize, Timestamp, Weight};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyStorableVec, Compressed, Version};
|
||||
use brk_parser::bitcoin;
|
||||
use brk_vec::{Compressed, Version};
|
||||
|
||||
use super::{
|
||||
Indexes, StorableVec, indexes,
|
||||
stats::{StorableVecGeneatorOptions, StorableVecsStatsFromHeight},
|
||||
Indexes,
|
||||
base::ComputedVec,
|
||||
grouped::{ComputedVecsFromHeight, StorableVecGeneatorOptions},
|
||||
indexes,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vecs {
|
||||
pub height_to_block_interval: StorableVec<Height, Timestamp>,
|
||||
pub indexes_to_block_interval_stats: StorableVecsStatsFromHeight<Timestamp>,
|
||||
pub dateindex_to_block_count: StorableVec<Dateindex, u16>,
|
||||
pub dateindex_to_total_block_count: StorableVec<Dateindex, u32>,
|
||||
pub height_to_interval: ComputedVec<Height, Timestamp>,
|
||||
pub indexes_to_block_interval: ComputedVecsFromHeight<Timestamp>,
|
||||
pub indexes_to_block_count: ComputedVecsFromHeight<StoredU32>,
|
||||
pub indexes_to_block_weight: ComputedVecsFromHeight<Weight>,
|
||||
pub height_to_vbytes: ComputedVec<Height, StoredU64>,
|
||||
pub indexes_to_block_vbytes: ComputedVecsFromHeight<StoredU64>,
|
||||
pub indexes_to_block_size: ComputedVecsFromHeight<StoredUsize>,
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
@@ -23,28 +29,58 @@ impl Vecs {
|
||||
fs::create_dir_all(path)?;
|
||||
|
||||
Ok(Self {
|
||||
height_to_block_interval: StorableVec::forced_import(
|
||||
&path.join("height_to_block_interval"),
|
||||
Version::ONE,
|
||||
height_to_interval: ComputedVec::forced_import(
|
||||
&path.join("height_to_interval"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
indexes_to_block_interval_stats: StorableVecsStatsFromHeight::forced_import(
|
||||
&path.join("block_interval"),
|
||||
indexes_to_block_interval: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"block_interval",
|
||||
false,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_percentiles()
|
||||
.add_minmax()
|
||||
.add_average(),
|
||||
)?,
|
||||
dateindex_to_block_count: StorableVec::forced_import(
|
||||
&path.join("dateindex_to_block_count"),
|
||||
Version::ONE,
|
||||
indexes_to_block_count: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"block_count",
|
||||
true,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_sum().add_total(),
|
||||
)?,
|
||||
indexes_to_block_weight: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"block_weight",
|
||||
false,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_sum().add_total(),
|
||||
)?,
|
||||
indexes_to_block_size: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"block_size",
|
||||
false,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_sum().add_total(),
|
||||
)?,
|
||||
height_to_vbytes: ComputedVec::forced_import(
|
||||
&path.join("height_to_vbytes"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
dateindex_to_total_block_count: StorableVec::forced_import(
|
||||
&path.join("dateindex_to_total_block_count"),
|
||||
Version::ONE,
|
||||
indexes_to_block_vbytes: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"block_vbytes",
|
||||
false,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_sum().add_total(),
|
||||
)?,
|
||||
})
|
||||
}
|
||||
@@ -56,14 +92,12 @@ impl Vecs {
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
let indexer_vecs = indexer.mut_vecs();
|
||||
|
||||
self.height_to_block_interval.compute_transform(
|
||||
self.height_to_interval.compute_transform(
|
||||
starting_indexes.height,
|
||||
indexer_vecs.height_to_timestamp.mut_vec(),
|
||||
indexer.mut_vecs().height_to_timestamp.mut_vec(),
|
||||
|(height, timestamp, _, height_to_timestamp)| {
|
||||
let interval = height.decremented().map_or(Timestamp::ZERO, |prev_h| {
|
||||
let prev_timestamp = *height_to_timestamp.get(prev_h).unwrap().unwrap();
|
||||
let prev_timestamp = height_to_timestamp.double_unwrap_cached_get(prev_h);
|
||||
timestamp
|
||||
.checked_sub(prev_timestamp)
|
||||
.unwrap_or(Timestamp::ZERO)
|
||||
@@ -73,24 +107,75 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.indexes_to_block_interval_stats.compute(
|
||||
&mut self.height_to_block_interval,
|
||||
self.indexes_to_block_interval.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(self.height_to_interval.mut_vec()),
|
||||
)?;
|
||||
|
||||
self.indexes_to_block_count.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, indexer, _, starting_indexes, exit| {
|
||||
v.compute_transform(
|
||||
starting_indexes.height,
|
||||
indexer.mut_vecs().height_to_weight.mut_vec(),
|
||||
|(h, ..)| (h, StoredU32::from(1_u32)),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
self.indexes_to_block_weight.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(indexer.mut_vecs().height_to_weight.mut_vec()),
|
||||
)?;
|
||||
|
||||
self.indexes_to_block_size.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(indexer.mut_vecs().height_to_total_size.mut_vec()),
|
||||
)?;
|
||||
|
||||
self.height_to_vbytes.compute_transform(
|
||||
starting_indexes.height,
|
||||
indexer.mut_vecs().height_to_weight.mut_vec(),
|
||||
|(h, w, ..)| {
|
||||
(
|
||||
h,
|
||||
StoredU64::from(bitcoin::Weight::from(w).to_vbytes_floor()),
|
||||
)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.indexes_to_block_vbytes.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(self.height_to_vbytes.mut_vec()),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn brk_vec::AnyStoredVec> {
|
||||
[
|
||||
vec![
|
||||
self.height_to_block_interval.any_vec(),
|
||||
self.dateindex_to_block_count.any_vec(),
|
||||
self.dateindex_to_total_block_count.any_vec(),
|
||||
self.height_to_interval.any_vec(),
|
||||
self.height_to_vbytes.any_vec(),
|
||||
],
|
||||
self.indexes_to_block_interval_stats.as_any_vecs(),
|
||||
self.indexes_to_block_interval.any_vecs(),
|
||||
self.indexes_to_block_count.any_vecs(),
|
||||
self.indexes_to_block_weight.any_vecs(),
|
||||
self.indexes_to_block_size.any_vecs(),
|
||||
self.indexes_to_block_vbytes.any_vecs(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
|
||||
+278
-89
@@ -1,112 +1,210 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_exit::Exit;
|
||||
use brk_vec::{AnyStorableVec, Compressed, Result, StoredIndex, StoredType, Version};
|
||||
use brk_vec::{
|
||||
Compressed, DynamicVec, GenericVec, Result, StoredIndex, StoredType, StoredVec, Version,
|
||||
};
|
||||
use color_eyre::eyre::ContextCompat;
|
||||
|
||||
use crate::storage::vecs::base::StorableVec;
|
||||
use crate::storage::vecs::base::ComputedVec;
|
||||
|
||||
use super::ComputedType;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StorableVecBuilder<I, T>
|
||||
pub struct ComputedVecBuilder<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: ComputedType,
|
||||
{
|
||||
pub first: Option<StorableVec<I, T>>,
|
||||
pub average: Option<StorableVec<I, T>>,
|
||||
pub sum: Option<StorableVec<I, T>>,
|
||||
pub max: Option<StorableVec<I, T>>,
|
||||
pub _90p: Option<StorableVec<I, T>>,
|
||||
pub _75p: Option<StorableVec<I, T>>,
|
||||
pub median: Option<StorableVec<I, T>>,
|
||||
pub _25p: Option<StorableVec<I, T>>,
|
||||
pub _10p: Option<StorableVec<I, T>>,
|
||||
pub min: Option<StorableVec<I, T>>,
|
||||
pub last: Option<StorableVec<I, T>>,
|
||||
first: Option<ComputedVec<I, T>>,
|
||||
average: Option<ComputedVec<I, T>>,
|
||||
sum: Option<ComputedVec<I, T>>,
|
||||
max: Option<ComputedVec<I, T>>,
|
||||
_90p: Option<ComputedVec<I, T>>,
|
||||
_75p: Option<ComputedVec<I, T>>,
|
||||
median: Option<ComputedVec<I, T>>,
|
||||
_25p: Option<ComputedVec<I, T>>,
|
||||
_10p: Option<ComputedVec<I, T>>,
|
||||
min: Option<ComputedVec<I, T>>,
|
||||
last: Option<ComputedVec<I, T>>,
|
||||
total: Option<ComputedVec<I, T>>,
|
||||
}
|
||||
|
||||
impl<I, T> StorableVecBuilder<I, T>
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<I, T> ComputedVecBuilder<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: ComputedType,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
version: Version,
|
||||
compressed: Compressed,
|
||||
options: StorableVecGeneatorOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let name = path.file_name().unwrap().to_str().unwrap().to_string();
|
||||
let key = I::to_string().split("::").last().unwrap().to_lowercase();
|
||||
|
||||
let only_one_active = options.is_only_one_active();
|
||||
|
||||
let prefix = |s: &str| {
|
||||
let default = || path.join(format!("{key}_to_{name}"));
|
||||
|
||||
let prefix = |s: &str| path.join(format!("{key}_to_{s}_{name}"));
|
||||
|
||||
let maybe_prefix = |s: &str| {
|
||||
if only_one_active {
|
||||
path.with_file_name(format!("{key}_to_{name}"))
|
||||
default()
|
||||
} else {
|
||||
path.with_file_name(format!("{key}_to_{s}_{name}"))
|
||||
prefix(s)
|
||||
}
|
||||
};
|
||||
|
||||
let suffix = |s: &str| {
|
||||
let suffix = |s: &str| path.join(format!("{key}_to_{name}_{s}"));
|
||||
|
||||
let maybe_suffix = |s: &str| {
|
||||
if only_one_active {
|
||||
path.with_file_name(format!("{key}_to_{name}"))
|
||||
default()
|
||||
} else {
|
||||
path.with_file_name(format!("{key}_to_{name}_{s}"))
|
||||
suffix(s)
|
||||
}
|
||||
};
|
||||
|
||||
let version = VERSION + version;
|
||||
|
||||
let s = Self {
|
||||
first: options.first.then(|| {
|
||||
StorableVec::forced_import(&prefix("first"), Version::ONE, compressed).unwrap()
|
||||
ComputedVec::forced_import(
|
||||
&maybe_prefix("first"),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
last: options.last.then(|| {
|
||||
StorableVec::forced_import(
|
||||
&path.with_file_name(format!("{key}_to_{name}")),
|
||||
Version::ONE,
|
||||
ComputedVec::forced_import(
|
||||
&path.join(format!("{key}_to_{name}")),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
min: options.min.then(|| {
|
||||
StorableVec::forced_import(&suffix("min"), Version::ONE, compressed).unwrap()
|
||||
ComputedVec::forced_import(
|
||||
&maybe_suffix("min"),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
max: options.max.then(|| {
|
||||
StorableVec::forced_import(&suffix("max"), Version::ONE, compressed).unwrap()
|
||||
ComputedVec::forced_import(
|
||||
&maybe_suffix("max"),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
median: options.median.then(|| {
|
||||
StorableVec::forced_import(&suffix("median"), Version::ONE, compressed).unwrap()
|
||||
ComputedVec::forced_import(
|
||||
&maybe_suffix("median"),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
average: options.average.then(|| {
|
||||
StorableVec::forced_import(&suffix("average"), Version::ONE, compressed).unwrap()
|
||||
ComputedVec::forced_import(
|
||||
&maybe_suffix("average"),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
sum: options.sum.then(|| {
|
||||
StorableVec::forced_import(&suffix("sum"), Version::ONE, compressed).unwrap()
|
||||
ComputedVec::forced_import(
|
||||
&maybe_suffix("sum"),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
total: options.total.then(|| {
|
||||
ComputedVec::forced_import(&prefix("total"), version + Version::ZERO, compressed)
|
||||
.unwrap()
|
||||
}),
|
||||
_90p: options._90p.then(|| {
|
||||
StorableVec::forced_import(&suffix("90p"), Version::ONE, compressed).unwrap()
|
||||
ComputedVec::forced_import(
|
||||
&maybe_suffix("90p"),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
_75p: options._75p.then(|| {
|
||||
StorableVec::forced_import(&suffix("75p"), Version::ONE, compressed).unwrap()
|
||||
ComputedVec::forced_import(
|
||||
&maybe_suffix("75p"),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
_25p: options._25p.then(|| {
|
||||
StorableVec::forced_import(&suffix("25p"), Version::ONE, compressed).unwrap()
|
||||
ComputedVec::forced_import(
|
||||
&maybe_suffix("25p"),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
_10p: options._10p.then(|| {
|
||||
StorableVec::forced_import(&suffix("10p"), Version::ONE, compressed).unwrap()
|
||||
ComputedVec::forced_import(
|
||||
&maybe_suffix("10p"),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
};
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
pub fn extend(&mut self, max_from: I, source: &mut StoredVec<I, T>, exit: &Exit) -> Result<()> {
|
||||
if self.total.is_none() {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let index = self.starting_index(max_from);
|
||||
|
||||
let total_vec = self.total.as_mut().unwrap();
|
||||
|
||||
source.iter_from(index, |(i, v, ..)| {
|
||||
let prev = i
|
||||
.unwrap_to_usize()
|
||||
.checked_sub(1)
|
||||
.map_or(T::from(0_usize), |prev_i| {
|
||||
total_vec
|
||||
.unwrap_cached_get(I::from(prev_i))
|
||||
.unwrap_or(T::from(0_usize))
|
||||
});
|
||||
let value = v.clone() + prev;
|
||||
total_vec.forced_push_at(i, value, exit)?;
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute<I2>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
source: &mut StorableVec<I2, T>,
|
||||
first_indexes: &mut brk_vec::StorableVec<I, I2>,
|
||||
last_indexes: &mut brk_vec::StorableVec<I, I2>,
|
||||
source: &mut StoredVec<I2, T>,
|
||||
first_indexes: &mut StoredVec<I, I2>,
|
||||
last_indexes: &mut StoredVec<I, I2>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
@@ -116,24 +214,21 @@ where
|
||||
{
|
||||
let index = self.starting_index(max_from);
|
||||
|
||||
first_indexes.iter_from(index, |(i, first_index)| {
|
||||
let first_index = *first_index;
|
||||
let last_index = *last_indexes.get(i).unwrap().unwrap();
|
||||
first_indexes.iter_from(index, |(i, first_index, first_indexes)| {
|
||||
let last_index = last_indexes.double_unwrap_cached_get(i);
|
||||
|
||||
if let Some(first) = self.first.as_mut() {
|
||||
let v = source.get(first_index).unwrap().unwrap();
|
||||
first.forced_push_at(index, v.clone(), exit)?;
|
||||
let v = source.double_unwrap_cached_get(first_index);
|
||||
first.forced_push_at(index, v, exit)?;
|
||||
}
|
||||
|
||||
if let Some(last) = self.last.as_mut() {
|
||||
let v = source.get(last_index).unwrap().unwrap();
|
||||
last.forced_push_at(index, v.clone(), exit)?;
|
||||
let v = source.double_unwrap_cached_get(last_index);
|
||||
last.forced_push_at(index, v, exit)?;
|
||||
}
|
||||
|
||||
let first_index = first_index.to_usize()?;
|
||||
let last_index = last_index.to_usize()?;
|
||||
|
||||
let needs_sum_or_average = self.sum.is_some() || self.average.is_some();
|
||||
let needs_sum_or_total = self.sum.is_some() || self.total.is_some();
|
||||
let needs_average_sum_or_total = needs_sum_or_total || self.average.is_some();
|
||||
let needs_sorted = self.max.is_some()
|
||||
|| self._90p.is_some()
|
||||
|| self._75p.is_some()
|
||||
@@ -141,17 +236,36 @@ where
|
||||
|| self._25p.is_some()
|
||||
|| self._10p.is_some()
|
||||
|| self.min.is_some();
|
||||
let needs_values = needs_sorted || needs_sum_or_average;
|
||||
let needs_values = needs_sorted || needs_average_sum_or_total;
|
||||
|
||||
if needs_values {
|
||||
let mut values =
|
||||
source.collect_range(Some(first_index as i64), Some(last_index as i64))?;
|
||||
let mut values = source.collect_inclusive_range(first_index, last_index)?;
|
||||
|
||||
if needs_sorted {
|
||||
values.sort_unstable();
|
||||
|
||||
if let Some(max) = self.max.as_mut() {
|
||||
max.forced_push_at(i, values.last().unwrap().clone(), exit)?;
|
||||
max.forced_push_at(
|
||||
i,
|
||||
values
|
||||
.last()
|
||||
.context("expect some")
|
||||
.inspect_err(|_| {
|
||||
dbg!(
|
||||
&values,
|
||||
max.path(),
|
||||
first_indexes.path(),
|
||||
first_index,
|
||||
last_indexes.path(),
|
||||
last_index,
|
||||
source.len(),
|
||||
source.path()
|
||||
);
|
||||
})
|
||||
.unwrap()
|
||||
.clone(),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(_90p) = self._90p.as_mut() {
|
||||
@@ -179,7 +293,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
if needs_sum_or_average {
|
||||
if needs_average_sum_or_total {
|
||||
let len = values.len();
|
||||
|
||||
if let Some(average) = self.average.as_mut() {
|
||||
@@ -192,9 +306,22 @@ where
|
||||
average.forced_push_at(i, avg, exit)?;
|
||||
}
|
||||
|
||||
if let Some(sum_vec) = self.sum.as_mut() {
|
||||
if needs_sum_or_total {
|
||||
let sum = values.into_iter().fold(T::from(0), |a, b| a + b);
|
||||
sum_vec.forced_push_at(i, sum, exit)?;
|
||||
|
||||
if let Some(sum_vec) = self.sum.as_mut() {
|
||||
sum_vec.forced_push_at(i, sum.clone(), exit)?;
|
||||
}
|
||||
|
||||
if let Some(total_vec) = self.total.as_mut() {
|
||||
let prev = i
|
||||
.unwrap_to_usize()
|
||||
.checked_sub(1)
|
||||
.map_or(T::from(0_usize), |prev_i| {
|
||||
total_vec.double_unwrap_cached_get(I::from(prev_i))
|
||||
});
|
||||
total_vec.forced_push_at(i, prev + sum, exit)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -211,9 +338,9 @@ where
|
||||
pub fn from_aligned<I2>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
source: &mut StorableVecBuilder<I2, T>,
|
||||
first_indexes: &mut brk_vec::StorableVec<I, I2>,
|
||||
last_indexes: &mut brk_vec::StorableVec<I, I2>,
|
||||
source: &mut ComputedVecBuilder<I2, T>,
|
||||
first_indexes: &mut StoredVec<I, I2>,
|
||||
last_indexes: &mut StoredVec<I, I2>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
@@ -232,19 +359,15 @@ where
|
||||
|
||||
let index = self.starting_index(max_from);
|
||||
|
||||
first_indexes.iter_from(index, |(i, first_index)| {
|
||||
let first_index = *first_index;
|
||||
let last_index = *last_indexes.get(i).unwrap().unwrap();
|
||||
first_indexes.iter_from(index, |(i, first_index, ..)| {
|
||||
let last_index = last_indexes.double_unwrap_cached_get(i);
|
||||
|
||||
if let Some(first) = self.first.as_mut() {
|
||||
let v = source
|
||||
.first
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.get(first_index)
|
||||
.unwrap()
|
||||
.cloned()
|
||||
.unwrap();
|
||||
.double_unwrap_cached_get(first_index);
|
||||
first.forced_push_at(index, v, exit)?;
|
||||
}
|
||||
|
||||
@@ -253,19 +376,14 @@ where
|
||||
.last
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.get(last_index)
|
||||
.unwrap()
|
||||
.cloned()
|
||||
.unwrap();
|
||||
.double_unwrap_cached_get(last_index);
|
||||
last.forced_push_at(index, v, exit)?;
|
||||
}
|
||||
|
||||
let first_index = Some(first_index.to_usize()? as i64);
|
||||
let last_index = Some(last_index.to_usize()? as i64);
|
||||
|
||||
let needs_sum_or_average = self.sum.is_some() || self.average.is_some();
|
||||
let needs_sum_or_total = self.sum.is_some() || self.total.is_some();
|
||||
let needs_average_sum_or_total = needs_sum_or_total || self.average.is_some();
|
||||
let needs_sorted = self.max.is_some() || self.min.is_some();
|
||||
let needs_values = needs_sorted || needs_sum_or_average;
|
||||
let needs_values = needs_sorted || needs_average_sum_or_total;
|
||||
|
||||
if needs_values {
|
||||
if needs_sorted {
|
||||
@@ -274,7 +392,7 @@ where
|
||||
.max
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.collect_range(first_index, last_index)?;
|
||||
.collect_inclusive_range(first_index, last_index)?;
|
||||
values.sort_unstable();
|
||||
max.forced_push_at(i, values.last().unwrap().clone(), exit)?;
|
||||
}
|
||||
@@ -284,19 +402,19 @@ where
|
||||
.min
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.collect_range(first_index, last_index)?;
|
||||
.collect_inclusive_range(first_index, last_index)?;
|
||||
values.sort_unstable();
|
||||
min.forced_push_at(i, values.first().unwrap().clone(), exit)?;
|
||||
}
|
||||
}
|
||||
|
||||
if needs_sum_or_average {
|
||||
if needs_average_sum_or_total {
|
||||
if let Some(average) = self.average.as_mut() {
|
||||
let values = source
|
||||
.average
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.collect_range(first_index, last_index)?;
|
||||
.collect_inclusive_range(first_index, last_index)?;
|
||||
let len = values.len() as f64;
|
||||
let total = values
|
||||
.into_iter()
|
||||
@@ -308,14 +426,27 @@ where
|
||||
average.forced_push_at(i, avg, exit)?;
|
||||
}
|
||||
|
||||
if let Some(sum_vec) = self.sum.as_mut() {
|
||||
if needs_sum_or_total {
|
||||
let values = source
|
||||
.sum
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.collect_range(first_index, last_index)?;
|
||||
.collect_inclusive_range(first_index, last_index)?;
|
||||
let sum = values.into_iter().fold(T::from(0), |a, b| a + b);
|
||||
sum_vec.forced_push_at(i, sum, exit)?;
|
||||
|
||||
if let Some(sum_vec) = self.sum.as_mut() {
|
||||
sum_vec.forced_push_at(i, sum.clone(), exit)?;
|
||||
}
|
||||
|
||||
if let Some(total_vec) = self.total.as_mut() {
|
||||
let prev = i
|
||||
.unwrap_to_usize()
|
||||
.checked_sub(1)
|
||||
.map_or(T::from(0_usize), |prev_i| {
|
||||
total_vec.double_unwrap_cached_get(I::from(prev_i))
|
||||
});
|
||||
total_vec.forced_push_at(i, prev + sum, exit)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -352,16 +483,49 @@ where
|
||||
|
||||
fn starting_index(&self, max_from: I) -> I {
|
||||
max_from.min(I::from(
|
||||
self.as_any_vecs()
|
||||
.into_iter()
|
||||
.map(|v| v.len())
|
||||
.min()
|
||||
.unwrap(),
|
||||
self.any_vecs().into_iter().map(|v| v.len()).min().unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
|
||||
let mut v: Vec<&dyn AnyStorableVec> = vec![];
|
||||
pub fn unwrap_first(&mut self) -> &mut ComputedVec<I, T> {
|
||||
self.first.as_mut().unwrap()
|
||||
}
|
||||
pub fn unwrap_average(&mut self) -> &mut ComputedVec<I, T> {
|
||||
self.average.as_mut().unwrap()
|
||||
}
|
||||
pub fn unwrap_sum(&mut self) -> &mut ComputedVec<I, T> {
|
||||
self.sum.as_mut().unwrap()
|
||||
}
|
||||
pub fn unwrap_max(&mut self) -> &mut ComputedVec<I, T> {
|
||||
self.max.as_mut().unwrap()
|
||||
}
|
||||
pub fn unwrap_90p(&mut self) -> &mut ComputedVec<I, T> {
|
||||
self._90p.as_mut().unwrap()
|
||||
}
|
||||
pub fn unwrap_75p(&mut self) -> &mut ComputedVec<I, T> {
|
||||
self._75p.as_mut().unwrap()
|
||||
}
|
||||
pub fn unwrap_median(&mut self) -> &mut ComputedVec<I, T> {
|
||||
self.median.as_mut().unwrap()
|
||||
}
|
||||
pub fn unwrap_25p(&mut self) -> &mut ComputedVec<I, T> {
|
||||
self._25p.as_mut().unwrap()
|
||||
}
|
||||
pub fn unwrap_10p(&mut self) -> &mut ComputedVec<I, T> {
|
||||
self._10p.as_mut().unwrap()
|
||||
}
|
||||
pub fn unwrap_min(&mut self) -> &mut ComputedVec<I, T> {
|
||||
self.min.as_mut().unwrap()
|
||||
}
|
||||
pub fn unwrap_last(&mut self) -> &mut ComputedVec<I, T> {
|
||||
self.last.as_mut().unwrap()
|
||||
}
|
||||
pub fn unwrap_total(&mut self) -> &mut ComputedVec<I, T> {
|
||||
self.total.as_mut().unwrap()
|
||||
}
|
||||
|
||||
pub fn any_vecs(&self) -> Vec<&dyn brk_vec::AnyStoredVec> {
|
||||
let mut v: Vec<&dyn brk_vec::AnyStoredVec> = vec![];
|
||||
|
||||
if let Some(first) = self.first.as_ref() {
|
||||
v.push(first.any_vec());
|
||||
@@ -384,6 +548,9 @@ where
|
||||
if let Some(sum) = self.sum.as_ref() {
|
||||
v.push(sum.any_vec());
|
||||
}
|
||||
if let Some(total) = self.total.as_ref() {
|
||||
v.push(total.any_vec());
|
||||
}
|
||||
if let Some(_90p) = self._90p.as_ref() {
|
||||
v.push(_90p.any_vec());
|
||||
}
|
||||
@@ -422,6 +589,9 @@ where
|
||||
if let Some(sum) = self.sum.as_mut() {
|
||||
sum.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(total) = self.total.as_mut() {
|
||||
total.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(_90p) = self._90p.as_mut() {
|
||||
_90p.safe_flush(exit)?;
|
||||
}
|
||||
@@ -452,6 +622,7 @@ pub struct StorableVecGeneatorOptions {
|
||||
min: bool,
|
||||
first: bool,
|
||||
last: bool,
|
||||
total: bool,
|
||||
}
|
||||
|
||||
impl StorableVecGeneatorOptions {
|
||||
@@ -510,6 +681,11 @@ impl StorableVecGeneatorOptions {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_total(mut self) -> Self {
|
||||
self.total = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_min(mut self) -> Self {
|
||||
self.min = false;
|
||||
self
|
||||
@@ -555,6 +731,11 @@ impl StorableVecGeneatorOptions {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_total(mut self) -> Self {
|
||||
self.total = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_minmax(mut self) -> Self {
|
||||
self.min = true;
|
||||
self.max = true;
|
||||
@@ -592,10 +773,18 @@ impl StorableVecGeneatorOptions {
|
||||
self.min,
|
||||
self.first,
|
||||
self.last,
|
||||
self.total,
|
||||
]
|
||||
.iter()
|
||||
.filter(|b| **b)
|
||||
.count()
|
||||
== 1
|
||||
}
|
||||
|
||||
pub fn copy_self_extra(&self) -> Self {
|
||||
Self {
|
||||
total: self.total,
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{Dateindex, Decadeindex, Monthindex, Quarterindex, Weekindex, Yearindex};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyStoredVec, Compressed, Result, Version};
|
||||
|
||||
use crate::storage::vecs::{Indexes, base::ComputedVec, indexes};
|
||||
|
||||
use super::{ComputedType, ComputedVecBuilder, StorableVecGeneatorOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedVecsFromDateindex<T>
|
||||
where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub dateindex: ComputedVec<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 + Ord + From<f64>,
|
||||
f64: From<T>,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
version: Version,
|
||||
compressed: Compressed,
|
||||
options: StorableVecGeneatorOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let version = VERSION + version;
|
||||
|
||||
let dateindex_extra = ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version,
|
||||
compressed,
|
||||
options.copy_self_extra(),
|
||||
)?;
|
||||
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
Ok(Self {
|
||||
dateindex: ComputedVec::forced_import(
|
||||
&path.join(format!("dateindex_to_{name}")),
|
||||
version,
|
||||
compressed,
|
||||
)?,
|
||||
dateindex_extra,
|
||||
weekindex: ComputedVecBuilder::forced_import(path, name, version, compressed, options)?,
|
||||
monthindex: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
quarterindex: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
yearindex: ComputedVecBuilder::forced_import(path, name, version, compressed, options)?,
|
||||
decadeindex: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute<F>(
|
||||
&mut self,
|
||||
indexer: &mut Indexer,
|
||||
indexes: &mut indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(
|
||||
&mut ComputedVec<Dateindex, T>,
|
||||
&mut Indexer,
|
||||
&mut indexes::Vecs,
|
||||
&Indexes,
|
||||
&Exit,
|
||||
) -> Result<()>,
|
||||
{
|
||||
compute(
|
||||
&mut self.dateindex,
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.dateindex_extra
|
||||
.extend(starting_indexes.dateindex, self.dateindex.mut_vec(), exit)?;
|
||||
|
||||
self.weekindex.compute(
|
||||
starting_indexes.weekindex,
|
||||
self.dateindex.mut_vec(),
|
||||
indexes.weekindex_to_first_dateindex.mut_vec(),
|
||||
indexes.weekindex_to_last_dateindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex.compute(
|
||||
starting_indexes.monthindex,
|
||||
self.dateindex.mut_vec(),
|
||||
indexes.monthindex_to_first_dateindex.mut_vec(),
|
||||
indexes.monthindex_to_last_dateindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.quarterindex.from_aligned(
|
||||
starting_indexes.quarterindex,
|
||||
&mut self.monthindex,
|
||||
indexes.quarterindex_to_first_monthindex.mut_vec(),
|
||||
indexes.quarterindex_to_last_monthindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex.from_aligned(
|
||||
starting_indexes.yearindex,
|
||||
&mut self.monthindex,
|
||||
indexes.yearindex_to_first_monthindex.mut_vec(),
|
||||
indexes.yearindex_to_last_monthindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex.from_aligned(
|
||||
starting_indexes.decadeindex,
|
||||
&mut self.yearindex,
|
||||
indexes.decadeindex_to_first_yearindex.mut_vec(),
|
||||
indexes.decadeindex_to_last_yearindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn any_vecs(&self) -> Vec<&dyn AnyStoredVec> {
|
||||
[
|
||||
vec![self.dateindex.any_vec()],
|
||||
self.dateindex_extra.any_vecs(),
|
||||
self.weekindex.any_vecs(),
|
||||
self.monthindex.any_vecs(),
|
||||
self.quarterindex.any_vecs(),
|
||||
self.yearindex.any_vecs(),
|
||||
self.decadeindex.any_vecs(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{
|
||||
Dateindex, Decadeindex, Difficultyepoch, Height, Monthindex, Quarterindex, Weekindex, Yearindex,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyStoredVec, Compressed, Result, StoredVec, Version};
|
||||
|
||||
use crate::storage::vecs::{Indexes, base::ComputedVec, indexes};
|
||||
|
||||
use super::{ComputedType, ComputedVecBuilder, StorableVecGeneatorOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedVecsFromHeight<T>
|
||||
where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub height: Option<ComputedVec<Height, T>>,
|
||||
pub height_extra: ComputedVecBuilder<Height, T>,
|
||||
pub dateindex: ComputedVecBuilder<Dateindex, T>,
|
||||
pub weekindex: ComputedVecBuilder<Weekindex, T>,
|
||||
pub difficultyepoch: ComputedVecBuilder<Difficultyepoch, T>,
|
||||
pub monthindex: ComputedVecBuilder<Monthindex, T>,
|
||||
pub quarterindex: ComputedVecBuilder<Quarterindex, T>,
|
||||
pub yearindex: ComputedVecBuilder<Yearindex, T>,
|
||||
// TODO: pub halvingepoch: StorableVecGeneator<Halvingepoch, T>,
|
||||
pub decadeindex: ComputedVecBuilder<Decadeindex, T>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<T> ComputedVecsFromHeight<T>
|
||||
where
|
||||
T: ComputedType + Ord + From<f64>,
|
||||
f64: From<T>,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
compute_source: bool,
|
||||
version: Version,
|
||||
compressed: Compressed,
|
||||
options: StorableVecGeneatorOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let version = VERSION + version;
|
||||
|
||||
let height = compute_source.then(|| {
|
||||
ComputedVec::forced_import(&path.join(format!("height_to_{name}")), version, compressed)
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
let height_extra = ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version,
|
||||
compressed,
|
||||
options.copy_self_extra(),
|
||||
)?;
|
||||
|
||||
let dateindex =
|
||||
ComputedVecBuilder::forced_import(path, name, version, compressed, options)?;
|
||||
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
Ok(Self {
|
||||
height,
|
||||
height_extra,
|
||||
dateindex,
|
||||
weekindex: ComputedVecBuilder::forced_import(path, name, version, compressed, options)?,
|
||||
difficultyepoch: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
monthindex: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
quarterindex: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
yearindex: ComputedVecBuilder::forced_import(path, name, version, compressed, options)?,
|
||||
// halvingepoch: StorableVecGeneator::forced_import(path, name, version, compressed, options)?,
|
||||
decadeindex: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute_all<F>(
|
||||
&mut self,
|
||||
indexer: &mut Indexer,
|
||||
indexes: &mut indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(
|
||||
&mut ComputedVec<Height, T>,
|
||||
&mut Indexer,
|
||||
&mut indexes::Vecs,
|
||||
&Indexes,
|
||||
&Exit,
|
||||
) -> Result<()>,
|
||||
{
|
||||
compute(
|
||||
self.height.as_mut().unwrap(),
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.compute_rest(indexes, starting_indexes, exit, None)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
indexes: &mut indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
height: Option<&mut StoredVec<Height, T>>,
|
||||
) -> color_eyre::Result<()> {
|
||||
let height = height.unwrap_or_else(|| self.height.as_mut().unwrap().mut_vec());
|
||||
|
||||
self.height_extra
|
||||
.extend(starting_indexes.height, height, exit)?;
|
||||
|
||||
self.dateindex.compute(
|
||||
starting_indexes.dateindex,
|
||||
height,
|
||||
indexes.dateindex_to_first_height.mut_vec(),
|
||||
indexes.dateindex_to_last_height.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.weekindex.from_aligned(
|
||||
starting_indexes.weekindex,
|
||||
&mut self.dateindex,
|
||||
indexes.weekindex_to_first_dateindex.mut_vec(),
|
||||
indexes.weekindex_to_last_dateindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex.from_aligned(
|
||||
starting_indexes.monthindex,
|
||||
&mut self.dateindex,
|
||||
indexes.monthindex_to_first_dateindex.mut_vec(),
|
||||
indexes.monthindex_to_last_dateindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.quarterindex.from_aligned(
|
||||
starting_indexes.quarterindex,
|
||||
&mut self.monthindex,
|
||||
indexes.quarterindex_to_first_monthindex.mut_vec(),
|
||||
indexes.quarterindex_to_last_monthindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex.from_aligned(
|
||||
starting_indexes.yearindex,
|
||||
&mut self.monthindex,
|
||||
indexes.yearindex_to_first_monthindex.mut_vec(),
|
||||
indexes.yearindex_to_last_monthindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex.from_aligned(
|
||||
starting_indexes.decadeindex,
|
||||
&mut self.yearindex,
|
||||
indexes.decadeindex_to_first_yearindex.mut_vec(),
|
||||
indexes.decadeindex_to_last_yearindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.difficultyepoch.compute(
|
||||
starting_indexes.difficultyepoch,
|
||||
height,
|
||||
indexes.difficultyepoch_to_first_height.mut_vec(),
|
||||
indexes.difficultyepoch_to_last_height.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn any_vecs(&self) -> Vec<&dyn AnyStoredVec> {
|
||||
[
|
||||
self.height.as_ref().map_or(vec![], |v| vec![v.any_vec()]),
|
||||
self.height_extra.any_vecs(),
|
||||
self.dateindex.any_vecs(),
|
||||
self.weekindex.any_vecs(),
|
||||
self.difficultyepoch.any_vecs(),
|
||||
self.monthindex.any_vecs(),
|
||||
self.quarterindex.any_vecs(),
|
||||
self.yearindex.any_vecs(),
|
||||
// self.halvingepoch.as_any_vecs(),
|
||||
self.decadeindex.any_vecs(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{Difficultyepoch, Height};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyStoredVec, Compressed, Result, Version};
|
||||
|
||||
use crate::storage::vecs::{Indexes, base::ComputedVec, indexes};
|
||||
|
||||
use super::{ComputedType, ComputedVecBuilder, StorableVecGeneatorOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedVecsFromHeightStrict<T>
|
||||
where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub height: ComputedVec<Height, T>,
|
||||
pub height_extra: ComputedVecBuilder<Height, T>,
|
||||
pub difficultyepoch: ComputedVecBuilder<Difficultyepoch, T>,
|
||||
// TODO: pub halvingepoch: StorableVecGeneator<Halvingepoch, T>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<T> ComputedVecsFromHeightStrict<T>
|
||||
where
|
||||
T: ComputedType + Ord + From<f64>,
|
||||
f64: From<T>,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
version: Version,
|
||||
compressed: Compressed,
|
||||
options: StorableVecGeneatorOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let version = VERSION + version;
|
||||
|
||||
let height = ComputedVec::forced_import(
|
||||
&path.join(format!("height_to_{name}")),
|
||||
version,
|
||||
compressed,
|
||||
)?;
|
||||
|
||||
let height_extra = ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version,
|
||||
compressed,
|
||||
options.copy_self_extra(),
|
||||
)?;
|
||||
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
Ok(Self {
|
||||
height,
|
||||
height_extra,
|
||||
difficultyepoch: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
// halvingepoch: StorableVecGeneator::forced_import(path, name, version, compressed, options)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute<F>(
|
||||
&mut self,
|
||||
indexer: &mut Indexer,
|
||||
indexes: &mut indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(
|
||||
&mut ComputedVec<Height, T>,
|
||||
&mut Indexer,
|
||||
&mut indexes::Vecs,
|
||||
&Indexes,
|
||||
&Exit,
|
||||
) -> Result<()>,
|
||||
{
|
||||
compute(&mut self.height, indexer, indexes, starting_indexes, exit)?;
|
||||
|
||||
self.height_extra
|
||||
.extend(starting_indexes.height, self.height.mut_vec(), exit)?;
|
||||
|
||||
self.difficultyepoch.compute(
|
||||
starting_indexes.difficultyepoch,
|
||||
self.height.mut_vec(),
|
||||
indexes.difficultyepoch_to_first_height.mut_vec(),
|
||||
indexes.difficultyepoch_to_last_height.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn any_vecs(&self) -> Vec<&dyn AnyStoredVec> {
|
||||
[
|
||||
vec![self.height.any_vec()],
|
||||
self.height_extra.any_vecs(),
|
||||
self.difficultyepoch.any_vecs(),
|
||||
// self.halvingepoch.as_any_vecs(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{
|
||||
Dateindex, Decadeindex, Difficultyepoch, Height, Monthindex, Quarterindex, Txindex, Weekindex,
|
||||
Yearindex,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyStoredVec, Compressed, Result, StoredVec, Version};
|
||||
|
||||
use crate::storage::vecs::{Indexes, base::ComputedVec, indexes};
|
||||
|
||||
use super::{ComputedType, ComputedVecBuilder, StorableVecGeneatorOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedVecsFromTxindex<T>
|
||||
where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub txindex: Option<ComputedVec<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>,
|
||||
// TODO: pub halvingepoch: StorableVecGeneator<Halvingepoch, T>,
|
||||
pub decadeindex: ComputedVecBuilder<Decadeindex, T>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<T> ComputedVecsFromTxindex<T>
|
||||
where
|
||||
T: ComputedType + Ord + From<f64>,
|
||||
f64: From<T>,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
compute_source: bool,
|
||||
version: Version,
|
||||
compressed: Compressed,
|
||||
options: StorableVecGeneatorOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let version = VERSION + version;
|
||||
|
||||
let txindex = compute_source.then(|| {
|
||||
ComputedVec::forced_import(
|
||||
&path.join(format!("txindex_to_{name}")),
|
||||
version,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
let height = ComputedVecBuilder::forced_import(path, name, version, compressed, options)?;
|
||||
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
Ok(Self {
|
||||
txindex,
|
||||
height,
|
||||
dateindex: ComputedVecBuilder::forced_import(path, name, version, compressed, options)?,
|
||||
weekindex: ComputedVecBuilder::forced_import(path, name, version, compressed, options)?,
|
||||
difficultyepoch: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
monthindex: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
quarterindex: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
yearindex: ComputedVecBuilder::forced_import(path, name, version, compressed, options)?,
|
||||
// halvingepoch: StorableVecGeneator::forced_import(path, name, version, compressed, options)?,
|
||||
decadeindex: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute_all<F>(
|
||||
&mut self,
|
||||
indexer: &mut Indexer,
|
||||
indexes: &mut indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(
|
||||
&mut ComputedVec<Txindex, T>,
|
||||
&mut Indexer,
|
||||
&mut indexes::Vecs,
|
||||
&Indexes,
|
||||
&Exit,
|
||||
) -> Result<()>,
|
||||
{
|
||||
compute(
|
||||
self.txindex.as_mut().unwrap(),
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.compute_rest(indexer, indexes, starting_indexes, exit, None)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
indexer: &mut Indexer,
|
||||
indexes: &mut indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
txindex: Option<&mut StoredVec<Txindex, T>>,
|
||||
) -> color_eyre::Result<()> {
|
||||
let txindex = txindex.unwrap_or_else(|| self.txindex.as_mut().unwrap().mut_vec());
|
||||
|
||||
self.height.compute(
|
||||
starting_indexes.height,
|
||||
txindex,
|
||||
indexer.mut_vecs().height_to_first_txindex.mut_vec(),
|
||||
indexes.height_to_last_txindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.dateindex.from_aligned(
|
||||
starting_indexes.dateindex,
|
||||
&mut self.height,
|
||||
indexes.dateindex_to_first_height.mut_vec(),
|
||||
indexes.dateindex_to_last_height.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.weekindex.from_aligned(
|
||||
starting_indexes.weekindex,
|
||||
&mut self.dateindex,
|
||||
indexes.weekindex_to_first_dateindex.mut_vec(),
|
||||
indexes.weekindex_to_last_dateindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex.from_aligned(
|
||||
starting_indexes.monthindex,
|
||||
&mut self.dateindex,
|
||||
indexes.monthindex_to_first_dateindex.mut_vec(),
|
||||
indexes.monthindex_to_last_dateindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.quarterindex.from_aligned(
|
||||
starting_indexes.quarterindex,
|
||||
&mut self.monthindex,
|
||||
indexes.quarterindex_to_first_monthindex.mut_vec(),
|
||||
indexes.quarterindex_to_last_monthindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex.from_aligned(
|
||||
starting_indexes.yearindex,
|
||||
&mut self.monthindex,
|
||||
indexes.yearindex_to_first_monthindex.mut_vec(),
|
||||
indexes.yearindex_to_last_monthindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex.from_aligned(
|
||||
starting_indexes.decadeindex,
|
||||
&mut self.yearindex,
|
||||
indexes.decadeindex_to_first_yearindex.mut_vec(),
|
||||
indexes.decadeindex_to_last_yearindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.difficultyepoch.from_aligned(
|
||||
starting_indexes.difficultyepoch,
|
||||
&mut self.height,
|
||||
indexes.difficultyepoch_to_first_height.mut_vec(),
|
||||
indexes.difficultyepoch_to_last_height.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn any_vecs(&self) -> Vec<&dyn AnyStoredVec> {
|
||||
[
|
||||
self.txindex.as_ref().map_or(vec![], |v| vec![v.any_vec()]),
|
||||
self.height.any_vecs(),
|
||||
self.dateindex.any_vecs(),
|
||||
self.weekindex.any_vecs(),
|
||||
self.difficultyepoch.any_vecs(),
|
||||
self.monthindex.any_vecs(),
|
||||
self.quarterindex.any_vecs(),
|
||||
self.yearindex.any_vecs(),
|
||||
// self.halvingepoch.as_any_vecs(),
|
||||
self.decadeindex.any_vecs(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
mod builder;
|
||||
mod from_dateindex;
|
||||
mod from_height;
|
||||
mod from_height_strict;
|
||||
mod from_txindex;
|
||||
mod stored_type;
|
||||
mod value_from_height;
|
||||
mod value_from_txindex;
|
||||
|
||||
pub use builder::*;
|
||||
pub use from_dateindex::*;
|
||||
pub use from_height::*;
|
||||
pub use from_height_strict::*;
|
||||
pub use from_txindex::*;
|
||||
pub use stored_type::*;
|
||||
pub use value_from_height::*;
|
||||
pub use value_from_txindex::*;
|
||||
@@ -0,0 +1,157 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{Bitcoin, Dollars, Height, Sats};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyStoredVec, Compressed, Result, StoredVec, Version};
|
||||
|
||||
use crate::storage::{
|
||||
base::ComputedVec,
|
||||
marketprice,
|
||||
vecs::{Indexes, indexes},
|
||||
};
|
||||
|
||||
use super::{ComputedVecsFromHeight, StorableVecGeneatorOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedValueVecsFromHeight {
|
||||
pub sats: ComputedVecsFromHeight<Sats>,
|
||||
pub bitcoin: ComputedVecsFromHeight<Bitcoin>,
|
||||
pub dollars: Option<ComputedVecsFromHeight<Dollars>>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ONE;
|
||||
|
||||
impl ComputedValueVecsFromHeight {
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
compute_source: bool,
|
||||
version: Version,
|
||||
compressed: Compressed,
|
||||
options: StorableVecGeneatorOptions,
|
||||
compute_dollars: bool,
|
||||
) -> color_eyre::Result<Self> {
|
||||
Ok(Self {
|
||||
sats: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
name,
|
||||
compute_source,
|
||||
VERSION + version,
|
||||
compressed,
|
||||
options,
|
||||
)?,
|
||||
bitcoin: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
&format!("{name}_in_btc"),
|
||||
true,
|
||||
VERSION + version,
|
||||
compressed,
|
||||
options,
|
||||
)?,
|
||||
dollars: compute_dollars.then(|| {
|
||||
ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
&format!("{name}_in_usd"),
|
||||
true,
|
||||
VERSION + version,
|
||||
compressed,
|
||||
options,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute_all<F>(
|
||||
&mut self,
|
||||
indexer: &mut Indexer,
|
||||
indexes: &mut indexes::Vecs,
|
||||
marketprices: &mut Option<&mut marketprice::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(
|
||||
&mut ComputedVec<Height, Sats>,
|
||||
&mut Indexer,
|
||||
&mut indexes::Vecs,
|
||||
&Indexes,
|
||||
&Exit,
|
||||
) -> Result<()>,
|
||||
{
|
||||
compute(
|
||||
self.sats.height.as_mut().unwrap(),
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.compute_rest(indexer, indexes, marketprices, starting_indexes, exit, None)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
indexer: &mut Indexer,
|
||||
indexes: &mut indexes::Vecs,
|
||||
marketprices: &mut Option<&mut marketprice::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut height: Option<&mut StoredVec<Height, Sats>>,
|
||||
) -> color_eyre::Result<()> {
|
||||
if let Some(height) = height.as_mut() {
|
||||
self.sats
|
||||
.compute_rest(indexes, starting_indexes, exit, Some(height))?;
|
||||
} else {
|
||||
self.sats
|
||||
.compute_rest(indexes, starting_indexes, exit, None)?;
|
||||
}
|
||||
|
||||
let height = height.unwrap_or_else(|| self.sats.height.as_mut().unwrap().mut_vec());
|
||||
|
||||
self.bitcoin.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, _, _, starting_indexes, exit| {
|
||||
v.compute_from_sats(starting_indexes.height, height, exit)
|
||||
},
|
||||
)?;
|
||||
|
||||
let txindex = self.bitcoin.height.as_mut().unwrap().mut_vec();
|
||||
let price = marketprices
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.chainindexes_to_close
|
||||
.height
|
||||
.mut_vec();
|
||||
|
||||
if let Some(dollars) = self.dollars.as_mut() {
|
||||
dollars.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, _, _, starting_indexes, exit| {
|
||||
v.compute_from_bitcoin(starting_indexes.height, txindex, price, exit)
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn any_vecs(&self) -> Vec<&dyn AnyStoredVec> {
|
||||
[
|
||||
self.sats.any_vecs(),
|
||||
self.bitcoin.any_vecs(),
|
||||
self.dollars.as_ref().map_or(vec![], |v| v.any_vecs()),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{Bitcoin, Dollars, Sats, Txindex};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyStoredVec, Compressed, Result, StoredVec, Version};
|
||||
|
||||
use crate::storage::{
|
||||
base::ComputedVec,
|
||||
marketprice,
|
||||
vecs::{Indexes, indexes},
|
||||
};
|
||||
|
||||
use super::{ComputedVecsFromTxindex, StorableVecGeneatorOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedValueVecsFromTxindex {
|
||||
pub sats: ComputedVecsFromTxindex<Sats>,
|
||||
pub bitcoin: ComputedVecsFromTxindex<Bitcoin>,
|
||||
pub dollars: Option<ComputedVecsFromTxindex<Dollars>>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ONE;
|
||||
|
||||
impl ComputedValueVecsFromTxindex {
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
compute_source: bool,
|
||||
version: Version,
|
||||
compressed: Compressed,
|
||||
options: StorableVecGeneatorOptions,
|
||||
compute_dollars: bool,
|
||||
) -> color_eyre::Result<Self> {
|
||||
Ok(Self {
|
||||
sats: ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
name,
|
||||
compute_source,
|
||||
VERSION + version,
|
||||
compressed,
|
||||
options,
|
||||
)?,
|
||||
bitcoin: ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
&format!("{name}_in_btc"),
|
||||
true,
|
||||
VERSION + version,
|
||||
compressed,
|
||||
options,
|
||||
)?,
|
||||
dollars: compute_dollars.then(|| {
|
||||
ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
&format!("{name}_in_usd"),
|
||||
true,
|
||||
VERSION + version,
|
||||
compressed,
|
||||
options,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute_all<F>(
|
||||
&mut self,
|
||||
indexer: &mut Indexer,
|
||||
indexes: &mut indexes::Vecs,
|
||||
marketprices: &mut Option<&mut marketprice::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(
|
||||
&mut ComputedVec<Txindex, Sats>,
|
||||
&mut Indexer,
|
||||
&mut indexes::Vecs,
|
||||
&Indexes,
|
||||
&Exit,
|
||||
) -> Result<()>,
|
||||
{
|
||||
compute(
|
||||
self.sats.txindex.as_mut().unwrap(),
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.compute_rest(indexer, indexes, marketprices, starting_indexes, exit, None)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
indexer: &mut Indexer,
|
||||
indexes: &mut indexes::Vecs,
|
||||
marketprices: &mut Option<&mut marketprice::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut txindex: Option<&mut StoredVec<Txindex, Sats>>,
|
||||
) -> color_eyre::Result<()> {
|
||||
if let Some(txindex) = txindex.as_mut() {
|
||||
self.sats
|
||||
.compute_rest(indexer, indexes, starting_indexes, exit, Some(txindex))?;
|
||||
} else {
|
||||
self.sats
|
||||
.compute_rest(indexer, indexes, starting_indexes, exit, None)?;
|
||||
}
|
||||
|
||||
let txindex = txindex.unwrap_or_else(|| self.sats.txindex.as_mut().unwrap().mut_vec());
|
||||
|
||||
self.bitcoin.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, _, _, starting_indexes, exit| {
|
||||
v.compute_from_sats(starting_indexes.txindex, txindex, exit)
|
||||
},
|
||||
)?;
|
||||
|
||||
let txindex = self.bitcoin.txindex.as_mut().unwrap().mut_vec();
|
||||
let price = marketprices
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.chainindexes_to_close
|
||||
.height
|
||||
.mut_vec();
|
||||
|
||||
if let Some(dollars) = self.dollars.as_mut() {
|
||||
dollars.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, indexer, _, starting_indexes, exit| {
|
||||
v.compute_from_bitcoin(
|
||||
starting_indexes.txindex,
|
||||
txindex,
|
||||
indexer.mut_vecs().txindex_to_height.mut_vec(),
|
||||
price,
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn any_vecs(&self) -> Vec<&dyn AnyStoredVec> {
|
||||
[
|
||||
self.sats.any_vecs(),
|
||||
self.bitcoin.any_vecs(),
|
||||
self.dollars.as_ref().map_or(vec![], |v| v.any_vecs()),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
@@ -6,62 +6,60 @@ use brk_core::{
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyStorableVec, Compressed, Version};
|
||||
use brk_vec::{Compressed, Version};
|
||||
|
||||
use super::StorableVec;
|
||||
use super::ComputedVec;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vecs {
|
||||
// pub height_to_last_addressindex: StorableVec<Height, Addressindex>,
|
||||
// pub height_to_last_txoutindex: StorableVec<Height, Txoutindex>,
|
||||
pub dateindex_to_date: StorableVec<Dateindex, Date>,
|
||||
pub dateindex_to_dateindex: StorableVec<Dateindex, Dateindex>,
|
||||
pub dateindex_to_first_height: StorableVec<Dateindex, Height>,
|
||||
pub dateindex_to_last_height: StorableVec<Dateindex, Height>,
|
||||
pub dateindex_to_monthindex: StorableVec<Dateindex, Monthindex>,
|
||||
pub dateindex_to_timestamp: StorableVec<Dateindex, Timestamp>,
|
||||
pub dateindex_to_weekindex: StorableVec<Dateindex, Weekindex>,
|
||||
pub decadeindex_to_decadeindex: StorableVec<Decadeindex, Decadeindex>,
|
||||
pub decadeindex_to_first_yearindex: StorableVec<Decadeindex, Yearindex>,
|
||||
pub decadeindex_to_last_yearindex: StorableVec<Decadeindex, Yearindex>,
|
||||
pub decadeindex_to_timestamp: StorableVec<Decadeindex, Timestamp>,
|
||||
pub difficultyepoch_to_difficultyepoch: StorableVec<Difficultyepoch, Difficultyepoch>,
|
||||
pub difficultyepoch_to_first_height: StorableVec<Difficultyepoch, Height>,
|
||||
pub difficultyepoch_to_last_height: StorableVec<Difficultyepoch, Height>,
|
||||
pub difficultyepoch_to_timestamp: StorableVec<Difficultyepoch, Timestamp>,
|
||||
pub halvingepoch_to_first_height: StorableVec<Halvingepoch, Height>,
|
||||
pub halvingepoch_to_halvingepoch: StorableVec<Halvingepoch, Halvingepoch>,
|
||||
pub halvingepoch_to_last_height: StorableVec<Halvingepoch, Height>,
|
||||
pub halvingepoch_to_timestamp: StorableVec<Halvingepoch, Timestamp>,
|
||||
pub height_to_dateindex: StorableVec<Height, Dateindex>,
|
||||
pub height_to_difficultyepoch: StorableVec<Height, Difficultyepoch>,
|
||||
pub height_to_fixed_date: StorableVec<Height, Date>,
|
||||
pub height_to_fixed_timestamp: StorableVec<Height, Timestamp>,
|
||||
pub height_to_halvingepoch: StorableVec<Height, Halvingepoch>,
|
||||
pub height_to_height: StorableVec<Height, Height>,
|
||||
pub height_to_last_txindex: StorableVec<Height, Txindex>,
|
||||
pub height_to_real_date: StorableVec<Height, Date>,
|
||||
pub monthindex_to_first_dateindex: StorableVec<Monthindex, Dateindex>,
|
||||
pub monthindex_to_last_dateindex: StorableVec<Monthindex, Dateindex>,
|
||||
pub monthindex_to_monthindex: StorableVec<Monthindex, Monthindex>,
|
||||
pub monthindex_to_quarterindex: StorableVec<Monthindex, Quarterindex>,
|
||||
pub monthindex_to_timestamp: StorableVec<Monthindex, Timestamp>,
|
||||
pub monthindex_to_yearindex: StorableVec<Monthindex, Yearindex>,
|
||||
pub quarterindex_to_first_monthindex: StorableVec<Quarterindex, Monthindex>,
|
||||
pub quarterindex_to_last_monthindex: StorableVec<Quarterindex, Monthindex>,
|
||||
pub quarterindex_to_quarterindex: StorableVec<Quarterindex, Quarterindex>,
|
||||
pub quarterindex_to_timestamp: StorableVec<Quarterindex, Timestamp>,
|
||||
pub txindex_to_last_txinindex: StorableVec<Txindex, Txinindex>,
|
||||
pub txindex_to_last_txoutindex: StorableVec<Txindex, Txoutindex>,
|
||||
pub weekindex_to_first_dateindex: StorableVec<Weekindex, Dateindex>,
|
||||
pub weekindex_to_last_dateindex: StorableVec<Weekindex, Dateindex>,
|
||||
pub weekindex_to_timestamp: StorableVec<Weekindex, Timestamp>,
|
||||
pub weekindex_to_weekindex: StorableVec<Weekindex, Weekindex>,
|
||||
pub yearindex_to_decadeindex: StorableVec<Yearindex, Decadeindex>,
|
||||
pub yearindex_to_first_monthindex: StorableVec<Yearindex, Monthindex>,
|
||||
pub yearindex_to_last_monthindex: StorableVec<Yearindex, Monthindex>,
|
||||
pub yearindex_to_timestamp: StorableVec<Yearindex, Timestamp>,
|
||||
pub yearindex_to_yearindex: StorableVec<Yearindex, Yearindex>,
|
||||
pub dateindex_to_date: ComputedVec<Dateindex, Date>,
|
||||
pub dateindex_to_dateindex: ComputedVec<Dateindex, Dateindex>,
|
||||
pub dateindex_to_first_height: ComputedVec<Dateindex, Height>,
|
||||
pub dateindex_to_last_height: ComputedVec<Dateindex, Height>,
|
||||
pub dateindex_to_monthindex: ComputedVec<Dateindex, Monthindex>,
|
||||
pub dateindex_to_timestamp: ComputedVec<Dateindex, Timestamp>,
|
||||
pub dateindex_to_weekindex: ComputedVec<Dateindex, Weekindex>,
|
||||
pub decadeindex_to_decadeindex: ComputedVec<Decadeindex, Decadeindex>,
|
||||
pub decadeindex_to_first_yearindex: ComputedVec<Decadeindex, Yearindex>,
|
||||
pub decadeindex_to_last_yearindex: ComputedVec<Decadeindex, Yearindex>,
|
||||
pub decadeindex_to_timestamp: ComputedVec<Decadeindex, Timestamp>,
|
||||
pub difficultyepoch_to_difficultyepoch: ComputedVec<Difficultyepoch, Difficultyepoch>,
|
||||
pub difficultyepoch_to_first_height: ComputedVec<Difficultyepoch, Height>,
|
||||
pub difficultyepoch_to_last_height: ComputedVec<Difficultyepoch, Height>,
|
||||
pub difficultyepoch_to_timestamp: ComputedVec<Difficultyepoch, Timestamp>,
|
||||
pub halvingepoch_to_first_height: ComputedVec<Halvingepoch, Height>,
|
||||
pub halvingepoch_to_halvingepoch: ComputedVec<Halvingepoch, Halvingepoch>,
|
||||
pub halvingepoch_to_last_height: ComputedVec<Halvingepoch, Height>,
|
||||
pub halvingepoch_to_timestamp: ComputedVec<Halvingepoch, Timestamp>,
|
||||
pub height_to_dateindex: ComputedVec<Height, Dateindex>,
|
||||
pub height_to_difficultyepoch: ComputedVec<Height, Difficultyepoch>,
|
||||
pub height_to_fixed_date: ComputedVec<Height, Date>,
|
||||
pub height_to_fixed_timestamp: ComputedVec<Height, Timestamp>,
|
||||
pub height_to_halvingepoch: ComputedVec<Height, Halvingepoch>,
|
||||
pub height_to_height: ComputedVec<Height, Height>,
|
||||
pub height_to_last_txindex: ComputedVec<Height, Txindex>,
|
||||
pub height_to_real_date: ComputedVec<Height, Date>,
|
||||
pub monthindex_to_first_dateindex: ComputedVec<Monthindex, Dateindex>,
|
||||
pub monthindex_to_last_dateindex: ComputedVec<Monthindex, Dateindex>,
|
||||
pub monthindex_to_monthindex: ComputedVec<Monthindex, Monthindex>,
|
||||
pub monthindex_to_quarterindex: ComputedVec<Monthindex, Quarterindex>,
|
||||
pub monthindex_to_timestamp: ComputedVec<Monthindex, Timestamp>,
|
||||
pub monthindex_to_yearindex: ComputedVec<Monthindex, Yearindex>,
|
||||
pub quarterindex_to_first_monthindex: ComputedVec<Quarterindex, Monthindex>,
|
||||
pub quarterindex_to_last_monthindex: ComputedVec<Quarterindex, Monthindex>,
|
||||
pub quarterindex_to_quarterindex: ComputedVec<Quarterindex, Quarterindex>,
|
||||
pub quarterindex_to_timestamp: ComputedVec<Quarterindex, Timestamp>,
|
||||
pub txindex_to_last_txinindex: ComputedVec<Txindex, Txinindex>,
|
||||
pub txindex_to_last_txoutindex: ComputedVec<Txindex, Txoutindex>,
|
||||
pub weekindex_to_first_dateindex: ComputedVec<Weekindex, Dateindex>,
|
||||
pub weekindex_to_last_dateindex: ComputedVec<Weekindex, Dateindex>,
|
||||
pub weekindex_to_timestamp: ComputedVec<Weekindex, Timestamp>,
|
||||
pub weekindex_to_weekindex: ComputedVec<Weekindex, Weekindex>,
|
||||
pub yearindex_to_decadeindex: ComputedVec<Yearindex, Decadeindex>,
|
||||
pub yearindex_to_first_monthindex: ComputedVec<Yearindex, Monthindex>,
|
||||
pub yearindex_to_last_monthindex: ComputedVec<Yearindex, Monthindex>,
|
||||
pub yearindex_to_timestamp: ComputedVec<Yearindex, Timestamp>,
|
||||
pub yearindex_to_yearindex: ComputedVec<Yearindex, Yearindex>,
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
@@ -69,244 +67,244 @@ impl Vecs {
|
||||
fs::create_dir_all(path)?;
|
||||
|
||||
Ok(Self {
|
||||
dateindex_to_date: StorableVec::forced_import(
|
||||
dateindex_to_date: ComputedVec::forced_import(
|
||||
&path.join("dateindex_to_date"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
dateindex_to_dateindex: StorableVec::forced_import(
|
||||
dateindex_to_dateindex: ComputedVec::forced_import(
|
||||
&path.join("dateindex_to_dateindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
dateindex_to_first_height: StorableVec::forced_import(
|
||||
dateindex_to_first_height: ComputedVec::forced_import(
|
||||
&path.join("dateindex_to_first_height"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
dateindex_to_last_height: StorableVec::forced_import(
|
||||
dateindex_to_last_height: ComputedVec::forced_import(
|
||||
&path.join("dateindex_to_last_height"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_real_date: StorableVec::forced_import(
|
||||
height_to_real_date: ComputedVec::forced_import(
|
||||
&path.join("height_to_real_date"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_fixed_date: StorableVec::forced_import(
|
||||
height_to_fixed_date: ComputedVec::forced_import(
|
||||
&path.join("height_to_fixed_date"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_dateindex: StorableVec::forced_import(
|
||||
height_to_dateindex: ComputedVec::forced_import(
|
||||
&path.join("height_to_dateindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_height: StorableVec::forced_import(
|
||||
height_to_height: ComputedVec::forced_import(
|
||||
&path.join("height_to_height"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_last_txindex: StorableVec::forced_import(
|
||||
height_to_last_txindex: ComputedVec::forced_import(
|
||||
&path.join("height_to_last_txindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_last_txinindex: StorableVec::forced_import(
|
||||
txindex_to_last_txinindex: ComputedVec::forced_import(
|
||||
&path.join("txindex_to_last_txinindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_last_txoutindex: StorableVec::forced_import(
|
||||
txindex_to_last_txoutindex: ComputedVec::forced_import(
|
||||
&path.join("txindex_to_last_txoutindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
difficultyepoch_to_first_height: StorableVec::forced_import(
|
||||
difficultyepoch_to_first_height: ComputedVec::forced_import(
|
||||
&path.join("difficultyepoch_to_first_height"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
difficultyepoch_to_last_height: StorableVec::forced_import(
|
||||
difficultyepoch_to_last_height: ComputedVec::forced_import(
|
||||
&path.join("difficultyepoch_to_last_height"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
halvingepoch_to_first_height: StorableVec::forced_import(
|
||||
halvingepoch_to_first_height: ComputedVec::forced_import(
|
||||
&path.join("halvingepoch_to_first_height"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
halvingepoch_to_last_height: StorableVec::forced_import(
|
||||
halvingepoch_to_last_height: ComputedVec::forced_import(
|
||||
&path.join("halvingepoch_to_last_height"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
weekindex_to_first_dateindex: StorableVec::forced_import(
|
||||
weekindex_to_first_dateindex: ComputedVec::forced_import(
|
||||
&path.join("weekindex_to_first_dateindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
weekindex_to_last_dateindex: StorableVec::forced_import(
|
||||
weekindex_to_last_dateindex: ComputedVec::forced_import(
|
||||
&path.join("weekindex_to_last_dateindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
monthindex_to_first_dateindex: StorableVec::forced_import(
|
||||
monthindex_to_first_dateindex: ComputedVec::forced_import(
|
||||
&path.join("monthindex_to_first_dateindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
monthindex_to_last_dateindex: StorableVec::forced_import(
|
||||
monthindex_to_last_dateindex: ComputedVec::forced_import(
|
||||
&path.join("monthindex_to_last_dateindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
yearindex_to_first_monthindex: StorableVec::forced_import(
|
||||
yearindex_to_first_monthindex: ComputedVec::forced_import(
|
||||
&path.join("yearindex_to_first_monthindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
yearindex_to_last_monthindex: StorableVec::forced_import(
|
||||
yearindex_to_last_monthindex: ComputedVec::forced_import(
|
||||
&path.join("yearindex_to_last_monthindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
decadeindex_to_first_yearindex: StorableVec::forced_import(
|
||||
decadeindex_to_first_yearindex: ComputedVec::forced_import(
|
||||
&path.join("decadeindex_to_first_yearindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
decadeindex_to_last_yearindex: StorableVec::forced_import(
|
||||
decadeindex_to_last_yearindex: ComputedVec::forced_import(
|
||||
&path.join("decadeindex_to_last_yearindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
dateindex_to_weekindex: StorableVec::forced_import(
|
||||
dateindex_to_weekindex: ComputedVec::forced_import(
|
||||
&path.join("dateindex_to_weekindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
dateindex_to_monthindex: StorableVec::forced_import(
|
||||
dateindex_to_monthindex: ComputedVec::forced_import(
|
||||
&path.join("dateindex_to_monthindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
monthindex_to_yearindex: StorableVec::forced_import(
|
||||
monthindex_to_yearindex: ComputedVec::forced_import(
|
||||
&path.join("monthindex_to_yearindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
yearindex_to_decadeindex: StorableVec::forced_import(
|
||||
yearindex_to_decadeindex: ComputedVec::forced_import(
|
||||
&path.join("yearindex_to_decadeindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_difficultyepoch: StorableVec::forced_import(
|
||||
height_to_difficultyepoch: ComputedVec::forced_import(
|
||||
&path.join("height_to_difficultyepoch"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_halvingepoch: StorableVec::forced_import(
|
||||
height_to_halvingepoch: ComputedVec::forced_import(
|
||||
&path.join("height_to_halvingepoch"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
weekindex_to_weekindex: StorableVec::forced_import(
|
||||
weekindex_to_weekindex: ComputedVec::forced_import(
|
||||
&path.join("weekindex_to_weekindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
monthindex_to_monthindex: StorableVec::forced_import(
|
||||
monthindex_to_monthindex: ComputedVec::forced_import(
|
||||
&path.join("monthindex_to_monthindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
yearindex_to_yearindex: StorableVec::forced_import(
|
||||
yearindex_to_yearindex: ComputedVec::forced_import(
|
||||
&path.join("yearindex_to_yearindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
decadeindex_to_decadeindex: StorableVec::forced_import(
|
||||
decadeindex_to_decadeindex: ComputedVec::forced_import(
|
||||
&path.join("decadeindex_to_decadeindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
difficultyepoch_to_difficultyepoch: StorableVec::forced_import(
|
||||
difficultyepoch_to_difficultyepoch: ComputedVec::forced_import(
|
||||
&path.join("difficultyepoch_to_difficultyepoch"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
halvingepoch_to_halvingepoch: StorableVec::forced_import(
|
||||
halvingepoch_to_halvingepoch: ComputedVec::forced_import(
|
||||
&path.join("halvingepoch_to_halvingepoch"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
dateindex_to_timestamp: StorableVec::forced_import(
|
||||
dateindex_to_timestamp: ComputedVec::forced_import(
|
||||
&path.join("dateindex_to_timestamp"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
decadeindex_to_timestamp: StorableVec::forced_import(
|
||||
decadeindex_to_timestamp: ComputedVec::forced_import(
|
||||
&path.join("decadeindex_to_timestamp"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
difficultyepoch_to_timestamp: StorableVec::forced_import(
|
||||
difficultyepoch_to_timestamp: ComputedVec::forced_import(
|
||||
&path.join("difficultyepoch_to_timestamp"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
halvingepoch_to_timestamp: StorableVec::forced_import(
|
||||
halvingepoch_to_timestamp: ComputedVec::forced_import(
|
||||
&path.join("halvingepoch_to_timestamp"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
monthindex_to_timestamp: StorableVec::forced_import(
|
||||
monthindex_to_timestamp: ComputedVec::forced_import(
|
||||
&path.join("monthindex_to_timestamp"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
weekindex_to_timestamp: StorableVec::forced_import(
|
||||
weekindex_to_timestamp: ComputedVec::forced_import(
|
||||
&path.join("weekindex_to_timestamp"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
yearindex_to_timestamp: StorableVec::forced_import(
|
||||
yearindex_to_timestamp: ComputedVec::forced_import(
|
||||
&path.join("yearindex_to_timestamp"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_fixed_timestamp: StorableVec::forced_import(
|
||||
height_to_fixed_timestamp: ComputedVec::forced_import(
|
||||
&path.join("height_to_fixed_timestamp"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
monthindex_to_quarterindex: StorableVec::forced_import(
|
||||
monthindex_to_quarterindex: ComputedVec::forced_import(
|
||||
&path.join("monthindex_to_quarterindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
quarterindex_to_first_monthindex: StorableVec::forced_import(
|
||||
quarterindex_to_first_monthindex: ComputedVec::forced_import(
|
||||
&path.join("quarterindex_to_first_monthindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
quarterindex_to_last_monthindex: StorableVec::forced_import(
|
||||
quarterindex_to_last_monthindex: ComputedVec::forced_import(
|
||||
&path.join("quarterindex_to_last_monthindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
quarterindex_to_quarterindex: StorableVec::forced_import(
|
||||
quarterindex_to_quarterindex: ComputedVec::forced_import(
|
||||
&path.join("quarterindex_to_quarterindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
quarterindex_to_timestamp: StorableVec::forced_import(
|
||||
quarterindex_to_timestamp: ComputedVec::forced_import(
|
||||
&path.join("quarterindex_to_timestamp"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
})
|
||||
@@ -320,7 +318,7 @@ impl Vecs {
|
||||
) -> color_eyre::Result<Indexes> {
|
||||
let indexer_vecs = indexer.mut_vecs();
|
||||
|
||||
let height_count = indexer_vecs.height_to_size.len();
|
||||
let height_count = indexer_vecs.height_to_total_size.len();
|
||||
let txindexes_count = indexer_vecs.txindex_to_txid.len();
|
||||
let txinindexes_count = indexer_vecs.txinindex_to_txoutindex.len();
|
||||
let txoutindexes_count = indexer_vecs.txoutindex_to_addressindex.len();
|
||||
@@ -345,12 +343,8 @@ impl Vecs {
|
||||
|(h, d, s, ..)| {
|
||||
let d = h
|
||||
.decremented()
|
||||
.and_then(|h| s.get(h).ok())
|
||||
.flatten()
|
||||
.map_or(d, |prev_d| {
|
||||
let prev_d = *prev_d;
|
||||
if prev_d > d { prev_d } else { d }
|
||||
});
|
||||
.and_then(|h| s.unwrap_cached_get(h))
|
||||
.map_or(d, |prev_d| prev_d.max(d));
|
||||
(h, d)
|
||||
},
|
||||
exit,
|
||||
@@ -363,10 +357,11 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let decremented_starting_height = starting_indexes.height.decremented().unwrap_or_default();
|
||||
|
||||
let starting_dateindex = self
|
||||
.height_to_dateindex
|
||||
.get(starting_indexes.height.decremented().unwrap_or_default())?
|
||||
.copied()
|
||||
.unwrap_cached_get(decremented_starting_height)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.height_to_dateindex.compute_transform(
|
||||
@@ -378,8 +373,7 @@ impl Vecs {
|
||||
|
||||
let starting_dateindex = if let Some(dateindex) = self
|
||||
.height_to_dateindex
|
||||
.get(starting_indexes.height.decremented().unwrap_or_default())?
|
||||
.copied()
|
||||
.unwrap_cached_get(decremented_starting_height)
|
||||
{
|
||||
starting_dateindex.min(dateindex)
|
||||
} else {
|
||||
@@ -451,8 +445,7 @@ impl Vecs {
|
||||
|
||||
let starting_weekindex = self
|
||||
.dateindex_to_weekindex
|
||||
.get(starting_dateindex)?
|
||||
.copied()
|
||||
.unwrap_cached_get(starting_dateindex)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.dateindex_to_weekindex.compute_transform(
|
||||
@@ -487,7 +480,7 @@ impl Vecs {
|
||||
self.weekindex_to_timestamp.compute_transform(
|
||||
starting_weekindex,
|
||||
self.weekindex_to_first_dateindex.mut_vec(),
|
||||
|(i, d, ..)| (i, *self.dateindex_to_timestamp.get(d).unwrap().unwrap()),
|
||||
|(i, d, ..)| (i, self.dateindex_to_timestamp.double_unwrap_cached_get(d)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -495,8 +488,7 @@ impl Vecs {
|
||||
|
||||
let starting_monthindex = self
|
||||
.dateindex_to_monthindex
|
||||
.get(starting_dateindex)?
|
||||
.copied()
|
||||
.unwrap_cached_get(starting_dateindex)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.dateindex_to_monthindex.compute_transform(
|
||||
@@ -533,7 +525,7 @@ impl Vecs {
|
||||
self.monthindex_to_timestamp.compute_transform(
|
||||
starting_monthindex,
|
||||
self.monthindex_to_first_dateindex.mut_vec(),
|
||||
|(i, d, ..)| (i, *self.dateindex_to_timestamp.get(d).unwrap().unwrap()),
|
||||
|(i, d, ..)| (i, self.dateindex_to_timestamp.double_unwrap_cached_get(d)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -541,8 +533,7 @@ impl Vecs {
|
||||
|
||||
let starting_quarterindex = self
|
||||
.monthindex_to_quarterindex
|
||||
.get(starting_monthindex)?
|
||||
.copied()
|
||||
.unwrap_cached_get(starting_monthindex)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.monthindex_to_quarterindex.compute_transform(
|
||||
@@ -579,7 +570,7 @@ impl Vecs {
|
||||
self.quarterindex_to_timestamp.compute_transform(
|
||||
starting_quarterindex,
|
||||
self.quarterindex_to_first_monthindex.mut_vec(),
|
||||
|(i, m, ..)| (i, *self.monthindex_to_timestamp.get(m).unwrap().unwrap()),
|
||||
|(i, m, ..)| (i, self.monthindex_to_timestamp.double_unwrap_cached_get(m)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -587,8 +578,7 @@ impl Vecs {
|
||||
|
||||
let starting_yearindex = self
|
||||
.monthindex_to_yearindex
|
||||
.get(starting_monthindex)?
|
||||
.copied()
|
||||
.unwrap_cached_get(starting_monthindex)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.monthindex_to_yearindex.compute_transform(
|
||||
@@ -625,7 +615,7 @@ impl Vecs {
|
||||
self.yearindex_to_timestamp.compute_transform(
|
||||
starting_yearindex,
|
||||
self.yearindex_to_first_monthindex.mut_vec(),
|
||||
|(i, m, ..)| (i, *self.monthindex_to_timestamp.get(m).unwrap().unwrap()),
|
||||
|(i, m, ..)| (i, self.monthindex_to_timestamp.double_unwrap_cached_get(m)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -633,8 +623,7 @@ impl Vecs {
|
||||
|
||||
let starting_decadeindex = self
|
||||
.yearindex_to_decadeindex
|
||||
.get(starting_yearindex)?
|
||||
.copied()
|
||||
.unwrap_cached_get(starting_yearindex)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.yearindex_to_decadeindex.compute_transform(
|
||||
@@ -669,7 +658,7 @@ impl Vecs {
|
||||
self.decadeindex_to_timestamp.compute_transform(
|
||||
starting_decadeindex,
|
||||
self.decadeindex_to_first_yearindex.mut_vec(),
|
||||
|(i, y, ..)| (i, *self.yearindex_to_timestamp.get(y).unwrap().unwrap()),
|
||||
|(i, y, ..)| (i, self.yearindex_to_timestamp.double_unwrap_cached_get(y)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -677,8 +666,7 @@ impl Vecs {
|
||||
|
||||
let starting_difficultyepoch = self
|
||||
.height_to_difficultyepoch
|
||||
.get(starting_indexes.height)?
|
||||
.copied()
|
||||
.unwrap_cached_get(decremented_starting_height)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.height_to_difficultyepoch.compute_transform(
|
||||
@@ -716,7 +704,7 @@ impl Vecs {
|
||||
|(i, h, ..)| {
|
||||
(
|
||||
i,
|
||||
*indexer_vecs.height_to_timestamp.get(h).unwrap().unwrap(),
|
||||
indexer_vecs.height_to_timestamp.double_unwrap_cached_get(h),
|
||||
)
|
||||
},
|
||||
exit,
|
||||
@@ -726,8 +714,7 @@ impl Vecs {
|
||||
|
||||
let starting_halvingepoch = self
|
||||
.height_to_halvingepoch
|
||||
.get(starting_indexes.height)?
|
||||
.copied()
|
||||
.unwrap_cached_get(decremented_starting_height)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.height_to_halvingepoch.compute_transform(
|
||||
@@ -765,7 +752,7 @@ impl Vecs {
|
||||
// |(i, h, ..)| {
|
||||
// (
|
||||
// i,
|
||||
// *indexer_vecs.height_to_timestamp.get(h).unwrap().unwrap(),
|
||||
// *indexer_vecs.height_to_timestamp.unwraped_cached_get(h).unwrap().unwrap(),
|
||||
// )
|
||||
// },
|
||||
// exit,
|
||||
@@ -784,7 +771,7 @@ impl Vecs {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn brk_vec::AnyStoredVec> {
|
||||
vec![
|
||||
self.dateindex_to_date.any_vec(),
|
||||
self.dateindex_to_dateindex.any_vec(),
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,14 +3,14 @@ use std::{fs, path::Path};
|
||||
use brk_exit::Exit;
|
||||
use brk_fetcher::Fetcher;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyStorableVec, Compressed};
|
||||
use brk_vec::{AnyStoredVec, Compressed};
|
||||
|
||||
mod base;
|
||||
mod blocks;
|
||||
mod indexes;
|
||||
mod marketprice;
|
||||
mod stats;
|
||||
mod transactions;
|
||||
pub mod base;
|
||||
pub mod blocks;
|
||||
pub mod grouped;
|
||||
pub mod indexes;
|
||||
pub mod marketprice;
|
||||
pub mod transactions;
|
||||
|
||||
use base::*;
|
||||
use indexes::*;
|
||||
@@ -30,7 +30,7 @@ impl Vecs {
|
||||
Ok(Self {
|
||||
blocks: blocks::Vecs::forced_import(path, compressed)?,
|
||||
indexes: indexes::Vecs::forced_import(path, compressed)?,
|
||||
transactions: transactions::Vecs::forced_import(path, compressed)?,
|
||||
transactions: transactions::Vecs::forced_import(path, compressed, fetch)?,
|
||||
marketprice: fetch.then(|| marketprice::Vecs::forced_import(path, compressed).unwrap()),
|
||||
})
|
||||
}
|
||||
@@ -47,9 +47,6 @@ impl Vecs {
|
||||
self.blocks
|
||||
.compute(indexer, &mut self.indexes, &starting_indexes, exit)?;
|
||||
|
||||
self.transactions
|
||||
.compute(indexer, &mut self.indexes, &starting_indexes, exit)?;
|
||||
|
||||
if let Some(marketprice) = self.marketprice.as_mut() {
|
||||
marketprice.compute(
|
||||
indexer,
|
||||
@@ -60,10 +57,18 @@ impl Vecs {
|
||||
)?;
|
||||
}
|
||||
|
||||
self.transactions.compute(
|
||||
indexer,
|
||||
&mut self.indexes,
|
||||
&starting_indexes,
|
||||
&mut self.marketprice.as_mut(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStoredVec> {
|
||||
[
|
||||
self.indexes.as_any_vecs(),
|
||||
self.blocks.as_any_vecs(),
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{Dateindex, Decadeindex, Monthindex, Quarterindex, Weekindex, Yearindex};
|
||||
use brk_exit::Exit;
|
||||
use brk_vec::{AnyStorableVec, Compressed};
|
||||
|
||||
use crate::storage::vecs::{Indexes, base::StorableVec, indexes};
|
||||
|
||||
use super::{ComputedType, StorableVecBuilder, StorableVecGeneatorOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StorableVecsStatsFromDate<T>
|
||||
where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub weekindex: StorableVecBuilder<Weekindex, T>,
|
||||
pub monthindex: StorableVecBuilder<Monthindex, T>,
|
||||
pub quarterindex: StorableVecBuilder<Quarterindex, T>,
|
||||
pub yearindex: StorableVecBuilder<Yearindex, T>,
|
||||
pub decadeindex: StorableVecBuilder<Decadeindex, T>,
|
||||
}
|
||||
|
||||
impl<T> StorableVecsStatsFromDate<T>
|
||||
where
|
||||
T: ComputedType + Ord + From<f64>,
|
||||
f64: From<T>,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
compressed: Compressed,
|
||||
options: StorableVecGeneatorOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
Ok(Self {
|
||||
weekindex: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
monthindex: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
quarterindex: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
yearindex: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
decadeindex: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute(
|
||||
&mut self,
|
||||
source: &mut StorableVec<Dateindex, T>,
|
||||
indexes: &mut indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
self.weekindex.compute(
|
||||
starting_indexes.weekindex,
|
||||
source,
|
||||
indexes.weekindex_to_first_dateindex.mut_vec(),
|
||||
indexes.weekindex_to_last_dateindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex.compute(
|
||||
starting_indexes.monthindex,
|
||||
source,
|
||||
indexes.monthindex_to_first_dateindex.mut_vec(),
|
||||
indexes.monthindex_to_last_dateindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.quarterindex.from_aligned(
|
||||
starting_indexes.quarterindex,
|
||||
&mut self.monthindex,
|
||||
indexes.quarterindex_to_first_monthindex.mut_vec(),
|
||||
indexes.quarterindex_to_last_monthindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex.from_aligned(
|
||||
starting_indexes.yearindex,
|
||||
&mut self.monthindex,
|
||||
indexes.yearindex_to_first_monthindex.mut_vec(),
|
||||
indexes.yearindex_to_last_monthindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex.from_aligned(
|
||||
starting_indexes.decadeindex,
|
||||
&mut self.yearindex,
|
||||
indexes.decadeindex_to_first_yearindex.mut_vec(),
|
||||
indexes.decadeindex_to_last_yearindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
|
||||
[
|
||||
self.weekindex.as_any_vecs(),
|
||||
self.monthindex.as_any_vecs(),
|
||||
self.quarterindex.as_any_vecs(),
|
||||
self.yearindex.as_any_vecs(),
|
||||
self.decadeindex.as_any_vecs(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{
|
||||
Dateindex, Decadeindex, Difficultyepoch, Height, Monthindex, Quarterindex, Weekindex, Yearindex,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_vec::{AnyStorableVec, Compressed};
|
||||
|
||||
use crate::storage::vecs::{Indexes, base::StorableVec, indexes};
|
||||
|
||||
use super::{ComputedType, StorableVecBuilder, StorableVecGeneatorOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StorableVecsStatsFromHeight<T>
|
||||
where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub dateindex: StorableVecBuilder<Dateindex, T>,
|
||||
pub weekindex: StorableVecBuilder<Weekindex, T>,
|
||||
pub difficultyepoch: StorableVecBuilder<Difficultyepoch, T>,
|
||||
pub monthindex: StorableVecBuilder<Monthindex, T>,
|
||||
pub quarterindex: StorableVecBuilder<Quarterindex, T>,
|
||||
pub yearindex: StorableVecBuilder<Yearindex, T>,
|
||||
// TODO: pub halvingepoch: StorableVecGeneator<Halvingepoch, T>,
|
||||
pub decadeindex: StorableVecBuilder<Decadeindex, T>,
|
||||
}
|
||||
|
||||
impl<T> StorableVecsStatsFromHeight<T>
|
||||
where
|
||||
T: ComputedType + Ord + From<f64>,
|
||||
f64: From<T>,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
compressed: Compressed,
|
||||
options: StorableVecGeneatorOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let dateindex = StorableVecBuilder::forced_import(path, compressed, options)?;
|
||||
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
Ok(Self {
|
||||
dateindex,
|
||||
weekindex: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
difficultyepoch: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
monthindex: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
quarterindex: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
yearindex: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
// halvingepoch: StorableVecGeneator::forced_import(path, compressed, options)?,
|
||||
decadeindex: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute(
|
||||
&mut self,
|
||||
source: &mut StorableVec<Height, T>,
|
||||
indexes: &mut indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
self.dateindex.compute(
|
||||
starting_indexes.dateindex,
|
||||
source,
|
||||
indexes.dateindex_to_first_height.mut_vec(),
|
||||
indexes.dateindex_to_last_height.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.weekindex.from_aligned(
|
||||
starting_indexes.weekindex,
|
||||
&mut self.dateindex,
|
||||
indexes.weekindex_to_first_dateindex.mut_vec(),
|
||||
indexes.weekindex_to_last_dateindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex.from_aligned(
|
||||
starting_indexes.monthindex,
|
||||
&mut self.dateindex,
|
||||
indexes.monthindex_to_first_dateindex.mut_vec(),
|
||||
indexes.monthindex_to_last_dateindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.quarterindex.from_aligned(
|
||||
starting_indexes.quarterindex,
|
||||
&mut self.monthindex,
|
||||
indexes.quarterindex_to_first_monthindex.mut_vec(),
|
||||
indexes.quarterindex_to_last_monthindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex.from_aligned(
|
||||
starting_indexes.yearindex,
|
||||
&mut self.monthindex,
|
||||
indexes.yearindex_to_first_monthindex.mut_vec(),
|
||||
indexes.yearindex_to_last_monthindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex.from_aligned(
|
||||
starting_indexes.decadeindex,
|
||||
&mut self.yearindex,
|
||||
indexes.decadeindex_to_first_yearindex.mut_vec(),
|
||||
indexes.decadeindex_to_last_yearindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.difficultyepoch.compute(
|
||||
starting_indexes.difficultyepoch,
|
||||
source,
|
||||
indexes.difficultyepoch_to_first_height.mut_vec(),
|
||||
indexes.difficultyepoch_to_last_height.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
|
||||
[
|
||||
self.dateindex.as_any_vecs(),
|
||||
self.weekindex.as_any_vecs(),
|
||||
self.difficultyepoch.as_any_vecs(),
|
||||
self.monthindex.as_any_vecs(),
|
||||
self.quarterindex.as_any_vecs(),
|
||||
self.yearindex.as_any_vecs(),
|
||||
// self.halvingepoch.as_any_vecs(),
|
||||
self.decadeindex.as_any_vecs(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{Difficultyepoch, Height};
|
||||
use brk_exit::Exit;
|
||||
use brk_vec::{AnyStorableVec, Compressed};
|
||||
|
||||
use crate::storage::vecs::{Indexes, base::StorableVec, indexes};
|
||||
|
||||
use super::{ComputedType, StorableVecBuilder, StorableVecGeneatorOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StorableVecsStatsFromHeightStrict<T>
|
||||
where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub difficultyepoch: StorableVecBuilder<Difficultyepoch, T>,
|
||||
// TODO: pub halvingepoch: StorableVecGeneator<Halvingepoch, T>,
|
||||
}
|
||||
|
||||
impl<T> StorableVecsStatsFromHeightStrict<T>
|
||||
where
|
||||
T: ComputedType + Ord + From<f64>,
|
||||
f64: From<T>,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
compressed: Compressed,
|
||||
options: StorableVecGeneatorOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
Ok(Self {
|
||||
difficultyepoch: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
// halvingepoch: StorableVecGeneator::forced_import(path, compressed, options)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute(
|
||||
&mut self,
|
||||
source: &mut StorableVec<Height, T>,
|
||||
indexes: &mut indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
self.difficultyepoch.compute(
|
||||
starting_indexes.difficultyepoch,
|
||||
source,
|
||||
indexes.difficultyepoch_to_first_height.mut_vec(),
|
||||
indexes.difficultyepoch_to_last_height.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
|
||||
[
|
||||
self.difficultyepoch.as_any_vecs(),
|
||||
// self.halvingepoch.as_any_vecs(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
mod from_date;
|
||||
mod from_height;
|
||||
mod from_height_strict;
|
||||
mod generic;
|
||||
mod stored_type;
|
||||
|
||||
pub use from_date::*;
|
||||
pub use from_height::*;
|
||||
pub use from_height_strict::*;
|
||||
pub use generic::*;
|
||||
pub use stored_type::*;
|
||||
@@ -1,86 +1,239 @@
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use brk_core::Txindex;
|
||||
use brk_core::{
|
||||
CheckedSub, Feerate, Sats, StoredU32, StoredU64, StoredUsize, TxVersion, Txindex, Txinindex,
|
||||
Txoutindex, Weight,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyStorableVec, Compressed, Version};
|
||||
use brk_parser::bitcoin;
|
||||
use brk_vec::{Compressed, DynamicVec, StoredIndex, Version};
|
||||
|
||||
use super::{Indexes, StorableVec, indexes};
|
||||
use super::{
|
||||
ComputedVec, Indexes,
|
||||
grouped::{
|
||||
ComputedValueVecsFromHeight, ComputedValueVecsFromTxindex, ComputedVecsFromHeight,
|
||||
ComputedVecsFromTxindex, StorableVecGeneatorOptions,
|
||||
},
|
||||
indexes, marketprice,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vecs {
|
||||
// pub height_to_fee: StorableVec<Txindex, Sats>,
|
||||
// pub height_to_inputcount: StorableVec<Height, u32>,
|
||||
// pub height_to_maxfeerate: StorableVec<Height, Feerate>,
|
||||
// pub height_to_medianfeerate: StorableVec<Height, Feerate>,
|
||||
// pub height_to_minfeerate: StorableVec<Height, Feerate>,
|
||||
// pub height_to_outputcount: StorableVec<Height, u32>,
|
||||
// pub height_to_subsidy: StorableVec<Height, u32>,
|
||||
// pub height_to_totalfees: StorableVec<Height, Sats>,
|
||||
// pub height_to_txcount: StorableVec<Height, u32>,
|
||||
// pub txindex_to_fee: StorableVec<Txindex, Sats>,
|
||||
pub txindex_to_is_coinbase: StorableVec<Txindex, bool>,
|
||||
// pub txindex_to_feerate: StorableVec<Txindex, Feerate>,
|
||||
pub txindex_to_inputs_count: StorableVec<Txindex, u32>,
|
||||
// pub txindex_to_inputs_sum: StorableVec<Txindex, Sats>,
|
||||
pub txindex_to_outputs_count: StorableVec<Txindex, u32>,
|
||||
// pub txindex_to_outputs_sum: StorableVec<Txindex, Sats>,
|
||||
// pub txinindex_to_value: StorableVec<Txinindex, Sats>,
|
||||
pub indexes_to_tx_count: ComputedVecsFromHeight<StoredU64>,
|
||||
pub indexes_to_fee: ComputedValueVecsFromTxindex,
|
||||
pub indexes_to_feerate: ComputedVecsFromTxindex<Feerate>,
|
||||
pub indexes_to_input_value: ComputedVecsFromTxindex<Sats>,
|
||||
pub indexes_to_output_value: ComputedVecsFromTxindex<Sats>,
|
||||
// pub txindex_to_is_v1: ComputedVec<Txindex, bool>,
|
||||
pub indexes_to_tx_v1: ComputedVecsFromHeight<StoredU32>,
|
||||
// pub txindex_to_is_v2: ComputedVec<Txindex, bool>,
|
||||
pub indexes_to_tx_v2: ComputedVecsFromHeight<StoredU32>,
|
||||
// pub txindex_to_is_v3: ComputedVec<Txindex, bool>,
|
||||
pub indexes_to_tx_v3: ComputedVecsFromHeight<StoredU32>,
|
||||
pub indexes_to_tx_vsize: ComputedVecsFromTxindex<StoredUsize>,
|
||||
pub indexes_to_tx_weight: ComputedVecsFromTxindex<Weight>,
|
||||
pub txindex_to_input_count: ComputedVecsFromTxindex<StoredU64>,
|
||||
pub txindex_to_is_coinbase: ComputedVec<Txindex, bool>,
|
||||
pub txindex_to_output_count: ComputedVecsFromTxindex<StoredU64>,
|
||||
pub txindex_to_vsize: ComputedVec<Txindex, StoredUsize>,
|
||||
pub txindex_to_weight: ComputedVec<Txindex, Weight>,
|
||||
/// Value == 0 when Coinbase
|
||||
pub txinindex_to_value: ComputedVec<Txinindex, Sats>,
|
||||
pub indexes_to_subsidy: ComputedValueVecsFromHeight,
|
||||
pub indexes_to_coinbase: ComputedValueVecsFromHeight,
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
pub fn forced_import(path: &Path, compressed: Compressed) -> color_eyre::Result<Self> {
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
compressed: Compressed,
|
||||
compute_dollars: bool,
|
||||
) -> color_eyre::Result<Self> {
|
||||
fs::create_dir_all(path)?;
|
||||
|
||||
Ok(Self {
|
||||
// height_to_fee: StorableVec::forced_import(&path.join("height_to_fee"), Version::ONE)?,
|
||||
// height_to_input_count: StorableVec::forced_import(
|
||||
// &path.join("height_to_input_count"),
|
||||
// Version::ONE,
|
||||
// )?,
|
||||
// height_to_maxfeerate: StorableVec::forced_import(&path.join("height_to_maxfeerate"), Version::ONE)?,
|
||||
// height_to_medianfeerate: StorableVec::forced_import(&path.join("height_to_medianfeerate"), Version::ONE)?,
|
||||
// height_to_minfeerate: StorableVec::forced_import(&path.join("height_to_minfeerate"), Version::ONE)?,
|
||||
// height_to_output_count: StorableVec::forced_import(
|
||||
// &path.join("height_to_output_count"),
|
||||
// Version::ONE,
|
||||
// )?,
|
||||
// height_to_subsidy: StorableVec::forced_import(&path.join("height_to_subsidy"), Version::ONE)?,
|
||||
// height_to_totalfees: StorableVec::forced_import(&path.join("height_to_totalfees"), Version::ONE)?,
|
||||
// height_to_txcount: StorableVec::forced_import(&path.join("height_to_txcount"), Version::ONE)?,
|
||||
// txindex_to_fee: StorableVec::forced_import(
|
||||
// &path.join("txindex_to_fee"),
|
||||
// Version::ONE,
|
||||
// )?,
|
||||
txindex_to_is_coinbase: StorableVec::forced_import(
|
||||
indexes_to_tx_count: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"tx_count",
|
||||
true,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_average()
|
||||
.add_minmax()
|
||||
.add_percentiles()
|
||||
.add_sum()
|
||||
.add_total(),
|
||||
)?,
|
||||
// height_to_subsidy: StorableVec::forced_import(&path.join("height_to_subsidy"), Version::ZERO)?,
|
||||
txindex_to_is_coinbase: ComputedVec::forced_import(
|
||||
&path.join("txindex_to_is_coinbase"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
// txindex_to_feerate: StorableVec::forced_import(&path.join("txindex_to_feerate"), Version::ONE)?,
|
||||
txindex_to_inputs_count: StorableVec::forced_import(
|
||||
&path.join("txindex_to_inputs_count"),
|
||||
Version::ONE,
|
||||
txindex_to_input_count: ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
"input_count",
|
||||
true,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_average()
|
||||
.add_minmax()
|
||||
.add_percentiles()
|
||||
.add_sum()
|
||||
.add_total(),
|
||||
)?,
|
||||
txindex_to_output_count: ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
"output_count",
|
||||
true,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_average()
|
||||
.add_minmax()
|
||||
.add_percentiles()
|
||||
.add_sum()
|
||||
.add_total(),
|
||||
)?,
|
||||
txinindex_to_value: ComputedVec::forced_import(
|
||||
&path.join("txinindex_to_value"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
// txindex_to_inputs_sum: StorableVec::forced_import(
|
||||
// &path.join("txindex_to_inputs_sum"),
|
||||
// Version::ONE,
|
||||
// )?,
|
||||
txindex_to_outputs_count: StorableVec::forced_import(
|
||||
&path.join("txindex_to_outputs_count"),
|
||||
Version::ONE,
|
||||
indexes_to_tx_v1: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"tx_v1",
|
||||
true,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_sum().add_total(),
|
||||
)?,
|
||||
indexes_to_tx_v2: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"tx_v2",
|
||||
true,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_sum().add_total(),
|
||||
)?,
|
||||
indexes_to_tx_v3: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"tx_v3",
|
||||
true,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_sum().add_total(),
|
||||
)?,
|
||||
indexes_to_input_value: ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
"input_value",
|
||||
true,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_average()
|
||||
.add_sum()
|
||||
.add_total(),
|
||||
)?,
|
||||
indexes_to_output_value: ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
"output_value",
|
||||
true,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_average()
|
||||
.add_sum()
|
||||
.add_total(),
|
||||
)?,
|
||||
indexes_to_fee: ComputedValueVecsFromTxindex::forced_import(
|
||||
path,
|
||||
"fee",
|
||||
true,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_sum()
|
||||
.add_total()
|
||||
.add_percentiles()
|
||||
.add_minmax()
|
||||
.add_average(),
|
||||
compute_dollars,
|
||||
)?,
|
||||
indexes_to_feerate: ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
"feerate",
|
||||
true,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_percentiles()
|
||||
.add_minmax()
|
||||
.add_average(),
|
||||
)?,
|
||||
txindex_to_weight: ComputedVec::forced_import(
|
||||
&path.join("txindex_to_weight"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
// txindex_to_outputs_sum: StorableVec::forced_import(
|
||||
// &path.join("txindex_to_outputs_sum"),
|
||||
// Version::ONE,
|
||||
// )?,
|
||||
// txinindex_to_value: StorableVec::forced_import(
|
||||
// &path.join("txinindex_to_value"),
|
||||
// Version::ONE,
|
||||
// compressed,
|
||||
// )?,
|
||||
txindex_to_vsize: ComputedVec::forced_import(
|
||||
&path.join("txindex_to_vsize"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
indexes_to_tx_vsize: ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
"tx_vsize",
|
||||
false,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_percentiles()
|
||||
.add_minmax()
|
||||
.add_average(),
|
||||
)?,
|
||||
indexes_to_tx_weight: ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
"tx_weight",
|
||||
false,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_percentiles()
|
||||
.add_minmax()
|
||||
.add_average(),
|
||||
)?,
|
||||
indexes_to_subsidy: ComputedValueVecsFromHeight::forced_import(
|
||||
path,
|
||||
"subsidy",
|
||||
true,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_percentiles()
|
||||
.add_sum()
|
||||
.add_total()
|
||||
.add_minmax()
|
||||
.add_average(),
|
||||
compute_dollars,
|
||||
)?,
|
||||
indexes_to_coinbase: ComputedValueVecsFromHeight::forced_import(
|
||||
path,
|
||||
"coinbase",
|
||||
true,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_sum()
|
||||
.add_total()
|
||||
.add_percentiles()
|
||||
.add_minmax()
|
||||
.add_average(),
|
||||
compute_dollars,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -89,24 +242,84 @@ impl Vecs {
|
||||
indexer: &mut Indexer,
|
||||
indexes: &mut indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
marketprices: &mut Option<&mut marketprice::Vecs>,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
self.indexes_to_tx_count.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, indexer, indexes, starting_indexes, exit| {
|
||||
v.compute_count_from_indexes(
|
||||
starting_indexes.height,
|
||||
indexer.mut_vecs().height_to_first_txindex.mut_vec(),
|
||||
indexes.height_to_last_txindex.mut_vec(),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
self.txindex_to_input_count.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, indexer, indexes, starting_indexes, exit| {
|
||||
v.compute_count_from_indexes(
|
||||
starting_indexes.txindex,
|
||||
indexer.mut_vecs().txindex_to_first_txinindex.mut_vec(),
|
||||
indexes.txindex_to_last_txinindex.mut_vec(),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
self.txindex_to_output_count.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, indexer, indexes, starting_indexes, exit| {
|
||||
v.compute_count_from_indexes(
|
||||
starting_indexes.txindex,
|
||||
indexer.mut_vecs().txindex_to_first_txoutindex.mut_vec(),
|
||||
indexes.txindex_to_last_txoutindex.mut_vec(),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
let mut compute_indexes_to_tx_vany =
|
||||
|indexes_to_tx_vany: &mut ComputedVecsFromHeight<StoredU32>, txversion| {
|
||||
indexes_to_tx_vany.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|vec, indexer, indexes, starting_indexes, exit| {
|
||||
let indexer_vecs = indexer.mut_vecs();
|
||||
vec.compute_filtered_count_from_indexes(
|
||||
starting_indexes.height,
|
||||
indexer_vecs.height_to_first_txindex.mut_vec(),
|
||||
indexes.height_to_last_txindex.mut_vec(),
|
||||
|txindex| {
|
||||
let v = indexer_vecs
|
||||
.txindex_to_txversion
|
||||
.double_unwrap_cached_get(txindex);
|
||||
v == txversion
|
||||
},
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)
|
||||
};
|
||||
compute_indexes_to_tx_vany(&mut self.indexes_to_tx_v1, TxVersion::ONE)?;
|
||||
compute_indexes_to_tx_vany(&mut self.indexes_to_tx_v2, TxVersion::TWO)?;
|
||||
compute_indexes_to_tx_vany(&mut self.indexes_to_tx_v3, TxVersion::THREE)?;
|
||||
|
||||
let indexer_vecs = indexer.mut_vecs();
|
||||
|
||||
self.txindex_to_inputs_count.compute_count_from_indexes(
|
||||
starting_indexes.txindex,
|
||||
indexer_vecs.txindex_to_first_txinindex.mut_vec(),
|
||||
indexes.txindex_to_last_txinindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.txindex_to_outputs_count.compute_count_from_indexes(
|
||||
starting_indexes.txindex,
|
||||
indexer_vecs.txindex_to_first_txoutindex.mut_vec(),
|
||||
indexes.txindex_to_last_txoutindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.txindex_to_is_coinbase.compute_is_first_ordered(
|
||||
starting_indexes.txindex,
|
||||
indexer_vecs.txindex_to_height.mut_vec(),
|
||||
@@ -114,52 +327,252 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// self.txinindex_to_value.compute_transform(
|
||||
// starting_indexes.txinindex,
|
||||
// indexer_vecs.txinindex_to_txoutindex.mut_vec(),
|
||||
// |(txinindex, txoutindex, slf, other)| {
|
||||
// let value =
|
||||
// if let Ok(Some(value)) = indexer_vecs.txoutindex_to_value.read(txoutindex) {
|
||||
// *value
|
||||
// } else {
|
||||
// dbg!(txinindex, txoutindex, slf.len(), other.len());
|
||||
// panic!()
|
||||
// };
|
||||
// (txinindex, value)
|
||||
// },
|
||||
// exit,
|
||||
// )?;
|
||||
self.txindex_to_weight.compute_transform(
|
||||
starting_indexes.txindex,
|
||||
indexer_vecs.txindex_to_base_size.mut_vec(),
|
||||
|(txindex, base_size, ..)| {
|
||||
let total_size = indexer_vecs
|
||||
.txindex_to_total_size
|
||||
.mut_vec()
|
||||
.double_unwrap_cached_get(txindex);
|
||||
|
||||
// self.vecs.txindex_to_fee.compute_transform(
|
||||
// &mut self.vecs.txindex_to_height,
|
||||
// &mut indexer.vecs().height_to_first_txindex,
|
||||
// )?;
|
||||
// This is the exact definition of a weight unit, as defined by BIP-141 (quote above).
|
||||
let wu = base_size * 3 + total_size;
|
||||
let weight = Weight::from(bitcoin::Weight::from_wu_usize(wu));
|
||||
|
||||
// self.vecs.height_to_dateindex.compute(...)
|
||||
(txindex, weight)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// ---
|
||||
// Date to X
|
||||
// ---
|
||||
// ...
|
||||
self.txindex_to_vsize.compute_transform(
|
||||
starting_indexes.txindex,
|
||||
self.txindex_to_weight.mut_vec(),
|
||||
|(txindex, weight, ..)| {
|
||||
let vbytes =
|
||||
StoredUsize::from(bitcoin::Weight::from(weight).to_vbytes_ceil() as usize);
|
||||
(txindex, vbytes)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// ---
|
||||
// Month to X
|
||||
// ---
|
||||
// ...
|
||||
self.txinindex_to_value.compute_transform(
|
||||
starting_indexes.txinindex,
|
||||
indexer_vecs.txinindex_to_txoutindex.mut_vec(),
|
||||
|(txinindex, txoutindex, slf, other)| {
|
||||
let value = if txoutindex == Txoutindex::COINBASE {
|
||||
Sats::ZERO
|
||||
} else if let Some(value) = indexer_vecs
|
||||
.txoutindex_to_value
|
||||
.mut_vec()
|
||||
.unwrap_cached_get(txoutindex)
|
||||
{
|
||||
value
|
||||
} else {
|
||||
dbg!(txinindex, txoutindex, slf.len(), other.len());
|
||||
panic!()
|
||||
};
|
||||
(txinindex, value)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// ---
|
||||
// Year to X
|
||||
// ---
|
||||
// ...
|
||||
self.indexes_to_output_value.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|vec, indexer, indexes, starting_indexes, exit| {
|
||||
let indexer_vecs = indexer.mut_vecs();
|
||||
vec.compute_sum_from_indexes(
|
||||
starting_indexes.txindex,
|
||||
indexer_vecs.txindex_to_first_txoutindex.mut_vec(),
|
||||
indexes.txindex_to_last_txoutindex.mut_vec(),
|
||||
indexer_vecs.txoutindex_to_value.mut_vec(),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
self.indexes_to_input_value.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|vec, indexer, indexes, starting_indexes, exit| {
|
||||
let indexer_vecs = indexer.mut_vecs();
|
||||
vec.compute_sum_from_indexes(
|
||||
starting_indexes.txindex,
|
||||
indexer_vecs.txindex_to_first_txinindex.mut_vec(),
|
||||
indexes.txindex_to_last_txinindex.mut_vec(),
|
||||
self.txinindex_to_value.mut_vec(),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
self.indexes_to_fee.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
marketprices,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|vec, _, _, starting_indexes, exit| {
|
||||
let txindex_to_output_value = self
|
||||
.indexes_to_output_value
|
||||
.txindex
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.mut_vec();
|
||||
vec.compute_transform(
|
||||
starting_indexes.txindex,
|
||||
self.indexes_to_input_value
|
||||
.txindex
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.mut_vec(),
|
||||
|(txindex, input_value, ..)| {
|
||||
if input_value.is_zero() {
|
||||
(txindex, input_value)
|
||||
} else {
|
||||
let output_value =
|
||||
txindex_to_output_value.double_unwrap_cached_get(txindex);
|
||||
(txindex, input_value.checked_sub(output_value).unwrap())
|
||||
}
|
||||
},
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
self.indexes_to_feerate.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|vec, _, _, starting_indexes, exit| {
|
||||
vec.compute_transform(
|
||||
starting_indexes.txindex,
|
||||
self.indexes_to_fee.sats.txindex.as_mut().unwrap().mut_vec(),
|
||||
|(txindex, fee, ..)| {
|
||||
let vsize = self
|
||||
.txindex_to_vsize
|
||||
.mut_vec()
|
||||
.double_unwrap_cached_get(txindex);
|
||||
|
||||
(txindex, Feerate::from((fee, vsize)))
|
||||
},
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
self.indexes_to_tx_weight.compute_rest(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(self.txindex_to_weight.mut_vec()),
|
||||
)?;
|
||||
|
||||
self.indexes_to_tx_vsize.compute_rest(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(self.txindex_to_vsize.mut_vec()),
|
||||
)?;
|
||||
|
||||
self.indexes_to_subsidy.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
marketprices,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|vec, indexer, indexes, starting_indexes, exit| {
|
||||
let indexer_vecs = indexer.mut_vecs();
|
||||
vec.compute_transform(
|
||||
starting_indexes.height,
|
||||
indexer_vecs.height_to_first_txindex.mut_vec(),
|
||||
|(height, txindex, ..)| {
|
||||
let first_txoutindex = indexer_vecs
|
||||
.txindex_to_first_txoutindex
|
||||
.double_unwrap_cached_get(txindex)
|
||||
.unwrap_to_usize();
|
||||
let last_txoutindex = indexes
|
||||
.txindex_to_last_txoutindex
|
||||
.mut_vec()
|
||||
.double_unwrap_cached_get(txindex)
|
||||
.unwrap_to_usize();
|
||||
let mut sats = Sats::ZERO;
|
||||
(first_txoutindex..=last_txoutindex).for_each(|txoutindex| {
|
||||
sats += indexer_vecs
|
||||
.txoutindex_to_value
|
||||
.double_unwrap_cached_get(Txoutindex::from(txoutindex));
|
||||
});
|
||||
(height, sats)
|
||||
},
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
self.indexes_to_coinbase.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
marketprices,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|vec, _, _, starting_indexes, exit| {
|
||||
vec.compute_transform(
|
||||
starting_indexes.height,
|
||||
self.indexes_to_subsidy
|
||||
.sats
|
||||
.height
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.mut_vec(),
|
||||
|(height, subsidy, ..)| {
|
||||
let fees = self
|
||||
.indexes_to_fee
|
||||
.sats
|
||||
.height
|
||||
.unwrap_sum()
|
||||
.mut_vec()
|
||||
.double_unwrap_cached_get(height);
|
||||
(height, subsidy.checked_sub(fees).unwrap())
|
||||
},
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
|
||||
vec![
|
||||
self.txindex_to_is_coinbase.any_vec(),
|
||||
self.txindex_to_inputs_count.any_vec(),
|
||||
self.txindex_to_outputs_count.any_vec(),
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn brk_vec::AnyStoredVec> {
|
||||
[
|
||||
vec![
|
||||
self.txindex_to_is_coinbase.any_vec(),
|
||||
self.txinindex_to_value.any_vec(),
|
||||
self.txindex_to_weight.any_vec(),
|
||||
self.txindex_to_vsize.any_vec(),
|
||||
],
|
||||
self.indexes_to_tx_count.any_vecs(),
|
||||
self.indexes_to_coinbase.any_vecs(),
|
||||
self.indexes_to_fee.any_vecs(),
|
||||
self.indexes_to_feerate.any_vecs(),
|
||||
self.indexes_to_input_value.any_vecs(),
|
||||
self.indexes_to_output_value.any_vecs(),
|
||||
self.indexes_to_subsidy.any_vecs(),
|
||||
self.indexes_to_tx_v1.any_vecs(),
|
||||
self.indexes_to_tx_v2.any_vecs(),
|
||||
self.indexes_to_tx_v3.any_vecs(),
|
||||
self.indexes_to_tx_vsize.any_vecs(),
|
||||
self.indexes_to_tx_weight.any_vecs(),
|
||||
self.txindex_to_input_count.any_vecs(),
|
||||
self.txindex_to_output_count.any_vecs(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<a href="https://deps.rs/crate/brk_core">
|
||||
<img src="https://deps.rs/crate/brk_core/latest/status.svg" alt="Dependency status">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cvrwpv3zEG">
|
||||
<a href="https://discord.gg/HaR3wpH3nr">
|
||||
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
|
||||
|
||||
@@ -1,10 +1,32 @@
|
||||
use std::ops::Mul;
|
||||
use std::ops::{Add, Div, Mul};
|
||||
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use super::Sats;
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Default,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Bitcoin(f64);
|
||||
|
||||
impl Add for Bitcoin {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul for Bitcoin {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: Self) -> Self::Output {
|
||||
@@ -12,6 +34,13 @@ impl Mul for Bitcoin {
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for Bitcoin {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 / rhs as f64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Sats> for Bitcoin {
|
||||
fn from(value: Sats) -> Self {
|
||||
Self(u64::from(value) as f64 / (u64::from(Sats::ONE_BTC) as f64))
|
||||
@@ -29,3 +58,18 @@ impl From<Bitcoin> for f64 {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Bitcoin {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as f64)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Bitcoin {}
|
||||
|
||||
#[allow(clippy::derive_ord_xor_partial_ord)]
|
||||
impl Ord for Bitcoin {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.0.partial_cmp(&other.0).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ pub struct Cents(u64);
|
||||
|
||||
impl From<Dollars> for Cents {
|
||||
fn from(value: Dollars) -> Self {
|
||||
Self((*value * 100.0).floor() as u64)
|
||||
Self((*value * 100.0).round() as u64)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,3 +31,15 @@ impl From<Cents> for f64 {
|
||||
value.0 as f64
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Cents {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Cents> for u64 {
|
||||
fn from(value: Cents) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use std::ops::{Add, Div};
|
||||
use std::ops::{Add, Div, Mul};
|
||||
|
||||
use derive_deref::Deref;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use super::Cents;
|
||||
use super::{Bitcoin, Cents, Sats};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
@@ -68,3 +68,12 @@ impl Ord for Dollars {
|
||||
self.0.partial_cmp(&other.0).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Bitcoin> for Dollars {
|
||||
type Output = Dollars;
|
||||
fn mul(self, rhs: Bitcoin) -> Self::Output {
|
||||
Self::from(Cents::from(
|
||||
u64::from(Sats::from(rhs)) * u64::from(Cents::from(self)) / u64::from(Sats::ONE_BTC),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,66 @@
|
||||
use std::ops::{Add, Div};
|
||||
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, FromBytes, Immutable, IntoBytes, KnownLayout)]
|
||||
use super::{Sats, StoredUsize};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Copy,
|
||||
Serialize,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct Feerate(f32);
|
||||
|
||||
impl From<(Sats, StoredUsize)> for Feerate {
|
||||
fn from((sats, vsize): (Sats, StoredUsize)) -> Self {
|
||||
Self((f64::from(sats) / f64::from(vsize)) as f32)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for Feerate {
|
||||
fn from(value: f64) -> Self {
|
||||
Self(value as f32)
|
||||
}
|
||||
}
|
||||
impl From<Feerate> for f64 {
|
||||
fn from(value: Feerate) -> Self {
|
||||
value.0 as f64
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Feerate {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for Feerate {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self((self.0 as f64 / rhs as f64) as f32)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Feerate {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as f32)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Feerate {}
|
||||
|
||||
#[allow(clippy::derive_ord_xor_partial_ord)]
|
||||
impl Ord for Feerate {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.0.partial_cmp(&other.0).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,10 @@ mod monthindex;
|
||||
mod ohlc;
|
||||
mod quarterindex;
|
||||
mod sats;
|
||||
mod stored_u32;
|
||||
mod stored_u64;
|
||||
mod stored_u8;
|
||||
mod stored_usize;
|
||||
mod timestamp;
|
||||
mod txid;
|
||||
mod txindex;
|
||||
@@ -55,6 +59,10 @@ pub use monthindex::*;
|
||||
pub use ohlc::*;
|
||||
pub use quarterindex::*;
|
||||
pub use sats::*;
|
||||
pub use stored_u8::*;
|
||||
pub use stored_u32::*;
|
||||
pub use stored_u64::*;
|
||||
pub use stored_usize::*;
|
||||
pub use timestamp::*;
|
||||
pub use txid::*;
|
||||
pub use txindex::*;
|
||||
|
||||
@@ -99,6 +99,51 @@ impl From<&OHLCCents> for OHLCDollars {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
|
||||
#[repr(C)]
|
||||
pub struct OHLCSats {
|
||||
pub open: Open<Sats>,
|
||||
pub high: High<Sats>,
|
||||
pub low: Low<Sats>,
|
||||
pub close: Close<Sats>,
|
||||
}
|
||||
|
||||
impl Serialize for OHLCSats {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut tup = serializer.serialize_tuple(4)?;
|
||||
tup.serialize_element(&self.open)?;
|
||||
tup.serialize_element(&self.high)?;
|
||||
tup.serialize_element(&self.low)?;
|
||||
tup.serialize_element(&self.close)?;
|
||||
tup.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(Open<Sats>, High<Sats>, Low<Sats>, Close<Sats>)> for OHLCSats {
|
||||
fn from(value: (Open<Sats>, High<Sats>, Low<Sats>, Close<Sats>)) -> Self {
|
||||
Self {
|
||||
open: value.0,
|
||||
high: value.1,
|
||||
low: value.2,
|
||||
close: value.3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Close<Sats>> for OHLCSats {
|
||||
fn from(value: Close<Sats>) -> Self {
|
||||
Self {
|
||||
open: Open::from(value),
|
||||
high: High::from(value),
|
||||
low: Low::from(value),
|
||||
close: value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Default,
|
||||
@@ -117,12 +162,40 @@ impl From<&OHLCCents> for OHLCDollars {
|
||||
)]
|
||||
#[repr(C)]
|
||||
pub struct Open<T>(T);
|
||||
impl<T> From<T> for Open<T> {
|
||||
fn from(value: T) -> Self {
|
||||
|
||||
impl<T> Open<T> {
|
||||
pub fn new(value: T) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<usize> for Open<T>
|
||||
where
|
||||
T: From<usize>,
|
||||
{
|
||||
fn from(value: usize) -> Self {
|
||||
Self(T::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<f64> for Open<T>
|
||||
where
|
||||
T: From<f64>,
|
||||
{
|
||||
fn from(value: f64) -> Self {
|
||||
Self(T::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Open<T>> for f64
|
||||
where
|
||||
f64: From<T>,
|
||||
{
|
||||
fn from(value: Open<T>) -> Self {
|
||||
Self::from(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Close<T>> for Open<T>
|
||||
where
|
||||
T: Copy,
|
||||
@@ -138,24 +211,6 @@ impl From<Open<Cents>> for Open<Dollars> {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Open<Dollars> {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Dollars::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for Open<Dollars> {
|
||||
fn from(value: f64) -> Self {
|
||||
Self(Dollars::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Open<Dollars>> for f64 {
|
||||
fn from(value: Open<Dollars>) -> Self {
|
||||
Self::from(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Add for Open<T>
|
||||
where
|
||||
T: Add<Output = T>,
|
||||
@@ -194,12 +249,40 @@ where
|
||||
)]
|
||||
#[repr(C)]
|
||||
pub struct High<T>(T);
|
||||
impl<T> From<T> for High<T> {
|
||||
fn from(value: T) -> Self {
|
||||
|
||||
impl<T> High<T> {
|
||||
pub fn new(value: T) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<usize> for High<T>
|
||||
where
|
||||
T: From<usize>,
|
||||
{
|
||||
fn from(value: usize) -> Self {
|
||||
Self(T::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<f64> for High<T>
|
||||
where
|
||||
T: From<f64>,
|
||||
{
|
||||
fn from(value: f64) -> Self {
|
||||
Self(T::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<High<T>> for f64
|
||||
where
|
||||
f64: From<T>,
|
||||
{
|
||||
fn from(value: High<T>) -> Self {
|
||||
Self::from(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Close<T>> for High<T>
|
||||
where
|
||||
T: Copy,
|
||||
@@ -215,24 +298,6 @@ impl From<High<Cents>> for High<Dollars> {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for High<Dollars> {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Dollars::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for High<Dollars> {
|
||||
fn from(value: f64) -> Self {
|
||||
Self(Dollars::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<High<Dollars>> for f64 {
|
||||
fn from(value: High<Dollars>) -> Self {
|
||||
Self::from(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Add for High<T>
|
||||
where
|
||||
T: Add<Output = T>,
|
||||
@@ -271,12 +336,40 @@ where
|
||||
)]
|
||||
#[repr(C)]
|
||||
pub struct Low<T>(T);
|
||||
impl<T> From<T> for Low<T> {
|
||||
fn from(value: T) -> Self {
|
||||
|
||||
impl<T> Low<T> {
|
||||
pub fn new(value: T) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<usize> for Low<T>
|
||||
where
|
||||
T: From<usize>,
|
||||
{
|
||||
fn from(value: usize) -> Self {
|
||||
Self(T::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<f64> for Low<T>
|
||||
where
|
||||
T: From<f64>,
|
||||
{
|
||||
fn from(value: f64) -> Self {
|
||||
Self(T::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Low<T>> for f64
|
||||
where
|
||||
f64: From<T>,
|
||||
{
|
||||
fn from(value: Low<T>) -> Self {
|
||||
Self::from(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Close<T>> for Low<T>
|
||||
where
|
||||
T: Copy,
|
||||
@@ -292,24 +385,6 @@ impl From<Low<Cents>> for Low<Dollars> {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Low<Dollars> {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Dollars::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for Low<Dollars> {
|
||||
fn from(value: f64) -> Self {
|
||||
Self(Dollars::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Low<Dollars>> for f64 {
|
||||
fn from(value: Low<Dollars>) -> Self {
|
||||
Self::from(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Add for Low<T>
|
||||
where
|
||||
T: Add<Output = T>,
|
||||
@@ -348,54 +423,52 @@ where
|
||||
)]
|
||||
#[repr(C)]
|
||||
pub struct Close<T>(T);
|
||||
impl<T> From<T> for Close<T> {
|
||||
fn from(value: T) -> Self {
|
||||
|
||||
impl<T> Close<T> {
|
||||
pub fn new(value: T) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<usize> for Close<T>
|
||||
where
|
||||
T: From<usize>,
|
||||
{
|
||||
fn from(value: usize) -> Self {
|
||||
Self(T::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<f64> for Close<T>
|
||||
where
|
||||
T: From<f64>,
|
||||
{
|
||||
fn from(value: f64) -> Self {
|
||||
Self(T::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Close<T>> for f64
|
||||
where
|
||||
f64: From<T>,
|
||||
{
|
||||
fn from(value: Close<T>) -> Self {
|
||||
Self::from(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
// impl<A, B> From<Close<A>> for Close<B>
|
||||
// where
|
||||
// B: From<A>,
|
||||
// {
|
||||
// fn from(value: Close<A>) -> Self {
|
||||
// Self(B::from(*value))
|
||||
impl From<Close<Cents>> for Close<Dollars> {
|
||||
fn from(value: Close<Cents>) -> Self {
|
||||
Self(Dollars::from(*value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Close<Dollars> {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Dollars::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Close<Sats> {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Sats::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for Close<Dollars> {
|
||||
fn from(value: f64) -> Self {
|
||||
Self(Dollars::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for Close<Sats> {
|
||||
fn from(value: f64) -> Self {
|
||||
Self(Sats::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Close<Dollars>> for f64 {
|
||||
fn from(value: Close<Dollars>) -> Self {
|
||||
Self::from(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Close<Sats>> for f64 {
|
||||
fn from(value: Close<Sats>) -> Self {
|
||||
Self::from(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Add for Close<T>
|
||||
where
|
||||
T: Add<Output = T>,
|
||||
|
||||
@@ -141,7 +141,7 @@ impl From<Sats> for Amount {
|
||||
|
||||
impl From<Bitcoin> for Sats {
|
||||
fn from(value: Bitcoin) -> Self {
|
||||
Self((f64::from(value) * (u64::from(Sats::ONE_BTC) as f64)) as u64)
|
||||
Self((f64::from(value) * (u64::from(Sats::ONE_BTC) as f64)).round() as u64)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
use std::ops::{Add, Div};
|
||||
|
||||
use derive_deref::Deref;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct StoredU32(u32);
|
||||
|
||||
impl StoredU32 {
|
||||
pub const ZERO: Self = Self(0);
|
||||
|
||||
pub fn new(counter: u32) -> Self {
|
||||
Self(counter)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for StoredU32 {
|
||||
fn from(value: u32) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for StoredU32 {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub<StoredU32> for StoredU32 {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for StoredU32 {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 / rhs as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for StoredU32 {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for StoredU32 {
|
||||
fn from(value: f64) -> Self {
|
||||
if value < 0.0 || value > u32::MAX as f64 {
|
||||
panic!()
|
||||
}
|
||||
Self(value as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StoredU32> for f64 {
|
||||
fn from(value: StoredU32) -> Self {
|
||||
value.0 as f64
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
use std::ops::{Add, Div};
|
||||
|
||||
use derive_deref::Deref;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
use super::{Txindex, Txinindex, Txoutindex};
|
||||
|
||||
#[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<Txinindex> for StoredU64 {
|
||||
fn from(value: Txinindex) -> Self {
|
||||
Self(*value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Txoutindex> for StoredU64 {
|
||||
fn from(value: Txoutindex) -> Self {
|
||||
Self(*value)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
use std::ops::{Add, Div};
|
||||
|
||||
use derive_deref::Deref;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct StoredU8(u8);
|
||||
|
||||
impl StoredU8 {
|
||||
pub const ZERO: Self = Self(0);
|
||||
|
||||
pub fn new(counter: u8) -> Self {
|
||||
Self(counter)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for StoredU8 {
|
||||
fn from(value: u8) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for StoredU8 {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u8)
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub<StoredU8> for StoredU8 {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for StoredU8 {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 / rhs as u8)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for StoredU8 {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for StoredU8 {
|
||||
fn from(value: f64) -> Self {
|
||||
if value < 0.0 || value > u32::MAX as f64 {
|
||||
panic!()
|
||||
}
|
||||
Self(value as u8)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StoredU8> for f64 {
|
||||
fn from(value: StoredU8) -> Self {
|
||||
value.0 as f64
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
use std::ops::{Add, Div};
|
||||
|
||||
use derive_deref::Deref;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
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 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
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::{CheckedSub, Error};
|
||||
|
||||
use super::StoredU32;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
@@ -97,3 +99,9 @@ impl From<Txindex> for ByteView {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Txindex> for StoredU32 {
|
||||
fn from(value: Txindex) -> Self {
|
||||
Self::from(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,31 @@ use derive_deref::Deref;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
#[derive(Debug, Deref, Clone, Copy, Immutable, IntoBytes, KnownLayout, FromBytes, Serialize)]
|
||||
use super::StoredU8;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
FromBytes,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct TxVersion(i32);
|
||||
|
||||
impl TxVersion {
|
||||
pub const ONE: Self = Self(1);
|
||||
pub const TWO: Self = Self(2);
|
||||
pub const THREE: Self = Self(3);
|
||||
}
|
||||
|
||||
impl From<bitcoin::transaction::Version> for TxVersion {
|
||||
fn from(value: bitcoin::transaction::Version) -> Self {
|
||||
Self(value.0)
|
||||
@@ -16,3 +38,9 @@ impl From<TxVersion> for bitcoin::transaction::Version {
|
||||
Self(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TxVersion> for StoredU8 {
|
||||
fn from(value: TxVersion) -> Self {
|
||||
Self::from(value.0 as u8)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,24 @@
|
||||
use std::ops::{Add, Div};
|
||||
|
||||
use derive_deref::Deref;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
#[derive(Debug, Deref, Clone, Copy, Immutable, IntoBytes, KnownLayout, FromBytes, Serialize)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
FromBytes,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Weight(u64);
|
||||
|
||||
impl From<bitcoin::Weight> for Weight {
|
||||
@@ -16,3 +32,35 @@ impl From<Weight> for bitcoin::Weight {
|
||||
Self::from_wu(*value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Weight {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for Weight {
|
||||
fn from(value: f64) -> Self {
|
||||
Self(value as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Weight> for f64 {
|
||||
fn from(value: Weight) -> Self {
|
||||
value.0 as f64
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Weight {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for Weight {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self::from(self.0 as usize / rhs)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<a href="https://deps.rs/crate/brk_exit">
|
||||
<img src="https://deps.rs/crate/brk_exit/latest/status.svg" alt="Dependency status">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cvrwpv3zEG">
|
||||
<a href="https://discord.gg/HaR3wpH3nr">
|
||||
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<a href="https://deps.rs/crate/brk_fetcher">
|
||||
<img src="https://deps.rs/crate/brk_fetcher/latest/status.svg" alt="Dependency status">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cvrwpv3zEG">
|
||||
<a href="https://discord.gg/HaR3wpH3nr">
|
||||
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
|
||||
|
||||
@@ -223,10 +223,10 @@ impl Binance {
|
||||
Ok((
|
||||
timestamp,
|
||||
OHLCCents::from((
|
||||
Open::from(get_cents(1)),
|
||||
High::from(get_cents(2)),
|
||||
Low::from(get_cents(3)),
|
||||
Close::from(get_cents(4)),
|
||||
Open::new(get_cents(1)),
|
||||
High::new(get_cents(2)),
|
||||
Low::new(get_cents(3)),
|
||||
Close::new(get_cents(4)),
|
||||
)),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -141,10 +141,10 @@ impl Kibo {
|
||||
};
|
||||
|
||||
Ok(OHLCCents::from((
|
||||
Open::from(get_value("open")?),
|
||||
High::from(get_value("high")?),
|
||||
Low::from(get_value("low")?),
|
||||
Close::from(get_value("close")?),
|
||||
Open::new(get_value("open")?),
|
||||
High::new(get_value("high")?),
|
||||
Low::new(get_value("low")?),
|
||||
Close::new(get_value("close")?),
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,10 +114,10 @@ impl Kraken {
|
||||
Ok((
|
||||
timestamp,
|
||||
OHLCCents::from((
|
||||
Open::from(get_cents(1)),
|
||||
High::from(get_cents(2)),
|
||||
Low::from(get_cents(3)),
|
||||
Close::from(get_cents(4)),
|
||||
Open::new(get_cents(1)),
|
||||
High::new(get_cents(2)),
|
||||
Low::new(get_cents(3)),
|
||||
Close::new(get_cents(4)),
|
||||
)),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -60,9 +60,9 @@ impl Fetcher {
|
||||
self.binance
|
||||
.get_from_1mn(timestamp, previous_timestamp)
|
||||
.unwrap_or_else(|_| {
|
||||
self.kibo.get_from_height(height).unwrap_or_else(|_| {
|
||||
self.kibo.get_from_height(height).unwrap_or_else(|e| {
|
||||
let date = Date::from(timestamp);
|
||||
|
||||
eprintln!("{e}");
|
||||
panic!(
|
||||
"
|
||||
Can't find the price for: height: {height} - date: {date}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<a href="https://deps.rs/crate/brk_indexer">
|
||||
<img src="https://deps.rs/crate/brk_indexer/latest/status.svg" alt="Dependency status">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cvrwpv3zEG">
|
||||
<a href="https://discord.gg/HaR3wpH3nr">
|
||||
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
|
||||
@@ -58,9 +58,14 @@ Stores: `src/storage/stores/mod.rs`
|
||||
|
||||
## Benchmark
|
||||
|
||||
Indexing `0..885_835` took `11 hours 6 min 50 s` on a Macbook Pro M3 Pro with 36 GB of RAM
|
||||
### Result 1 - 2025-04-12
|
||||
|
||||
`footprint` report:
|
||||
- Peak memory: `5115 MB`
|
||||
- Memory while waiting for a new block: `890 MB`
|
||||
- Reclaimable memory: `6478 MB`
|
||||
- version: `v0.0.21`
|
||||
- machine: `Macbook Pro M3 Pro (36GB RAM)`
|
||||
- mode: `raw`
|
||||
- from: `0`
|
||||
- to: `892_098`
|
||||
- time: `7 hours 10 min 22s`
|
||||
- peak memory: `6.1GB`
|
||||
- disk usage: `270 GB`
|
||||
- overhead: `36%` (`270 GB / 741 GB`)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::path::Path;
|
||||
use std::{path::Path, time::Instant};
|
||||
|
||||
use brk_core::default_bitcoin_path;
|
||||
use brk_exit::Exit;
|
||||
@@ -8,6 +8,8 @@ use brk_parser::{Parser, rpc};
|
||||
fn main() -> color_eyre::Result<()> {
|
||||
color_eyre::install()?;
|
||||
|
||||
let i = Instant::now();
|
||||
|
||||
brk_logger::init(Some(Path::new(".log")));
|
||||
|
||||
let bitcoin_dir = default_bitcoin_path();
|
||||
@@ -29,5 +31,7 @@ fn main() -> color_eyre::Result<()> {
|
||||
|
||||
indexer.index(&parser, rpc, &exit)?;
|
||||
|
||||
dbg!(i.elapsed());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -5,9 +5,10 @@ use brk_core::{
|
||||
Pushonlyindex, Txindex, Txinindex, Txoutindex, Unknownindex,
|
||||
};
|
||||
use brk_parser::NUMBER_OF_UNSAFE_BLOCKS;
|
||||
use brk_vec::{Result, StoredIndex, StoredType, Value};
|
||||
use color_eyre::eyre::ContextCompat;
|
||||
|
||||
use crate::{Stores, Vecs};
|
||||
use crate::{IndexedVec, Stores, Vecs};
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct Indexes {
|
||||
@@ -65,13 +66,7 @@ impl Indexes {
|
||||
.push_if_needed(height, self.p2wpkhindex)?;
|
||||
vecs.height_to_first_p2wshindex
|
||||
.push_if_needed(height, self.p2wshindex)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn push_future_if_needed(&mut self, vecs: &mut Vecs) -> brk_vec::Result<()> {
|
||||
self.height.increment();
|
||||
self.push_if_needed(vecs)?;
|
||||
self.height.decrement();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -111,32 +106,121 @@ impl TryFrom<(&mut Vecs, &Stores, &Client)> for Indexes {
|
||||
.unwrap_or(starting_height);
|
||||
|
||||
Ok(Self {
|
||||
addressindex: *vecs.height_to_first_addressindex.get(height)?.context("")?,
|
||||
emptyindex: *vecs.height_to_first_emptyindex.get(height)?.context("")?,
|
||||
addressindex: *starting_index(
|
||||
&vecs.height_to_first_addressindex,
|
||||
&vecs.addressindex_to_height,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
emptyindex: *starting_index(
|
||||
&vecs.height_to_first_emptyindex,
|
||||
&vecs.emptyindex_to_height,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
height,
|
||||
multisigindex: *vecs
|
||||
.height_to_first_multisigindex
|
||||
.get(height)?
|
||||
.context("")?,
|
||||
opreturnindex: *vecs
|
||||
.height_to_first_opreturnindex
|
||||
.get(height)?
|
||||
.context("")?,
|
||||
p2pk33index: *vecs.height_to_first_p2pk33index.get(height)?.context("")?,
|
||||
p2pk65index: *vecs.height_to_first_p2pk65index.get(height)?.context("")?,
|
||||
p2pkhindex: *vecs.height_to_first_p2pkhindex.get(height)?.context("")?,
|
||||
p2shindex: *vecs.height_to_first_p2shindex.get(height)?.context("")?,
|
||||
p2trindex: *vecs.height_to_first_p2trindex.get(height)?.context("")?,
|
||||
p2wpkhindex: *vecs.height_to_first_p2wpkhindex.get(height)?.context("")?,
|
||||
p2wshindex: *vecs.height_to_first_p2wshindex.get(height)?.context("")?,
|
||||
pushonlyindex: *vecs
|
||||
.height_to_first_pushonlyindex
|
||||
.get(height)?
|
||||
.context("")?,
|
||||
txindex: *vecs.height_to_first_txindex.get(height)?.context("")?,
|
||||
txinindex: *vecs.height_to_first_txinindex.get(height)?.context("")?,
|
||||
txoutindex: *vecs.height_to_first_txoutindex.get(height)?.context("")?,
|
||||
unknownindex: *vecs.height_to_first_unknownindex.get(height)?.context("")?,
|
||||
multisigindex: *starting_index(
|
||||
&vecs.height_to_first_multisigindex,
|
||||
&vecs.multisigindex_to_height,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
opreturnindex: *starting_index(
|
||||
&vecs.height_to_first_opreturnindex,
|
||||
&vecs.opreturnindex_to_height,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
p2pk33index: *starting_index(
|
||||
&vecs.height_to_first_p2pk33index,
|
||||
&vecs.p2pk33index_to_height,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
p2pk65index: *starting_index(
|
||||
&vecs.height_to_first_p2pk65index,
|
||||
&vecs.p2pk65index_to_height,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
p2pkhindex: *starting_index(
|
||||
&vecs.height_to_first_p2pkhindex,
|
||||
&vecs.p2pkhindex_to_height,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
p2shindex: *starting_index(
|
||||
&vecs.height_to_first_p2shindex,
|
||||
&vecs.p2shindex_to_height,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
p2trindex: *starting_index(
|
||||
&vecs.height_to_first_p2trindex,
|
||||
&vecs.p2trindex_to_height,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
p2wpkhindex: *starting_index(
|
||||
&vecs.height_to_first_p2wpkhindex,
|
||||
&vecs.p2wpkhindex_to_height,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
p2wshindex: *starting_index(
|
||||
&vecs.height_to_first_p2wshindex,
|
||||
&vecs.p2wshindex_to_height,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
pushonlyindex: *starting_index(
|
||||
&vecs.height_to_first_pushonlyindex,
|
||||
&vecs.pushonlyindex_to_height,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
txindex: *starting_index(
|
||||
&vecs.height_to_first_txindex,
|
||||
&vecs.txindex_to_height,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
txinindex: *starting_index(
|
||||
&vecs.height_to_first_txinindex,
|
||||
&vecs.txinindex_to_height,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
txoutindex: *starting_index(
|
||||
&vecs.height_to_first_txoutindex,
|
||||
&vecs.txoutindex_to_height,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
unknownindex: *starting_index(
|
||||
&vecs.height_to_first_unknownindex,
|
||||
&vecs.unknownindex_to_height,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn starting_index<'a, I>(
|
||||
height_to_index: &'a IndexedVec<Height, I>,
|
||||
index_to_height: &'a IndexedVec<I, Height>,
|
||||
starting_height: Height,
|
||||
) -> Result<Option<Value<'a, I>>>
|
||||
where
|
||||
I: StoredType + StoredIndex + From<usize>,
|
||||
{
|
||||
if height_to_index
|
||||
.height()
|
||||
.is_ok_and(|h| h + 1_u32 == starting_height)
|
||||
{
|
||||
Ok(Some(Value::Owned(I::from(index_to_height.len()))))
|
||||
} else {
|
||||
height_to_index.get(starting_height)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ pub use stores::*;
|
||||
pub use vecs::*;
|
||||
|
||||
const SNAPSHOT_BLOCK_RANGE: usize = 1000;
|
||||
const COLLISIONS_CHECKED_UP_TO: u32 = 888_000;
|
||||
const COLLISIONS_CHECKED_UP_TO: u32 = 890_000;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Indexer {
|
||||
@@ -81,7 +81,7 @@ impl Indexer {
|
||||
self.stores.as_ref().unwrap(),
|
||||
rpc,
|
||||
))
|
||||
.unwrap_or_else(|_| {
|
||||
.unwrap_or_else(|_report| {
|
||||
let indexes = Indexes::default();
|
||||
indexes.push_if_needed(self.vecs.as_mut().unwrap()).unwrap();
|
||||
indexes
|
||||
@@ -101,6 +101,7 @@ impl Indexer {
|
||||
let vecs = self.vecs.as_mut().unwrap();
|
||||
let stores = self.stores.as_mut().unwrap();
|
||||
|
||||
// Cloned because we want to return starting indexes for the computer
|
||||
let mut idxs = starting_indexes.clone();
|
||||
|
||||
let start = Some(idxs.height);
|
||||
@@ -153,6 +154,8 @@ impl Indexer {
|
||||
return Err(eyre!("Collision, expect prefix to need be set yet"));
|
||||
}
|
||||
|
||||
idxs.push_if_needed(vecs)?;
|
||||
|
||||
stores
|
||||
.blockhash_prefix_to_height
|
||||
.insert_if_needed(blockhash_prefix, height, height);
|
||||
@@ -162,7 +165,7 @@ impl Indexer {
|
||||
.push_if_needed(height, block.header.difficulty_float())?;
|
||||
vecs.height_to_timestamp
|
||||
.push_if_needed(height, Timestamp::from(block.header.time))?;
|
||||
vecs.height_to_size.push_if_needed(height, block.total_size())?;
|
||||
vecs.height_to_total_size.push_if_needed(height, block.total_size().into())?;
|
||||
vecs.height_to_weight.push_if_needed(height, block.weight().into())?;
|
||||
|
||||
let inputs = block
|
||||
@@ -462,6 +465,9 @@ impl Indexer {
|
||||
|
||||
vecs.txoutindex_to_value.push_if_needed(txoutindex, sats)?;
|
||||
|
||||
vecs.txoutindex_to_height
|
||||
.push_if_needed(txoutindex, height)?;
|
||||
|
||||
let mut addressindex = idxs.addressindex;
|
||||
|
||||
let mut addresshash = None;
|
||||
@@ -481,18 +487,55 @@ impl Indexer {
|
||||
idxs.addressindex.increment();
|
||||
|
||||
let addresstypeindex = match addresstype {
|
||||
Addresstype::Empty => idxs.emptyindex.copy_then_increment(),
|
||||
Addresstype::Multisig => idxs.multisigindex.copy_then_increment(),
|
||||
Addresstype::OpReturn => idxs.opreturnindex.copy_then_increment(),
|
||||
Addresstype::PushOnly => idxs.pushonlyindex.copy_then_increment(),
|
||||
Addresstype::Unknown => idxs.unknownindex.copy_then_increment(),
|
||||
Addresstype::P2PK65 => idxs.p2pk65index.copy_then_increment(),
|
||||
Addresstype::P2PK33 => idxs.p2pk33index.copy_then_increment(),
|
||||
Addresstype::P2PKH => idxs.p2pkhindex.copy_then_increment(),
|
||||
Addresstype::P2SH => idxs.p2shindex.copy_then_increment(),
|
||||
Addresstype::P2WPKH => idxs.p2wpkhindex.copy_then_increment(),
|
||||
Addresstype::P2WSH => idxs.p2wshindex.copy_then_increment(),
|
||||
Addresstype::P2TR => idxs.p2trindex.copy_then_increment(),
|
||||
Addresstype::Empty => {
|
||||
vecs.emptyindex_to_height
|
||||
.push_if_needed(idxs.emptyindex, height)?;
|
||||
idxs.emptyindex.copy_then_increment()
|
||||
},
|
||||
Addresstype::Multisig => {
|
||||
vecs.multisigindex_to_height.push_if_needed(idxs.multisigindex, height)?;
|
||||
idxs.multisigindex.copy_then_increment()
|
||||
},
|
||||
Addresstype::OpReturn => {
|
||||
vecs.opreturnindex_to_height.push_if_needed(idxs.opreturnindex, height)?;
|
||||
idxs.opreturnindex.copy_then_increment()
|
||||
},
|
||||
Addresstype::PushOnly => {
|
||||
vecs.pushonlyindex_to_height.push_if_needed(idxs.pushonlyindex, height)?;
|
||||
idxs.pushonlyindex.copy_then_increment()
|
||||
},
|
||||
Addresstype::Unknown => {
|
||||
vecs.unknownindex_to_height.push_if_needed(idxs.unknownindex, height)?;
|
||||
idxs.unknownindex.copy_then_increment()
|
||||
},
|
||||
Addresstype::P2PK65 => {
|
||||
vecs.p2pk65index_to_height.push_if_needed(idxs.p2pk65index, height)?;
|
||||
idxs.p2pk65index.copy_then_increment()
|
||||
},
|
||||
Addresstype::P2PK33 => {
|
||||
vecs.p2pk33index_to_height.push_if_needed(idxs.p2pk33index, height)?;
|
||||
idxs.p2pk33index.copy_then_increment()
|
||||
},
|
||||
Addresstype::P2PKH => {
|
||||
vecs.p2pkhindex_to_height.push_if_needed(idxs.p2pkhindex, height)?;
|
||||
idxs.p2pkhindex.copy_then_increment()
|
||||
},
|
||||
Addresstype::P2SH => {
|
||||
vecs.p2shindex_to_height.push_if_needed(idxs.p2shindex, height)?;
|
||||
idxs.p2shindex.copy_then_increment()
|
||||
},
|
||||
Addresstype::P2WPKH => {
|
||||
vecs.p2wpkhindex_to_height.push_if_needed(idxs.p2wpkhindex, height)?;
|
||||
idxs.p2wpkhindex.copy_then_increment()
|
||||
},
|
||||
Addresstype::P2WSH => {
|
||||
vecs.p2wshindex_to_height.push_if_needed(idxs.p2wshindex, height)?;
|
||||
idxs.p2wshindex.copy_then_increment()
|
||||
},
|
||||
Addresstype::P2TR => {
|
||||
vecs.p2trindex_to_height.push_if_needed(idxs.p2trindex, height)?;
|
||||
idxs.p2trindex.copy_then_increment()
|
||||
},
|
||||
};
|
||||
|
||||
vecs.addressindex_to_addresstype
|
||||
@@ -580,6 +623,10 @@ impl Indexer {
|
||||
|
||||
vecs.txinindex_to_txoutindex.push_if_needed(txinindex, txoutindex)?;
|
||||
|
||||
vecs.txinindex_to_height
|
||||
.push_if_needed(txinindex, height)?;
|
||||
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -668,8 +715,6 @@ impl Indexer {
|
||||
idxs.txinindex += Txinindex::from(inputs_len);
|
||||
idxs.txoutindex += Txoutindex::from(outputs_len);
|
||||
|
||||
idxs.push_future_if_needed(vecs)?;
|
||||
|
||||
export_if_needed(stores, vecs, height, false, exit)?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -98,10 +98,10 @@ where
|
||||
|
||||
if !self.puts.is_empty() {
|
||||
unreachable!("Shouldn't reach this");
|
||||
// self.puts.remove(&key);
|
||||
}
|
||||
// dbg!(&key);
|
||||
if !self.dels.insert(key) {
|
||||
|
||||
if !self.dels.insert(key.clone()) {
|
||||
dbg!(key, &self.meta.path());
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,10 @@ impl StoreMeta {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
pub fn version(&self) -> Version {
|
||||
self.version
|
||||
}
|
||||
|
||||
pub fn export(&mut self, len: usize, height: Height) -> io::Result<()> {
|
||||
self.len = len;
|
||||
self.write_length()?;
|
||||
@@ -61,6 +65,10 @@ impl StoreMeta {
|
||||
fs::create_dir(path)
|
||||
}
|
||||
|
||||
pub fn path(&self) -> &Path {
|
||||
&self.pathbuf
|
||||
}
|
||||
|
||||
fn path_version(&self) -> PathBuf {
|
||||
Self::path_version_(&self.pathbuf)
|
||||
}
|
||||
|
||||
@@ -27,11 +27,11 @@ impl Stores {
|
||||
pub fn import(path: &Path) -> color_eyre::Result<Self> {
|
||||
thread::scope(|scope| {
|
||||
let addresshash_to_addressindex = scope
|
||||
.spawn(|| Store::import(&path.join("addresshash_to_addressindex"), Version::ONE));
|
||||
.spawn(|| Store::import(&path.join("addresshash_to_addressindex"), Version::ZERO));
|
||||
let blockhash_prefix_to_height = scope
|
||||
.spawn(|| Store::import(&path.join("blockhash_prefix_to_height"), Version::ONE));
|
||||
.spawn(|| Store::import(&path.join("blockhash_prefix_to_height"), Version::ZERO));
|
||||
let txid_prefix_to_txindex =
|
||||
scope.spawn(|| Store::import(&path.join("txid_prefix_to_txindex"), Version::ONE));
|
||||
scope.spawn(|| Store::import(&path.join("txid_prefix_to_txindex"), Version::ZERO));
|
||||
|
||||
Ok(Self {
|
||||
addresshash_to_addressindex: addresshash_to_addressindex.join().unwrap()?,
|
||||
|
||||
@@ -1,113 +1,80 @@
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
fmt::Debug,
|
||||
io,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use brk_vec::{
|
||||
AnyStorableVec, Compressed, Error, MAX_CACHE_SIZE, MAX_PAGE_SIZE, Result, StoredIndex,
|
||||
StoredType, Value, Version,
|
||||
Compressed, DynamicVec, Error, GenericVec, Result, StoredIndex, StoredType, StoredVec, Value,
|
||||
Version,
|
||||
};
|
||||
|
||||
use super::Height;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StorableVec<I, T> {
|
||||
height: Option<Height>,
|
||||
vec: brk_vec::StorableVec<I, T>,
|
||||
}
|
||||
|
||||
impl<I, T> StorableVec<I, T>
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IndexedVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
pub const SIZE_OF_T: usize = size_of::<T>();
|
||||
pub const PER_PAGE: usize = MAX_PAGE_SIZE / Self::SIZE_OF_T;
|
||||
pub const PAGE_SIZE: usize = Self::PER_PAGE * Self::SIZE_OF_T;
|
||||
pub const CACHE_LENGTH: usize = MAX_CACHE_SIZE / Self::PAGE_SIZE;
|
||||
height: Option<Height>,
|
||||
inner: StoredVec<I, T>,
|
||||
}
|
||||
|
||||
impl<I, T> IndexedVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
version: Version,
|
||||
compressed: Compressed,
|
||||
) -> brk_vec::Result<Self> {
|
||||
let mut vec = brk_vec::StorableVec::forced_import(path, version, compressed)?;
|
||||
let mut inner = StoredVec::forced_import(path, version, compressed)?;
|
||||
|
||||
vec.enable_large_cache();
|
||||
inner.enable_large_cache_if_needed();
|
||||
|
||||
Ok(Self {
|
||||
height: Height::try_from(Self::path_height_(path).as_path()).ok(),
|
||||
vec,
|
||||
inner,
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get(&self, index: I) -> Result<Option<Value<'_, T>>> {
|
||||
self.get_(index.to_usize()?)
|
||||
self.inner.get(index)
|
||||
}
|
||||
fn get_(&self, index: usize) -> Result<Option<Value<'_, T>>> {
|
||||
match self.vec.index_to_pushed_index(index) {
|
||||
Ok(index) => {
|
||||
if let Some(index) = index {
|
||||
return Ok(self.vec.pushed().get(index).map(|v| Value::Ref(v)));
|
||||
}
|
||||
}
|
||||
Err(Error::IndexTooHigh) => return Ok(None),
|
||||
Err(Error::IndexTooLow) => {}
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
|
||||
let large_cache_len = self.vec.large_cache_len();
|
||||
if large_cache_len != 0 {
|
||||
let page_index = Self::index_to_page_index(index);
|
||||
let last_index = self.vec.stored_len() - 1;
|
||||
let max_page_index = Self::index_to_page_index(last_index);
|
||||
let min_page_index = (max_page_index + 1) - large_cache_len;
|
||||
|
||||
if page_index >= min_page_index {
|
||||
let values = self
|
||||
.vec
|
||||
.pages()
|
||||
.unwrap()
|
||||
.get(page_index - min_page_index)
|
||||
.ok_or(Error::MmapsVecIsTooSmall)?
|
||||
.get_or_init(|| self.vec.decode_page(page_index).unwrap());
|
||||
|
||||
return Ok(values.get(index)?.map(|v| Value::Ref(v)));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(self.vec.read_(index)?.map(|v| Value::Owned(v)))
|
||||
#[inline]
|
||||
pub fn unwrap_cached_get(&mut self, index: I) -> Option<T> {
|
||||
self.inner.unwrap_cached_get(index)
|
||||
}
|
||||
#[inline]
|
||||
pub fn double_unwrap_cached_get(&mut self, index: I) -> T {
|
||||
self.inner.double_unwrap_cached_get(index)
|
||||
}
|
||||
|
||||
pub fn iter_from<F>(&mut self, index: I, f: F) -> Result<()>
|
||||
where
|
||||
F: FnMut((I, &T)) -> Result<()>,
|
||||
F: FnMut((I, T, &mut dyn DynamicVec<I = I, T = T>)) -> Result<()>,
|
||||
{
|
||||
self.vec.iter_from(index, f)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn index_to_page_index(index: usize) -> usize {
|
||||
index / Self::PER_PAGE
|
||||
self.inner.iter_from(index, f)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn push_if_needed(&mut self, index: I, value: T) -> Result<()> {
|
||||
match self.vec.len().cmp(&index.to_usize()?) {
|
||||
match self.inner.len().cmp(&index.to_usize()?) {
|
||||
Ordering::Greater => {
|
||||
// dbg!(len, index, &self.pathbuf);
|
||||
// panic!();
|
||||
Ok(())
|
||||
}
|
||||
Ordering::Equal => {
|
||||
self.vec.push(value);
|
||||
self.inner.push(value);
|
||||
Ok(())
|
||||
}
|
||||
Ordering::Less => {
|
||||
dbg!(index, value);
|
||||
dbg!(index, value, self.inner.len(), self.path_height());
|
||||
Err(Error::IndexTooHigh)
|
||||
}
|
||||
}
|
||||
@@ -117,70 +84,57 @@ where
|
||||
if self.height.is_none_or(|self_height| self_height != height) {
|
||||
height.write(&self.path_height())?;
|
||||
}
|
||||
self.vec.truncate_if_needed(index)?;
|
||||
self.inner.truncate_if_needed(index)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn flush(&mut self, height: Height) -> io::Result<()> {
|
||||
pub fn flush(&mut self, height: Height) -> Result<()> {
|
||||
height.write(&self.path_height())?;
|
||||
self.vec.flush()
|
||||
self.inner.flush()
|
||||
}
|
||||
|
||||
pub fn vec(&self) -> &brk_vec::StorableVec<I, T> {
|
||||
&self.vec
|
||||
pub fn vec(&self) -> &StoredVec<I, T> {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub fn mut_vec(&mut self) -> &mut brk_vec::StorableVec<I, T> {
|
||||
&mut self.vec
|
||||
pub fn mut_vec(&mut self) -> &mut StoredVec<I, T> {
|
||||
&mut self.inner
|
||||
}
|
||||
|
||||
pub fn any_vec(&self) -> &dyn AnyStorableVec {
|
||||
&self.vec
|
||||
pub fn any_vec(&self) -> &dyn brk_vec::AnyStoredVec {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.vec.len()
|
||||
self.inner.len()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.vec.is_empty()
|
||||
self.inner.is_empty()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn hasnt(&self, index: I) -> Result<bool> {
|
||||
self.vec.has(index).map(|b| !b)
|
||||
self.inner.has(index).map(|b| !b)
|
||||
}
|
||||
|
||||
pub fn height(&self) -> brk_core::Result<Height> {
|
||||
Height::try_from(self.path_height().as_path())
|
||||
}
|
||||
fn path_height(&self) -> PathBuf {
|
||||
Self::path_height_(self.vec.path())
|
||||
Self::path_height_(self.inner.path())
|
||||
}
|
||||
fn path_height_(path: &Path) -> PathBuf {
|
||||
path.join("height")
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> Clone for StorableVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
height: self.height,
|
||||
vec: self.vec.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AnyIndexedVec: Send + Sync {
|
||||
fn height(&self) -> brk_core::Result<Height>;
|
||||
fn flush(&mut self, height: Height) -> io::Result<()>;
|
||||
fn flush(&mut self, height: Height) -> Result<()>;
|
||||
}
|
||||
|
||||
impl<I, T> AnyIndexedVec for StorableVec<I, T>
|
||||
impl<I, T> AnyIndexedVec for IndexedVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
@@ -189,7 +143,7 @@ where
|
||||
self.height()
|
||||
}
|
||||
|
||||
fn flush(&mut self, height: Height) -> io::Result<()> {
|
||||
fn flush(&mut self, height: Height) -> Result<()> {
|
||||
self.flush(height)
|
||||
}
|
||||
}
|
||||
|
||||
+298
-157
@@ -1,13 +1,13 @@
|
||||
use std::{fs, io, path::Path};
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use brk_core::{
|
||||
Addressbytes, Addressindex, Addresstype, Addresstypeindex, BlockHash, Emptyindex, Height,
|
||||
LockTime, Multisigindex, Opreturnindex, P2PK33AddressBytes, P2PK33index, P2PK65AddressBytes,
|
||||
P2PK65index, P2PKHAddressBytes, P2PKHindex, P2SHAddressBytes, P2SHindex, P2TRAddressBytes,
|
||||
P2TRindex, P2WPKHAddressBytes, P2WPKHindex, P2WSHAddressBytes, P2WSHindex, Pushonlyindex, Sats,
|
||||
Timestamp, TxVersion, Txid, Txindex, Txinindex, Txoutindex, Unknownindex, Weight,
|
||||
StoredUsize, Timestamp, TxVersion, Txid, Txindex, Txinindex, Txoutindex, Unknownindex, Weight,
|
||||
};
|
||||
use brk_vec::{AnyStorableVec, Compressed, Version};
|
||||
use brk_vec::{AnyStoredVec, Compressed, Result, Version};
|
||||
use rayon::prelude::*;
|
||||
|
||||
use crate::Indexes;
|
||||
@@ -18,50 +18,64 @@ pub use base::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vecs {
|
||||
pub addressindex_to_addresstype: StorableVec<Addressindex, Addresstype>,
|
||||
pub addressindex_to_addresstypeindex: StorableVec<Addressindex, Addresstypeindex>,
|
||||
pub addressindex_to_height: StorableVec<Addressindex, Height>,
|
||||
pub height_to_blockhash: StorableVec<Height, BlockHash>,
|
||||
pub height_to_difficulty: StorableVec<Height, f64>,
|
||||
pub height_to_first_addressindex: StorableVec<Height, Addressindex>,
|
||||
pub height_to_first_emptyindex: StorableVec<Height, Emptyindex>,
|
||||
pub height_to_first_multisigindex: StorableVec<Height, Multisigindex>,
|
||||
pub height_to_first_opreturnindex: StorableVec<Height, Opreturnindex>,
|
||||
pub height_to_first_pushonlyindex: StorableVec<Height, Pushonlyindex>,
|
||||
pub height_to_first_txindex: StorableVec<Height, Txindex>,
|
||||
pub height_to_first_txinindex: StorableVec<Height, Txinindex>,
|
||||
pub height_to_first_txoutindex: StorableVec<Height, Txoutindex>,
|
||||
pub height_to_first_unknownindex: StorableVec<Height, Unknownindex>,
|
||||
pub height_to_first_p2pk33index: StorableVec<Height, P2PK33index>,
|
||||
pub height_to_first_p2pk65index: StorableVec<Height, P2PK65index>,
|
||||
pub height_to_first_p2pkhindex: StorableVec<Height, P2PKHindex>,
|
||||
pub height_to_first_p2shindex: StorableVec<Height, P2SHindex>,
|
||||
pub height_to_first_p2trindex: StorableVec<Height, P2TRindex>,
|
||||
pub height_to_first_p2wpkhindex: StorableVec<Height, P2WPKHindex>,
|
||||
pub height_to_first_p2wshindex: StorableVec<Height, P2WSHindex>,
|
||||
pub height_to_size: StorableVec<Height, usize>,
|
||||
pub height_to_timestamp: StorableVec<Height, Timestamp>,
|
||||
pub height_to_weight: StorableVec<Height, Weight>,
|
||||
pub p2pk33index_to_p2pk33addressbytes: StorableVec<P2PK33index, P2PK33AddressBytes>,
|
||||
pub p2pk65index_to_p2pk65addressbytes: StorableVec<P2PK65index, P2PK65AddressBytes>,
|
||||
pub p2pkhindex_to_p2pkhaddressbytes: StorableVec<P2PKHindex, P2PKHAddressBytes>,
|
||||
pub p2shindex_to_p2shaddressbytes: StorableVec<P2SHindex, P2SHAddressBytes>,
|
||||
pub p2trindex_to_p2traddressbytes: StorableVec<P2TRindex, P2TRAddressBytes>,
|
||||
pub p2wpkhindex_to_p2wpkhaddressbytes: StorableVec<P2WPKHindex, P2WPKHAddressBytes>,
|
||||
pub p2wshindex_to_p2wshaddressbytes: StorableVec<P2WSHindex, P2WSHAddressBytes>,
|
||||
pub txindex_to_first_txinindex: StorableVec<Txindex, Txinindex>,
|
||||
pub txindex_to_first_txoutindex: StorableVec<Txindex, Txoutindex>,
|
||||
pub txindex_to_height: StorableVec<Txindex, Height>,
|
||||
pub txindex_to_locktime: StorableVec<Txindex, LockTime>,
|
||||
pub txindex_to_txid: StorableVec<Txindex, Txid>,
|
||||
pub txindex_to_base_size: StorableVec<Txindex, usize>,
|
||||
pub txindex_to_total_size: StorableVec<Txindex, usize>,
|
||||
pub txindex_to_is_explicitly_rbf: StorableVec<Txindex, bool>,
|
||||
pub txindex_to_txversion: StorableVec<Txindex, TxVersion>,
|
||||
pub addressindex_to_addresstype: IndexedVec<Addressindex, Addresstype>,
|
||||
pub addressindex_to_addresstypeindex: IndexedVec<Addressindex, Addresstypeindex>,
|
||||
pub addressindex_to_height: IndexedVec<Addressindex, Height>,
|
||||
pub emptyindex_to_height: IndexedVec<Emptyindex, Height>,
|
||||
pub height_to_blockhash: IndexedVec<Height, BlockHash>,
|
||||
pub height_to_difficulty: IndexedVec<Height, f64>,
|
||||
pub height_to_first_addressindex: IndexedVec<Height, Addressindex>,
|
||||
pub height_to_first_emptyindex: IndexedVec<Height, Emptyindex>,
|
||||
pub height_to_first_multisigindex: IndexedVec<Height, Multisigindex>,
|
||||
pub height_to_first_opreturnindex: IndexedVec<Height, Opreturnindex>,
|
||||
pub height_to_first_p2pk33index: IndexedVec<Height, P2PK33index>,
|
||||
pub height_to_first_p2pk65index: IndexedVec<Height, P2PK65index>,
|
||||
pub height_to_first_p2pkhindex: IndexedVec<Height, P2PKHindex>,
|
||||
pub height_to_first_p2shindex: IndexedVec<Height, P2SHindex>,
|
||||
pub height_to_first_p2trindex: IndexedVec<Height, P2TRindex>,
|
||||
pub height_to_first_p2wpkhindex: IndexedVec<Height, P2WPKHindex>,
|
||||
pub height_to_first_p2wshindex: IndexedVec<Height, P2WSHindex>,
|
||||
pub height_to_first_pushonlyindex: IndexedVec<Height, Pushonlyindex>,
|
||||
pub height_to_first_txindex: IndexedVec<Height, Txindex>,
|
||||
pub height_to_first_txinindex: IndexedVec<Height, Txinindex>,
|
||||
pub height_to_first_txoutindex: IndexedVec<Height, Txoutindex>,
|
||||
pub height_to_first_unknownindex: IndexedVec<Height, Unknownindex>,
|
||||
pub height_to_total_size: IndexedVec<Height, StoredUsize>,
|
||||
pub height_to_timestamp: IndexedVec<Height, Timestamp>,
|
||||
pub height_to_weight: IndexedVec<Height, Weight>,
|
||||
pub multisigindex_to_height: IndexedVec<Multisigindex, Height>,
|
||||
pub opreturnindex_to_height: IndexedVec<Opreturnindex, Height>,
|
||||
pub p2pk33index_to_height: IndexedVec<P2PK33index, Height>,
|
||||
pub p2pk33index_to_p2pk33addressbytes: IndexedVec<P2PK33index, P2PK33AddressBytes>,
|
||||
pub p2pk65index_to_height: IndexedVec<P2PK65index, Height>,
|
||||
pub p2pk65index_to_p2pk65addressbytes: IndexedVec<P2PK65index, P2PK65AddressBytes>,
|
||||
pub p2pkhindex_to_height: IndexedVec<P2PKHindex, Height>,
|
||||
pub p2pkhindex_to_p2pkhaddressbytes: IndexedVec<P2PKHindex, P2PKHAddressBytes>,
|
||||
pub p2shindex_to_height: IndexedVec<P2SHindex, Height>,
|
||||
pub p2shindex_to_p2shaddressbytes: IndexedVec<P2SHindex, P2SHAddressBytes>,
|
||||
pub p2trindex_to_height: IndexedVec<P2TRindex, Height>,
|
||||
pub p2trindex_to_p2traddressbytes: IndexedVec<P2TRindex, P2TRAddressBytes>,
|
||||
pub p2wpkhindex_to_height: IndexedVec<P2WPKHindex, Height>,
|
||||
pub p2wpkhindex_to_p2wpkhaddressbytes: IndexedVec<P2WPKHindex, P2WPKHAddressBytes>,
|
||||
pub p2wshindex_to_height: IndexedVec<P2WSHindex, Height>,
|
||||
pub p2wshindex_to_p2wshaddressbytes: IndexedVec<P2WSHindex, P2WSHAddressBytes>,
|
||||
pub pushonlyindex_to_height: IndexedVec<Pushonlyindex, Height>,
|
||||
pub txindex_to_base_size: IndexedVec<Txindex, usize>,
|
||||
pub txindex_to_first_txinindex: IndexedVec<Txindex, Txinindex>,
|
||||
pub txindex_to_first_txoutindex: IndexedVec<Txindex, Txoutindex>,
|
||||
pub txindex_to_height: IndexedVec<Txindex, Height>,
|
||||
pub txindex_to_is_explicitly_rbf: IndexedVec<Txindex, bool>,
|
||||
pub txindex_to_locktime: IndexedVec<Txindex, LockTime>,
|
||||
pub txindex_to_total_size: IndexedVec<Txindex, usize>,
|
||||
pub txindex_to_txid: IndexedVec<Txindex, Txid>,
|
||||
pub txindex_to_txversion: IndexedVec<Txindex, TxVersion>,
|
||||
pub txinindex_to_height: IndexedVec<Txinindex, Height>,
|
||||
/// If txoutindex == Txoutindex MAX then is it's coinbase
|
||||
pub txinindex_to_txoutindex: StorableVec<Txinindex, Txoutindex>,
|
||||
pub txoutindex_to_addressindex: StorableVec<Txoutindex, Addressindex>,
|
||||
pub txoutindex_to_value: StorableVec<Txoutindex, Sats>,
|
||||
pub txinindex_to_txoutindex: IndexedVec<Txinindex, Txoutindex>,
|
||||
pub txoutindex_to_addressindex: IndexedVec<Txoutindex, Addressindex>,
|
||||
pub txoutindex_to_height: IndexedVec<Txoutindex, Height>,
|
||||
pub txoutindex_to_value: IndexedVec<Txoutindex, Sats>,
|
||||
pub unknownindex_to_height: IndexedVec<Unknownindex, Height>,
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
@@ -69,219 +83,289 @@ impl Vecs {
|
||||
fs::create_dir_all(path)?;
|
||||
|
||||
Ok(Self {
|
||||
addressindex_to_addresstype: StorableVec::forced_import(
|
||||
addressindex_to_addresstype: IndexedVec::forced_import(
|
||||
&path.join("addressindex_to_addresstype"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
addressindex_to_addresstypeindex: StorableVec::forced_import(
|
||||
addressindex_to_addresstypeindex: IndexedVec::forced_import(
|
||||
&path.join("addressindex_to_addresstypeindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
addressindex_to_height: StorableVec::forced_import(
|
||||
addressindex_to_height: IndexedVec::forced_import(
|
||||
&path.join("addressindex_to_height"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_blockhash: StorableVec::forced_import(
|
||||
height_to_blockhash: IndexedVec::forced_import(
|
||||
&path.join("height_to_blockhash"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
Compressed::NO,
|
||||
)?,
|
||||
height_to_difficulty: StorableVec::forced_import(
|
||||
height_to_difficulty: IndexedVec::forced_import(
|
||||
&path.join("height_to_difficulty"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_addressindex: StorableVec::forced_import(
|
||||
height_to_first_addressindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_addressindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_emptyindex: StorableVec::forced_import(
|
||||
height_to_first_emptyindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_emptyindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_multisigindex: StorableVec::forced_import(
|
||||
height_to_first_multisigindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_multisigindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_opreturnindex: StorableVec::forced_import(
|
||||
height_to_first_opreturnindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_opreturnindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_pushonlyindex: StorableVec::forced_import(
|
||||
height_to_first_pushonlyindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_pushonlyindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_txindex: StorableVec::forced_import(
|
||||
height_to_first_txindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_txindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_txinindex: StorableVec::forced_import(
|
||||
height_to_first_txinindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_txinindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_txoutindex: StorableVec::forced_import(
|
||||
height_to_first_txoutindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_txoutindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_unknownindex: StorableVec::forced_import(
|
||||
height_to_first_unknownindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_unkownindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_p2pk33index: StorableVec::forced_import(
|
||||
height_to_first_p2pk33index: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_p2pk33index"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_p2pk65index: StorableVec::forced_import(
|
||||
height_to_first_p2pk65index: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_p2pk65index"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_p2pkhindex: StorableVec::forced_import(
|
||||
height_to_first_p2pkhindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_p2pkhindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_p2shindex: StorableVec::forced_import(
|
||||
height_to_first_p2shindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_p2shindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_p2trindex: StorableVec::forced_import(
|
||||
height_to_first_p2trindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_p2trindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_p2wpkhindex: StorableVec::forced_import(
|
||||
height_to_first_p2wpkhindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_p2wpkhindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_p2wshindex: StorableVec::forced_import(
|
||||
height_to_first_p2wshindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_p2wshindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_size: StorableVec::forced_import(
|
||||
&path.join("height_to_size"),
|
||||
Version::ONE,
|
||||
height_to_total_size: IndexedVec::forced_import(
|
||||
&path.join("height_to_total_size"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_timestamp: StorableVec::forced_import(
|
||||
height_to_timestamp: IndexedVec::forced_import(
|
||||
&path.join("height_to_timestamp"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_weight: StorableVec::forced_import(
|
||||
height_to_weight: IndexedVec::forced_import(
|
||||
&path.join("height_to_weight"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2pk33index_to_p2pk33addressbytes: StorableVec::forced_import(
|
||||
p2pk33index_to_p2pk33addressbytes: IndexedVec::forced_import(
|
||||
&path.join("p2pk33index_to_p2pk33addressbytes"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
Compressed::NO,
|
||||
)?,
|
||||
p2pk65index_to_p2pk65addressbytes: StorableVec::forced_import(
|
||||
p2pk65index_to_p2pk65addressbytes: IndexedVec::forced_import(
|
||||
&path.join("p2pk65index_to_p2pk65addressbytes"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
Compressed::NO,
|
||||
)?,
|
||||
p2pkhindex_to_p2pkhaddressbytes: StorableVec::forced_import(
|
||||
p2pkhindex_to_p2pkhaddressbytes: IndexedVec::forced_import(
|
||||
&path.join("p2pkhindex_to_p2pkhaddressbytes"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
Compressed::NO,
|
||||
)?,
|
||||
p2shindex_to_p2shaddressbytes: StorableVec::forced_import(
|
||||
p2shindex_to_p2shaddressbytes: IndexedVec::forced_import(
|
||||
&path.join("p2shindex_to_p2shaddressbytes"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
Compressed::NO,
|
||||
)?,
|
||||
p2trindex_to_p2traddressbytes: StorableVec::forced_import(
|
||||
p2trindex_to_p2traddressbytes: IndexedVec::forced_import(
|
||||
&path.join("p2trindex_to_p2traddressbytes"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
Compressed::NO,
|
||||
)?,
|
||||
p2wpkhindex_to_p2wpkhaddressbytes: StorableVec::forced_import(
|
||||
p2wpkhindex_to_p2wpkhaddressbytes: IndexedVec::forced_import(
|
||||
&path.join("p2wpkhindex_to_p2wpkhaddressbytes"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
Compressed::NO,
|
||||
)?,
|
||||
p2wshindex_to_p2wshaddressbytes: StorableVec::forced_import(
|
||||
p2wshindex_to_p2wshaddressbytes: IndexedVec::forced_import(
|
||||
&path.join("p2wshindex_to_p2wshaddressbytes"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
Compressed::NO,
|
||||
)?,
|
||||
txindex_to_first_txinindex: StorableVec::forced_import(
|
||||
txindex_to_first_txinindex: IndexedVec::forced_import(
|
||||
&path.join("txindex_to_first_txinindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_first_txoutindex: StorableVec::forced_import(
|
||||
txindex_to_first_txoutindex: IndexedVec::forced_import(
|
||||
&path.join("txindex_to_first_txoutindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
Compressed::NO,
|
||||
)?,
|
||||
txindex_to_height: StorableVec::forced_import(
|
||||
txindex_to_height: IndexedVec::forced_import(
|
||||
&path.join("txindex_to_height"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_locktime: StorableVec::forced_import(
|
||||
txindex_to_locktime: IndexedVec::forced_import(
|
||||
&path.join("txindex_to_locktime"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_txid: StorableVec::forced_import(
|
||||
txindex_to_txid: IndexedVec::forced_import(
|
||||
&path.join("txindex_to_txid"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
Compressed::NO,
|
||||
)?,
|
||||
txindex_to_base_size: StorableVec::forced_import(
|
||||
txindex_to_base_size: IndexedVec::forced_import(
|
||||
&path.join("txindex_to_base_size"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_total_size: StorableVec::forced_import(
|
||||
txindex_to_total_size: IndexedVec::forced_import(
|
||||
&path.join("txindex_to_total_size"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_is_explicitly_rbf: StorableVec::forced_import(
|
||||
txindex_to_is_explicitly_rbf: IndexedVec::forced_import(
|
||||
&path.join("txindex_to_is_explicitly_rbf"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_txversion: StorableVec::forced_import(
|
||||
txindex_to_txversion: IndexedVec::forced_import(
|
||||
&path.join("txindex_to_txversion"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txinindex_to_txoutindex: StorableVec::forced_import(
|
||||
txinindex_to_txoutindex: IndexedVec::forced_import(
|
||||
&path.join("txinindex_to_txoutindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txoutindex_to_addressindex: StorableVec::forced_import(
|
||||
txoutindex_to_addressindex: IndexedVec::forced_import(
|
||||
&path.join("txoutindex_to_addressindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txoutindex_to_value: StorableVec::forced_import(
|
||||
txoutindex_to_value: IndexedVec::forced_import(
|
||||
&path.join("txoutindex_to_value"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
emptyindex_to_height: IndexedVec::forced_import(
|
||||
&path.join("emptyindex_to_height"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
multisigindex_to_height: IndexedVec::forced_import(
|
||||
&path.join("multisigindex_to_height"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
opreturnindex_to_height: IndexedVec::forced_import(
|
||||
&path.join("opreturnindex_to_height"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
pushonlyindex_to_height: IndexedVec::forced_import(
|
||||
&path.join("pushonlyindex_to_height"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txinindex_to_height: IndexedVec::forced_import(
|
||||
&path.join("txinindex_to_height"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txoutindex_to_height: IndexedVec::forced_import(
|
||||
&path.join("txoutindex_to_height"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
unknownindex_to_height: IndexedVec::forced_import(
|
||||
&path.join("unknownindex_to_height"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2pk33index_to_height: IndexedVec::forced_import(
|
||||
&path.join("p2pk33index_to_height"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2pk65index_to_height: IndexedVec::forced_import(
|
||||
&path.join("p2pk65index_to_height"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2pkhindex_to_height: IndexedVec::forced_import(
|
||||
&path.join("p2pkhindex_to_height"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2shindex_to_height: IndexedVec::forced_import(
|
||||
&path.join("p2shindex_to_height"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2trindex_to_height: IndexedVec::forced_import(
|
||||
&path.join("p2trindex_to_height"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2wpkhindex_to_height: IndexedVec::forced_import(
|
||||
&path.join("p2wpkhindex_to_height"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2wshindex_to_height: IndexedVec::forced_import(
|
||||
&path.join("p2wshindex_to_height"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
})
|
||||
@@ -290,8 +374,25 @@ impl Vecs {
|
||||
pub fn rollback_if_needed(&mut self, starting_indexes: &Indexes) -> brk_vec::Result<()> {
|
||||
let saved_height = starting_indexes.height.decremented().unwrap_or_default();
|
||||
|
||||
// We don't want to override the starting indexes so we cut from n + 1
|
||||
let height = starting_indexes.height.incremented();
|
||||
let &Indexes {
|
||||
addressindex,
|
||||
height,
|
||||
p2pk33index,
|
||||
p2pk65index,
|
||||
p2pkhindex,
|
||||
p2shindex,
|
||||
p2trindex,
|
||||
p2wpkhindex,
|
||||
p2wshindex,
|
||||
txindex,
|
||||
txinindex,
|
||||
txoutindex,
|
||||
unknownindex,
|
||||
pushonlyindex,
|
||||
opreturnindex,
|
||||
multisigindex,
|
||||
emptyindex,
|
||||
} = starting_indexes;
|
||||
|
||||
self.height_to_first_addressindex
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
@@ -326,28 +427,11 @@ impl Vecs {
|
||||
self.height_to_first_unknownindex
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
|
||||
// Now we can cut everything that's out of date
|
||||
let &Indexes {
|
||||
addressindex,
|
||||
height,
|
||||
p2pk33index,
|
||||
p2pk65index,
|
||||
p2pkhindex,
|
||||
p2shindex,
|
||||
p2trindex,
|
||||
p2wpkhindex,
|
||||
p2wshindex,
|
||||
txindex,
|
||||
txinindex,
|
||||
txoutindex,
|
||||
..
|
||||
} = starting_indexes;
|
||||
|
||||
self.height_to_blockhash
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_difficulty
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_size
|
||||
self.height_to_total_size
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_timestamp
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
@@ -403,6 +487,35 @@ impl Vecs {
|
||||
self.txoutindex_to_value
|
||||
.truncate_if_needed(txoutindex, saved_height)?;
|
||||
|
||||
self.emptyindex_to_height
|
||||
.truncate_if_needed(emptyindex, saved_height)?;
|
||||
self.multisigindex_to_height
|
||||
.truncate_if_needed(multisigindex, saved_height)?;
|
||||
self.opreturnindex_to_height
|
||||
.truncate_if_needed(opreturnindex, saved_height)?;
|
||||
self.pushonlyindex_to_height
|
||||
.truncate_if_needed(pushonlyindex, saved_height)?;
|
||||
self.txinindex_to_height
|
||||
.truncate_if_needed(txinindex, saved_height)?;
|
||||
self.txoutindex_to_height
|
||||
.truncate_if_needed(txoutindex, saved_height)?;
|
||||
self.unknownindex_to_height
|
||||
.truncate_if_needed(unknownindex, saved_height)?;
|
||||
self.p2pk33index_to_height
|
||||
.truncate_if_needed(p2pk33index, saved_height)?;
|
||||
self.p2pk65index_to_height
|
||||
.truncate_if_needed(p2pk65index, saved_height)?;
|
||||
self.p2pkhindex_to_height
|
||||
.truncate_if_needed(p2pkhindex, saved_height)?;
|
||||
self.p2shindex_to_height
|
||||
.truncate_if_needed(p2shindex, saved_height)?;
|
||||
self.p2trindex_to_height
|
||||
.truncate_if_needed(p2trindex, saved_height)?;
|
||||
self.p2wpkhindex_to_height
|
||||
.truncate_if_needed(p2wpkhindex, saved_height)?;
|
||||
self.p2wshindex_to_height
|
||||
.truncate_if_needed(p2wshindex, saved_height)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -481,7 +594,7 @@ impl Vecs {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flush(&mut self, height: Height) -> io::Result<()> {
|
||||
pub fn flush(&mut self, height: Height) -> Result<()> {
|
||||
self.as_mut_any_vecs()
|
||||
.into_par_iter()
|
||||
.try_for_each(|vec| vec.flush(height))
|
||||
@@ -495,7 +608,7 @@ impl Vecs {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStoredVec> {
|
||||
vec![
|
||||
self.addressindex_to_addresstype.any_vec(),
|
||||
self.addressindex_to_addresstypeindex.any_vec(),
|
||||
@@ -518,7 +631,7 @@ impl Vecs {
|
||||
self.height_to_first_p2trindex.any_vec(),
|
||||
self.height_to_first_p2wpkhindex.any_vec(),
|
||||
self.height_to_first_p2wshindex.any_vec(),
|
||||
self.height_to_size.any_vec(),
|
||||
self.height_to_total_size.any_vec(),
|
||||
self.height_to_timestamp.any_vec(),
|
||||
self.height_to_weight.any_vec(),
|
||||
self.p2pk33index_to_p2pk33addressbytes.any_vec(),
|
||||
@@ -540,6 +653,20 @@ impl Vecs {
|
||||
self.txinindex_to_txoutindex.any_vec(),
|
||||
self.txoutindex_to_addressindex.any_vec(),
|
||||
self.txoutindex_to_value.any_vec(),
|
||||
self.emptyindex_to_height.any_vec(),
|
||||
self.multisigindex_to_height.any_vec(),
|
||||
self.opreturnindex_to_height.any_vec(),
|
||||
self.pushonlyindex_to_height.any_vec(),
|
||||
self.txinindex_to_height.any_vec(),
|
||||
self.txoutindex_to_height.any_vec(),
|
||||
self.unknownindex_to_height.any_vec(),
|
||||
self.p2pk33index_to_height.any_vec(),
|
||||
self.p2pk65index_to_height.any_vec(),
|
||||
self.p2pkhindex_to_height.any_vec(),
|
||||
self.p2shindex_to_height.any_vec(),
|
||||
self.p2trindex_to_height.any_vec(),
|
||||
self.p2wpkhindex_to_height.any_vec(),
|
||||
self.p2wshindex_to_height.any_vec(),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -566,7 +693,7 @@ impl Vecs {
|
||||
&mut self.height_to_first_p2trindex,
|
||||
&mut self.height_to_first_p2wpkhindex,
|
||||
&mut self.height_to_first_p2wshindex,
|
||||
&mut self.height_to_size,
|
||||
&mut self.height_to_total_size,
|
||||
&mut self.height_to_timestamp,
|
||||
&mut self.height_to_weight,
|
||||
&mut self.p2pk33index_to_p2pk33addressbytes,
|
||||
@@ -588,6 +715,20 @@ impl Vecs {
|
||||
&mut self.txinindex_to_txoutindex,
|
||||
&mut self.txoutindex_to_addressindex,
|
||||
&mut self.txoutindex_to_value,
|
||||
&mut self.emptyindex_to_height,
|
||||
&mut self.multisigindex_to_height,
|
||||
&mut self.opreturnindex_to_height,
|
||||
&mut self.pushonlyindex_to_height,
|
||||
&mut self.txinindex_to_height,
|
||||
&mut self.txoutindex_to_height,
|
||||
&mut self.unknownindex_to_height,
|
||||
&mut self.p2pk33index_to_height,
|
||||
&mut self.p2pk65index_to_height,
|
||||
&mut self.p2pkhindex_to_height,
|
||||
&mut self.p2shindex_to_height,
|
||||
&mut self.p2trindex_to_height,
|
||||
&mut self.p2wpkhindex_to_height,
|
||||
&mut self.p2wshindex_to_height,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<a href="https://deps.rs/crate/brk_logger">
|
||||
<img src="https://deps.rs/crate/brk_logger/latest/status.svg" alt="Dependency status">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cvrwpv3zEG">
|
||||
<a href="https://discord.gg/HaR3wpH3nr">
|
||||
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<a href="https://deps.rs/crate/brk_parser">
|
||||
<img src="https://deps.rs/crate/brk_parser/latest/status.svg" alt="Dependency status">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cvrwpv3zEG">
|
||||
<a href="https://discord.gg/HaR3wpH3nr">
|
||||
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
|
||||
@@ -41,23 +41,29 @@ The element returned by the iterator is a tuple which includes the:
|
||||
- Block: `Block` (from `bitcoin-rust`)
|
||||
- Block's Hash: `BlockHash` (also from `bitcoin-rust`)
|
||||
|
||||
## Example
|
||||
|
||||
`src/main.rs`
|
||||
Tested with Bitcoin Core `v25.0..=v28.1`
|
||||
|
||||
## Requirements
|
||||
|
||||
Even though it reads *blkXXXXX.dat* files, it **needs** `bitcoind` to run with the RPC server to filter out block forks.
|
||||
Even though it reads *blkXXXXX.dat* files, it **needs** `bitcoind` (with no particular parameters) to run with the RPC server to filter out forks.
|
||||
|
||||
Peak memory should be around 500MB.
|
||||
|
||||
## Comparaison
|
||||
XOR-ed blocks are supported.
|
||||
|
||||
| | [brk_parser](https://crates.io/crates/brk_parser) | [bitcoin-explorer (deprecated)](https://crates.io/crates/bitcoin-explorer) | [blocks_iterator](https://crates.io/crates/blocks_iterator) |
|
||||
## Disclaimer
|
||||
|
||||
A state of the local chain is saved in `{bitcoindir}/blocks/blk_index_to_blk_recap.json` to allow for faster starts (see benchmark below) but doesn't yet support locking. Thus, it is highly recommended to run one instance of `brk_parser` at a time.
|
||||
|
||||
## Benchmark
|
||||
|
||||
| | [brk_parser](https://crates.io/crates/brk_parser) | [bitcoin-explorer (deprecated)](https://crates.io/crates/bitcoin-explorer) | [blocks_iterator](https://crates.io/crates/blocks_iterator)* |
|
||||
| --- | --- | --- | --- |
|
||||
| Runs **with** `bitcoind` | Yes ✅ | No ❌ | Yes ✅ |
|
||||
| Runs **without** `bitcoind` | No ❌ | Yes ✅ | Yes ✅ |
|
||||
| `0..=855_000` | 4mn 10s | 4mn 45s | > 2h |
|
||||
| `800_000..=855_000` | 0mn 52s (4mn 10s if first run) | 0mn 55s | > 2h |
|
||||
|
||||
\* `blocks_iterator` is with the default config (and thus with `skip_prevout = false` which does a lot more than just iterate over blocks) so it isn't an apples to apples comparaison and the numbers are misleading. You should expect much closer times. Will update the benchmark with `skip_prevout = true` as soon as possible.
|
||||
|
||||
*Benchmarked on a Macbook Pro M3 Pro*
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<a href="https://deps.rs/crate/brk_query">
|
||||
<img src="https://deps.rs/crate/brk_query/latest/status.svg" alt="Dependency status">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cvrwpv3zEG">
|
||||
<a href="https://discord.gg/HaR3wpH3nr">
|
||||
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
|
||||
|
||||
@@ -24,10 +24,15 @@ pub enum Index {
|
||||
Decadeindex,
|
||||
Difficultyepoch,
|
||||
Halvingepoch,
|
||||
Emptyindex,
|
||||
Multisigindex,
|
||||
Opreturnindex,
|
||||
Pushonlyindex,
|
||||
Unknownindex,
|
||||
}
|
||||
|
||||
impl Index {
|
||||
pub fn all() -> [Self; 20] {
|
||||
pub fn all() -> [Self; 25] {
|
||||
[
|
||||
Self::Height,
|
||||
Self::Dateindex,
|
||||
@@ -49,6 +54,11 @@ impl Index {
|
||||
Self::Txindex,
|
||||
Self::Txinindex,
|
||||
Self::Txoutindex,
|
||||
Self::Emptyindex,
|
||||
Self::Multisigindex,
|
||||
Self::Opreturnindex,
|
||||
Self::Pushonlyindex,
|
||||
Self::Unknownindex,
|
||||
]
|
||||
}
|
||||
|
||||
@@ -75,6 +85,11 @@ impl Index {
|
||||
Self::P2TRindex => &["p2tr", "p2trindex"],
|
||||
Self::P2WPKHindex => &["p2wpkh", "p2wpkhindex"],
|
||||
Self::P2WSHindex => &["p2wsh", "p2wshindex"],
|
||||
Self::Emptyindex => &["empty", "emptyindex"],
|
||||
Self::Multisigindex => &["multisig", "multisigindex"],
|
||||
Self::Opreturnindex => &["opreturn", "opreturnindex"],
|
||||
Self::Pushonlyindex => &["pushonly", "pushonlyindex"],
|
||||
Self::Unknownindex => &["unknown", "unknownindex"],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +137,12 @@ impl TryFrom<&str> for Index {
|
||||
v if (Self::Difficultyepoch).possible_values().contains(&v) => Self::Difficultyepoch,
|
||||
v if (Self::Halvingepoch).possible_values().contains(&v) => Self::Halvingepoch,
|
||||
v if (Self::Quarterindex).possible_values().contains(&v) => Self::Quarterindex,
|
||||
v if (Self::Quarterindex).possible_values().contains(&v) => Self::Quarterindex,
|
||||
v if (Self::Emptyindex).possible_values().contains(&v) => Self::Emptyindex,
|
||||
v if (Self::Multisigindex).possible_values().contains(&v) => Self::Multisigindex,
|
||||
v if (Self::Opreturnindex).possible_values().contains(&v) => Self::Opreturnindex,
|
||||
v if (Self::Pushonlyindex).possible_values().contains(&v) => Self::Pushonlyindex,
|
||||
v if (Self::Unknownindex).possible_values().contains(&v) => Self::Unknownindex,
|
||||
_ => return Err(eyre!("Bad index")),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
use brk_computer::Computer;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::AnyStorableVec;
|
||||
use brk_vec::AnyStoredVec;
|
||||
use tabled::settings::Style;
|
||||
|
||||
mod format;
|
||||
@@ -51,7 +51,7 @@ impl<'a> Query<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn search(&self, index: Index, ids: &[&str]) -> Vec<(String, &&dyn AnyStorableVec)> {
|
||||
pub fn search(&self, index: Index, ids: &[&str]) -> Vec<(String, &&dyn AnyStoredVec)> {
|
||||
let tuples = ids
|
||||
.iter()
|
||||
.flat_map(|s| {
|
||||
@@ -86,7 +86,7 @@ impl<'a> Query<'a> {
|
||||
|
||||
pub fn format(
|
||||
&self,
|
||||
vecs: Vec<(String, &&dyn AnyStorableVec)>,
|
||||
vecs: Vec<(String, &&dyn AnyStoredVec)>,
|
||||
from: Option<i64>,
|
||||
to: Option<i64>,
|
||||
format: Option<Format>,
|
||||
@@ -94,7 +94,7 @@ impl<'a> Query<'a> {
|
||||
let mut values = vecs
|
||||
.iter()
|
||||
.map(|(_, vec)| -> brk_vec::Result<Vec<serde_json::Value>> {
|
||||
vec.collect_range_values(from, to)
|
||||
vec.collect_range_serde_json(from, to)
|
||||
})
|
||||
.collect::<brk_vec::Result<Vec<_>>>()?;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use brk_vec::AnyStorableVec;
|
||||
use brk_vec::AnyStoredVec;
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
|
||||
use super::index::Index;
|
||||
@@ -13,10 +13,11 @@ pub struct VecTrees<'a> {
|
||||
|
||||
impl<'a> VecTrees<'a> {
|
||||
// Not the most performant or type safe but only built once so that's okay
|
||||
pub fn insert(&mut self, vec: &'a dyn AnyStorableVec) {
|
||||
pub fn insert(&mut self, vec: &'a dyn AnyStoredVec) {
|
||||
let file_name = vec.file_name();
|
||||
let split = file_name.split("_to_").collect::<Vec<_>>();
|
||||
if split.len() != 2 {
|
||||
dbg!(&file_name, &split);
|
||||
panic!();
|
||||
}
|
||||
let str = vec
|
||||
@@ -87,7 +88,7 @@ impl<'a> VecTrees<'a> {
|
||||
}
|
||||
|
||||
#[derive(Default, Deref, DerefMut)]
|
||||
pub struct IndexToVec<'a>(BTreeMap<Index, &'a dyn AnyStorableVec>);
|
||||
pub struct IndexToVec<'a>(BTreeMap<Index, &'a dyn AnyStoredVec>);
|
||||
|
||||
#[derive(Default, Deref, DerefMut)]
|
||||
pub struct IdToVec<'a>(BTreeMap<String, &'a dyn AnyStorableVec>);
|
||||
pub struct IdToVec<'a>(BTreeMap<String, &'a dyn AnyStoredVec>);
|
||||
|
||||
@@ -7,7 +7,7 @@ license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
axum = "0.8.3"
|
||||
axum = { workspace = true }
|
||||
brk_computer = { workspace = true }
|
||||
brk_exit = { workspace = true }
|
||||
brk_fetcher = { workspace = true }
|
||||
@@ -21,10 +21,9 @@ color-eyre = { workspace = true }
|
||||
jiff = { workspace = true }
|
||||
log = { workspace = true }
|
||||
minreq = { workspace = true }
|
||||
oxc = { version = "0.62.0", features = ["codegen", "minifier"] }
|
||||
oxc = { version = "0.64.0", features = ["codegen", "minifier"] }
|
||||
serde = { workspace = true }
|
||||
tokio = { version = "1.44.1", features = ["full"] }
|
||||
tokio = { version = "1.44.2", features = ["full"] }
|
||||
tower-http = { version = "0.6.2", features = ["compression-full", "trace"] }
|
||||
zip = "2.6.0"
|
||||
zip = "2.6.1"
|
||||
tracing = "0.1.41"
|
||||
tracing-subscriber = "0.3.19"
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<a href="https://deps.rs/crate/brk_server">
|
||||
<img src="https://deps.rs/crate/brk_server/latest/status.svg" alt="Dependency status">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cvrwpv3zEG">
|
||||
<a href="https://discord.gg/HaR3wpH3nr">
|
||||
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
|
||||
|
||||
@@ -10,7 +10,6 @@ use brk_parser::{
|
||||
rpc::{self, RpcApi},
|
||||
};
|
||||
use brk_server::{Server, Website};
|
||||
use log::info;
|
||||
|
||||
pub fn main() -> color_eyre::Result<()> {
|
||||
color_eyre::install()?;
|
||||
@@ -60,14 +59,10 @@ pub fn main() -> color_eyre::Result<()> {
|
||||
loop {
|
||||
let block_count = rpc.get_block_count()?;
|
||||
|
||||
info!("{block_count} blocks found.");
|
||||
|
||||
let starting_indexes = indexer.index(&parser, rpc, &exit)?;
|
||||
|
||||
computer.compute(&mut indexer, starting_indexes, &exit)?;
|
||||
|
||||
info!("Waiting for new blocks...");
|
||||
|
||||
while block_count == rpc.get_block_count()? {
|
||||
sleep(Duration::from_secs(1))
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ impl DTS for Query<'static> {
|
||||
let indexes = Index::all();
|
||||
|
||||
let mut contents = "//
|
||||
// File auto-generated, any modification will be overwritten
|
||||
// File auto-generated, any modifications will be overwritten
|
||||
//\n\n"
|
||||
.to_string();
|
||||
|
||||
@@ -67,7 +67,7 @@ impl DTS for Query<'static> {
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
|
||||
contents += "\n\n return {\n";
|
||||
contents += "\n\n return /** @type {const} */ ({\n";
|
||||
|
||||
self.vec_trees
|
||||
.id_to_index_to_vec
|
||||
@@ -89,7 +89,7 @@ impl DTS for Query<'static> {
|
||||
);
|
||||
});
|
||||
|
||||
contents += " }\n";
|
||||
contents += " });\n";
|
||||
contents.push('}');
|
||||
|
||||
contents += "\n/** @typedef {ReturnType<typeof createVecIdToIndexes>} VecIdToIndexes */";
|
||||
|
||||
@@ -129,15 +129,14 @@ impl Server {
|
||||
let status = response.status();
|
||||
let uri = response.extensions().get::<Uri>().unwrap();
|
||||
match status {
|
||||
StatusCode::INTERNAL_SERVER_ERROR => {
|
||||
error!("{} {} {:?}", status.as_u16().red(), uri, latency)
|
||||
}
|
||||
StatusCode::NOT_MODIFIED => {
|
||||
info!("{} {} {:?}", status.as_u16().bright_black(), uri, latency)
|
||||
}
|
||||
StatusCode::OK => {
|
||||
info!("{} {} {:?}", status.as_u16().green(), uri, latency)
|
||||
}
|
||||
StatusCode::NOT_MODIFIED
|
||||
| StatusCode::TEMPORARY_REDIRECT
|
||||
| StatusCode::PERMANENT_REDIRECT => {
|
||||
info!("{} {} {:?}", status.as_u16().bright_black(), uri, latency)
|
||||
}
|
||||
_ => error!("{} {} {:?}", status.as_u16().red(), uri, latency),
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "brk_vec"
|
||||
description = "A very small, fast, efficient and simple storable Vec"
|
||||
description = "A push-only, truncable, compressable, saveable Vec"
|
||||
keywords = ["vec", "disk", "data"]
|
||||
categories = ["database"]
|
||||
version.workspace = true
|
||||
@@ -9,6 +9,8 @@ license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
axum = { workspace = true }
|
||||
arc-swap = "1.7.1"
|
||||
memmap2 = "0.9.5"
|
||||
rayon = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<a href="https://deps.rs/crate/brk_vec">
|
||||
<img src="https://deps.rs/crate/brk_vec/latest/status.svg" alt="Dependency status">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cvrwpv3zEG">
|
||||
<a href="https://discord.gg/HaR3wpH3nr">
|
||||
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
|
||||
@@ -39,19 +39,3 @@ A `Vec` (an array) that is stored on disk and thus which can be much larger than
|
||||
Compared to a key/value store, the data stored is raw byte interpretation of the Vec's values without any overhead which is very efficient. Additionally it uses close to no RAM when caching isn't active and up to 100 MB when it is.
|
||||
|
||||
Compression is also available and built on top [`zstd`](https://crates.io/crates/zstd) to save even more space (from 0 to 75%). The tradeoff being slower reading speeds, especially random reading speeds. This is due to the data being stored in compressed pages of 16 KB, which means that if you to read even one value in that page you have to uncompress the whole page.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
Portability will depend on the type of values.
|
||||
|
||||
Non bytes/slices types (`u8`, `u16`, ...) will be read as slice in an unsafe manner (using `std::slice::from_raw_parts`) and thus have the endianness of the system. On the other hand, `&[u8]` should be inserted as is.
|
||||
|
||||
If portability is important to you, just create a wrapper struct which has custom `get`, `push`, ... methods and does something like:
|
||||
|
||||
```rust
|
||||
impl StorableVecU64 {
|
||||
pub fn push(&mut self, value: u64) {
|
||||
self.push(&value.to_be_bytes())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use brk_vec::{Compressed, StorableVec, Version};
|
||||
use brk_vec::{Compressed, DynamicVec, GenericVec, StoredVec, Version};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let _ = fs::remove_dir_all("./vec");
|
||||
|
||||
let version = Version::ZERO;
|
||||
let compressed = Compressed::YES;
|
||||
|
||||
{
|
||||
let mut vec: StorableVec<usize, u32> =
|
||||
StorableVec::forced_import(Path::new("./vec"), Version::ONE, Compressed::YES)?;
|
||||
let mut vec: StoredVec<usize, u32> =
|
||||
StoredVec::forced_import(Path::new("./vec"), version, compressed)?;
|
||||
|
||||
(0..21_u32).for_each(|v| {
|
||||
vec.push(v);
|
||||
@@ -20,8 +23,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
|
||||
{
|
||||
let mut vec: StorableVec<usize, u32> =
|
||||
StorableVec::forced_import(Path::new("./vec"), Version::ONE, Compressed::YES)?;
|
||||
let mut vec: StoredVec<usize, u32> =
|
||||
StoredVec::forced_import(Path::new("./vec"), version, compressed)?;
|
||||
|
||||
dbg!(vec.get(0)?);
|
||||
dbg!(vec.get(0)?);
|
||||
@@ -42,10 +45,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
|
||||
{
|
||||
let mut vec: StorableVec<usize, u32> =
|
||||
StorableVec::forced_import(Path::new("./vec"), Version::ONE, Compressed::YES)?;
|
||||
let mut vec: StoredVec<usize, u32> =
|
||||
StoredVec::forced_import(Path::new("./vec"), version, compressed)?;
|
||||
|
||||
vec.enable_large_cache();
|
||||
vec.enable_large_cache_if_needed();
|
||||
|
||||
dbg!(vec.get(0)?);
|
||||
dbg!(vec.get(20)?);
|
||||
@@ -58,17 +61,17 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
dbg!(vec.get(5)?);
|
||||
dbg!(vec.get(20)?);
|
||||
|
||||
vec.iter(|(_, v)| {
|
||||
vec.iter(|(_, v, ..)| {
|
||||
dbg!(v);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
vec.iter_from(5, |(_, v)| {
|
||||
vec.iter_from(5, |(_, v, ..)| {
|
||||
dbg!(v);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
dbg!(vec.collect_range(Some(-5), None)?);
|
||||
dbg!(vec.collect_signed_range(Some(-5), None)?);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -15,13 +15,15 @@ pub enum Error {
|
||||
IO(io::Error),
|
||||
ZeroCopyError,
|
||||
IndexTooHigh,
|
||||
EmptyVec,
|
||||
IndexTooLow,
|
||||
ExpectFileToHaveIndex,
|
||||
ExpectVecToHaveIndex,
|
||||
FailedKeyTryIntoUsize,
|
||||
UnsupportedUnflushedState,
|
||||
RangeFromAfterTo,
|
||||
RangeFromAfterTo(usize, usize),
|
||||
DifferentCompressionMode,
|
||||
ToSerdeJsonValueError(serde_json::Error),
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
@@ -42,6 +44,12 @@ impl<A, B> From<zerocopy::error::SizeError<A, B>> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<serde_json::Error> for Error {
|
||||
fn from(error: serde_json::Error) -> Self {
|
||||
Self::ToSerdeJsonValueError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
@@ -66,8 +74,10 @@ impl fmt::Display for Error {
|
||||
)
|
||||
}
|
||||
Error::ZeroCopyError => write!(f, "Zero copy convert error"),
|
||||
Error::RangeFromAfterTo => write!(f, "Range, from is after to"),
|
||||
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::ToSerdeJsonValueError(error) => Debug::fmt(&error, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
mod error;
|
||||
mod value;
|
||||
mod values;
|
||||
|
||||
pub use error::*;
|
||||
pub use value::*;
|
||||
pub use values::*;
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
use std::ops::Range;
|
||||
|
||||
use memmap2::Mmap;
|
||||
use zerocopy::{Immutable, IntoBytes, KnownLayout, TryFromBytes};
|
||||
|
||||
use crate::MAX_PAGE_SIZE;
|
||||
|
||||
use super::Result;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Values<T> {
|
||||
Owned(Box<[T]>),
|
||||
Ref(Box<Mmap>),
|
||||
}
|
||||
|
||||
impl<T> Values<T> {
|
||||
const PER_PAGE: usize = MAX_PAGE_SIZE / Self::SIZE_OF_T;
|
||||
const SIZE_OF_T: usize = size_of::<T>();
|
||||
|
||||
pub fn get(&self, index: usize) -> Result<Option<&T>>
|
||||
where
|
||||
T: TryFromBytes + IntoBytes + Immutable + KnownLayout,
|
||||
{
|
||||
let index = Self::index_to_decoded_index(index);
|
||||
|
||||
Ok(match self {
|
||||
Self::Owned(a) => a.get(index),
|
||||
Self::Ref(m) => {
|
||||
let range = Self::index_to_byte_range(index);
|
||||
let source = &m[range];
|
||||
Some(T::try_ref_from_bytes(source)?)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn as_arr(&self) -> &[T] {
|
||||
match self {
|
||||
Self::Owned(a) => a,
|
||||
Self::Ref(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_mmap(&self) -> &Mmap {
|
||||
match self {
|
||||
Self::Owned(_) => unreachable!(),
|
||||
Self::Ref(m) => m,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn index_to_byte_range(index: usize) -> Range<usize> {
|
||||
let index = Self::index_to_byte_index(index) as usize;
|
||||
index..(index + Self::SIZE_OF_T)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn index_to_byte_index(index: usize) -> u64 {
|
||||
(index * Self::SIZE_OF_T) as u64
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn index_to_decoded_index(index: usize) -> usize {
|
||||
index % Self::PER_PAGE
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Box<[T]>> for Values<T> {
|
||||
fn from(value: Box<[T]>) -> Self {
|
||||
Self::Owned(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Mmap> for Values<T> {
|
||||
fn from(value: Mmap) -> Self {
|
||||
Self::Ref(Box::new(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for Values<T> {
|
||||
fn default() -> Self {
|
||||
Self::Owned(vec![].into_boxed_slice())
|
||||
}
|
||||
}
|
||||
+198
-820
File diff suppressed because it is too large
Load Diff
@@ -22,8 +22,10 @@ impl CompressedPagesMetadata {
|
||||
const PAGE_SIZE: usize = size_of::<CompressedPageMetadata>();
|
||||
|
||||
pub fn read(path: &Path) -> Result<CompressedPagesMetadata> {
|
||||
let path = path.join("pages_meta");
|
||||
|
||||
let slf = Self {
|
||||
vec: fs::read(path)
|
||||
vec: fs::read(&path)
|
||||
.unwrap_or_default()
|
||||
.chunks(Self::PAGE_SIZE)
|
||||
.map(|bytes| {
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
use std::{io, path::PathBuf};
|
||||
|
||||
use crate::{Result, StorableVec};
|
||||
|
||||
use super::{StoredIndex, StoredType};
|
||||
|
||||
pub trait AnyStorableVec: Send + Sync {
|
||||
fn file_name(&self) -> String;
|
||||
fn index_type_to_string(&self) -> &str;
|
||||
fn len(&self) -> usize;
|
||||
fn is_empty(&self) -> bool;
|
||||
fn collect_range_values(
|
||||
&self,
|
||||
from: Option<i64>,
|
||||
to: Option<i64>,
|
||||
) -> Result<Vec<serde_json::Value>>;
|
||||
fn flush(&mut self) -> io::Result<()>;
|
||||
fn path_vec(&self) -> PathBuf;
|
||||
}
|
||||
|
||||
impl<I, T> AnyStorableVec for StorableVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
fn file_name(&self) -> String {
|
||||
self.file_name()
|
||||
}
|
||||
|
||||
fn index_type_to_string(&self) -> &str {
|
||||
self.index_type_to_string()
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.is_empty()
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.flush()
|
||||
}
|
||||
|
||||
fn collect_range_values(
|
||||
&self,
|
||||
from: Option<i64>,
|
||||
to: Option<i64>,
|
||||
) -> Result<Vec<serde_json::Value>> {
|
||||
Ok(self
|
||||
.collect_range(from, to)?
|
||||
.into_iter()
|
||||
.map(|v| serde_json::to_value(v).unwrap())
|
||||
.collect::<Vec<_>>())
|
||||
}
|
||||
|
||||
fn path_vec(&self) -> PathBuf {
|
||||
self.base().path_vec()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
use std::{path::Path, sync::Arc};
|
||||
|
||||
use arc_swap::{ArcSwap, Guard};
|
||||
use memmap2::Mmap;
|
||||
|
||||
use crate::{Error, Result, Value};
|
||||
|
||||
use super::{StoredIndex, StoredType};
|
||||
|
||||
pub trait DynamicVec: Send + Sync {
|
||||
type I: StoredIndex;
|
||||
type T: StoredType;
|
||||
|
||||
#[inline]
|
||||
fn get(&self, index: Self::I) -> Result<Option<Value<Self::T>>> {
|
||||
self.get_(index.to_usize()?)
|
||||
}
|
||||
#[inline]
|
||||
fn cached_get(&mut self, index: Self::I) -> Result<Option<Value<Self::T>>> {
|
||||
self.cached_get_(index.to_usize()?)
|
||||
}
|
||||
#[inline]
|
||||
fn unwrap_cached_get(&mut self, index: Self::I) -> Option<Self::T> {
|
||||
self.cached_get(index).unwrap().map(Value::into_inner)
|
||||
}
|
||||
#[inline]
|
||||
fn double_unwrap_cached_get(&mut self, index: Self::I) -> Self::T {
|
||||
self.unwrap_cached_get(index).unwrap()
|
||||
}
|
||||
#[inline]
|
||||
fn get_(&self, index: usize) -> Result<Option<Value<Self::T>>> {
|
||||
match self.index_to_pushed_index(index) {
|
||||
Ok(index) => {
|
||||
if let Some(index) = index {
|
||||
return Ok(self.pushed().get(index).map(Value::Ref));
|
||||
}
|
||||
}
|
||||
Err(Error::IndexTooHigh) => return Ok(None),
|
||||
Err(Error::IndexTooLow) => {}
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
|
||||
Ok(self
|
||||
.get_stored_(index.to_usize()?, self.guard().as_ref().unwrap())?
|
||||
.map(Value::Owned))
|
||||
}
|
||||
fn get_stored_(&self, index: usize, mmap: &Mmap) -> Result<Option<Self::T>>;
|
||||
fn get_last(&self) -> Result<Option<Value<Self::T>>> {
|
||||
let len = self.len();
|
||||
if len == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
self.get_(len - 1)
|
||||
}
|
||||
#[inline]
|
||||
fn cached_get_(&mut self, index: usize) -> Result<Option<Value<Self::T>>> {
|
||||
match self.index_to_pushed_index(index) {
|
||||
Ok(index) => {
|
||||
if let Some(index) = index {
|
||||
return Ok(self.pushed().get(index).map(Value::Ref));
|
||||
}
|
||||
}
|
||||
Err(Error::IndexTooHigh) => return Ok(None),
|
||||
Err(Error::IndexTooLow) => {}
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
|
||||
let mmap = Arc::clone(self.guard().as_ref().unwrap());
|
||||
|
||||
Ok(self
|
||||
.cached_get_stored_(index.to_usize()?, &mmap)?
|
||||
.map(Value::Owned))
|
||||
}
|
||||
fn cached_get_stored_(&mut self, index: usize, mmap: &Mmap) -> Result<Option<Self::T>>;
|
||||
fn cached_get_last(&mut self) -> Result<Option<Value<Self::T>>> {
|
||||
let len = self.len();
|
||||
if len == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
self.cached_get_(len - 1)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn len(&self) -> usize {
|
||||
self.stored_len() + self.pushed_len()
|
||||
}
|
||||
#[inline]
|
||||
fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
fn mmap(&self) -> &ArcSwap<Mmap>;
|
||||
|
||||
fn guard(&self) -> &Option<Guard<Arc<Mmap>>>;
|
||||
fn mut_guard(&mut self) -> &mut Option<Guard<Arc<Mmap>>>;
|
||||
|
||||
fn stored_len(&self) -> usize;
|
||||
|
||||
fn pushed(&self) -> &[Self::T];
|
||||
#[inline]
|
||||
fn pushed_len(&self) -> usize {
|
||||
self.pushed().len()
|
||||
}
|
||||
fn mut_pushed(&mut self) -> &mut Vec<Self::T>;
|
||||
#[inline]
|
||||
fn push(&mut self, value: Self::T) {
|
||||
self.mut_pushed().push(value)
|
||||
}
|
||||
#[inline]
|
||||
fn index_to_pushed_index(&self, index: usize) -> Result<Option<usize>> {
|
||||
let stored_len = self.stored_len();
|
||||
|
||||
if index >= stored_len {
|
||||
let index = index - stored_len;
|
||||
if index >= self.pushed_len() {
|
||||
Err(Error::IndexTooHigh)
|
||||
} else {
|
||||
Ok(Some(index))
|
||||
}
|
||||
} else {
|
||||
Err(Error::IndexTooLow)
|
||||
}
|
||||
}
|
||||
|
||||
fn path(&self) -> &Path;
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
use std::{
|
||||
fs::{File, OpenOptions},
|
||||
io::{self, Seek, SeekFrom, Write},
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use axum::{
|
||||
Json,
|
||||
response::{IntoResponse, Response},
|
||||
};
|
||||
use memmap2::Mmap;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{Error, Result, Version};
|
||||
|
||||
use super::{DynamicVec, StoredIndex, StoredType};
|
||||
|
||||
pub trait GenericVec<I, T>: DynamicVec<I = I, T = T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
const SIZE_OF_T: usize = size_of::<Self::T>();
|
||||
|
||||
fn open_file(&self) -> io::Result<File> {
|
||||
Self::open_file_(&self.path_vec())
|
||||
}
|
||||
fn open_file_(path: &Path) -> io::Result<File> {
|
||||
OpenOptions::new()
|
||||
.read(true)
|
||||
.create(true)
|
||||
.truncate(false)
|
||||
.append(true)
|
||||
.open(path)
|
||||
}
|
||||
|
||||
fn file_set_len(&mut self, len: u64) -> Result<()> {
|
||||
let mut file = self.open_file()?;
|
||||
Self::file_set_len_(&mut file, len)?;
|
||||
self.update_mmap(file)
|
||||
}
|
||||
fn file_set_len_(file: &mut File, len: u64) -> Result<()> {
|
||||
file.set_len(len)?;
|
||||
file.seek(SeekFrom::End(0))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn file_write_all(&mut self, buf: &[u8]) -> Result<()> {
|
||||
let mut file = self.open_file()?;
|
||||
file.write_all(buf)?;
|
||||
self.update_mmap(file)
|
||||
}
|
||||
|
||||
fn file_truncate_and_write_all(&mut self, len: u64, buf: &[u8]) -> Result<()> {
|
||||
let mut file = self.open_file()?;
|
||||
Self::file_set_len_(&mut file, len)?;
|
||||
file.write_all(buf)?;
|
||||
self.update_mmap(file)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reset(&mut self) -> Result<()> {
|
||||
self.file_truncate_and_write_all(0, &[])
|
||||
}
|
||||
|
||||
fn new_mmap(file: File) -> Result<Arc<Mmap>> {
|
||||
Ok(Arc::new(unsafe { Mmap::map(&file)? }))
|
||||
}
|
||||
|
||||
fn update_mmap(&mut self, file: File) -> Result<()> {
|
||||
let mmap = Self::new_mmap(file)?;
|
||||
self.mmap().store(mmap);
|
||||
if self.guard().is_some() {
|
||||
let guard = self.mmap().load();
|
||||
self.mut_guard().replace(guard);
|
||||
} else {
|
||||
unreachable!("This function shouldn't be called in a cloned instance")
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_pushed_empty(&self) -> bool {
|
||||
self.pushed_len() == 0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn has(&self, index: Self::I) -> Result<bool> {
|
||||
Ok(self.has_(index.to_usize()?))
|
||||
}
|
||||
#[inline]
|
||||
fn has_(&self, index: usize) -> bool {
|
||||
index < self.len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn index_type_to_string(&self) -> &str {
|
||||
Self::I::to_string()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn iter<F>(&mut self, f: F) -> Result<()>
|
||||
where
|
||||
F: FnMut(
|
||||
(
|
||||
Self::I,
|
||||
Self::T,
|
||||
&mut dyn DynamicVec<I = Self::I, T = Self::T>,
|
||||
),
|
||||
) -> Result<()>,
|
||||
{
|
||||
self.iter_from(Self::I::default(), f)
|
||||
}
|
||||
|
||||
fn iter_from<F>(&mut self, index: Self::I, f: F) -> Result<()>
|
||||
where
|
||||
F: FnMut(
|
||||
(
|
||||
Self::I,
|
||||
Self::T,
|
||||
&mut dyn DynamicVec<I = Self::I, T = Self::T>,
|
||||
),
|
||||
) -> Result<()>;
|
||||
|
||||
fn flush(&mut self) -> Result<()>;
|
||||
|
||||
fn truncate_if_needed(&mut self, index: Self::I) -> Result<()>;
|
||||
|
||||
fn collect_range(&self, from: Option<usize>, to: Option<usize>) -> Result<Vec<Self::T>>;
|
||||
|
||||
#[inline]
|
||||
fn collect_inclusive_range(&self, from: I, to: I) -> Result<Vec<Self::T>> {
|
||||
self.collect_range(Some(from.to_usize()?), Some(to.to_usize()? + 1))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn i64_to_usize(i: i64, len: usize) -> usize {
|
||||
if i >= 0 {
|
||||
i as usize
|
||||
} else {
|
||||
let v = len as i64 + i;
|
||||
if v < 0 { 0 } else { v as usize }
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_signed_range(&self, from: Option<i64>, to: Option<i64>) -> Result<Vec<Self::T>> {
|
||||
let len = self.len();
|
||||
let from = from.map(|i| Self::i64_to_usize(i, len));
|
||||
let to = to.map(|i| Self::i64_to_usize(i, len));
|
||||
self.collect_range(from, to)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn collect_range_axum_json(
|
||||
&self,
|
||||
from: Option<i64>,
|
||||
to: Option<i64>,
|
||||
) -> Result<Json<Vec<Self::T>>> {
|
||||
Ok(Json(self.collect_signed_range(from, to)?))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn collect_range_serde_json(&self, from: Option<i64>, to: Option<i64>) -> Result<Vec<Value>> {
|
||||
self.collect_signed_range(from, to)?
|
||||
.into_iter()
|
||||
.map(|v| serde_json::to_value(v).map_err(Error::from))
|
||||
.collect::<Result<Vec<_>>>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn collect_range_response(&self, from: Option<i64>, to: Option<i64>) -> Result<Response> {
|
||||
Ok(self.collect_range_axum_json(from, to)?.into_response())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn path_vec(&self) -> PathBuf {
|
||||
Self::path_vec_(self.path())
|
||||
}
|
||||
#[inline]
|
||||
fn path_vec_(path: &Path) -> PathBuf {
|
||||
path.join("vec")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn path_version_(path: &Path) -> PathBuf {
|
||||
path.join("version")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn path_compressed_(path: &Path) -> PathBuf {
|
||||
path.join("compressed")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn file_name(&self) -> String {
|
||||
self.path()
|
||||
.file_name()
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
fn version(&self) -> Version;
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
mod any;
|
||||
// mod bytes;
|
||||
mod dynamic;
|
||||
mod generic;
|
||||
mod stored_index;
|
||||
mod stored_type;
|
||||
|
||||
pub use any::*;
|
||||
pub use dynamic::*;
|
||||
pub use generic::*;
|
||||
pub use stored_index::*;
|
||||
pub use stored_type::*;
|
||||
|
||||
@@ -18,6 +18,7 @@ where
|
||||
+ Send
|
||||
+ Sync,
|
||||
{
|
||||
fn unwrap_to_usize(self) -> usize;
|
||||
fn to_usize(self) -> Result<usize>;
|
||||
fn to_string<'a>() -> &'a str;
|
||||
}
|
||||
@@ -37,7 +38,12 @@ where
|
||||
+ Send
|
||||
+ Sync,
|
||||
{
|
||||
#[inline(always)]
|
||||
#[inline]
|
||||
fn unwrap_to_usize(self) -> usize {
|
||||
self.to_usize().unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn to_usize(self) -> Result<usize> {
|
||||
self.try_into().map_err(|_| Error::FailedKeyTryIntoUsize)
|
||||
}
|
||||
|
||||
@@ -5,10 +5,28 @@ use zerocopy::{Immutable, IntoBytes, KnownLayout, TryFromBytes};
|
||||
|
||||
pub trait StoredType
|
||||
where
|
||||
Self: Sized + Debug + Clone + TryFromBytes + IntoBytes + Immutable + KnownLayout + Send + Sync + Serialize,
|
||||
Self: Sized
|
||||
+ Debug
|
||||
+ Clone
|
||||
+ TryFromBytes
|
||||
+ IntoBytes
|
||||
+ Immutable
|
||||
+ KnownLayout
|
||||
+ Send
|
||||
+ Sync
|
||||
+ Serialize,
|
||||
{
|
||||
}
|
||||
impl<T> StoredType for T where
|
||||
T: Sized + Debug + Clone + TryFromBytes + IntoBytes + Immutable + KnownLayout + Send + Sync + Serialize
|
||||
T: Sized
|
||||
+ Debug
|
||||
+ Clone
|
||||
+ TryFromBytes
|
||||
+ IntoBytes
|
||||
+ Immutable
|
||||
+ KnownLayout
|
||||
+ Send
|
||||
+ Sync
|
||||
+ Serialize
|
||||
{
|
||||
}
|
||||
|
||||
@@ -0,0 +1,526 @@
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
mem,
|
||||
path::Path,
|
||||
sync::{Arc, OnceLock},
|
||||
};
|
||||
|
||||
use arc_swap::{ArcSwap, Guard};
|
||||
use memmap2::Mmap;
|
||||
use rayon::prelude::*;
|
||||
use zstd::DEFAULT_COMPRESSION_LEVEL;
|
||||
|
||||
use crate::{
|
||||
CompressedPageMetadata, CompressedPagesMetadata, DynamicVec, Error, GenericVec, RawVec, Result,
|
||||
StoredIndex, StoredType, UnsafeSlice, Version,
|
||||
};
|
||||
|
||||
const ONE_KIB: usize = 1024;
|
||||
const ONE_MIB: usize = ONE_KIB * ONE_KIB;
|
||||
pub const MAX_CACHE_SIZE: usize = 100 * ONE_MIB;
|
||||
pub const MAX_PAGE_SIZE: usize = 16 * ONE_KIB;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CompressedVec<I, T> {
|
||||
inner: RawVec<I, T>,
|
||||
decoded_page: Option<(usize, Vec<T>)>,
|
||||
decoded_pages: Option<Vec<OnceLock<Vec<T>>>>,
|
||||
pages_meta: Arc<ArcSwap<CompressedPagesMetadata>>,
|
||||
// pages: Option<Vec<OnceLock<Values<T>>>>,
|
||||
// page: Option<(usize, Values<T>)>,
|
||||
// length: Length
|
||||
}
|
||||
|
||||
impl<I, T> CompressedVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
pub const PER_PAGE: usize = MAX_PAGE_SIZE / Self::SIZE_OF_T;
|
||||
pub const PAGE_SIZE: usize = Self::PER_PAGE * Self::SIZE_OF_T;
|
||||
pub const CACHE_LENGTH: usize = MAX_CACHE_SIZE / Self::PAGE_SIZE;
|
||||
|
||||
/// Same as import but will reset the folder under certain errors, so be careful !
|
||||
pub fn forced_import(path: &Path, version: Version) -> Result<Self> {
|
||||
let res = Self::import(path, version);
|
||||
match res {
|
||||
Err(Error::WrongEndian)
|
||||
| Err(Error::DifferentVersion { .. })
|
||||
| Err(Error::DifferentCompressionMode) => {
|
||||
fs::remove_dir_all(path)?;
|
||||
Self::import(path, version)
|
||||
}
|
||||
_ => res,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn import(path: &Path, version: Version) -> Result<Self> {
|
||||
fs::create_dir_all(path)?;
|
||||
|
||||
let vec_exists = fs::exists(Self::path_vec_(path)).is_ok_and(|b| b);
|
||||
let compressed_path = Self::path_compressed_(path);
|
||||
let compressed_exists = fs::exists(&compressed_path).is_ok_and(|b| b);
|
||||
|
||||
if vec_exists && !compressed_exists {
|
||||
return Err(Error::DifferentCompressionMode);
|
||||
}
|
||||
|
||||
if !vec_exists && !compressed_exists {
|
||||
File::create(&compressed_path)?;
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
inner: RawVec::import(path, version)?,
|
||||
decoded_page: None,
|
||||
decoded_pages: None,
|
||||
pages_meta: Arc::new(ArcSwap::new(Arc::new(CompressedPagesMetadata::read(path)?))),
|
||||
})
|
||||
}
|
||||
|
||||
fn cached_get_stored__(
|
||||
index: usize,
|
||||
mmap: &Mmap,
|
||||
stored_len: usize,
|
||||
decoded_page: &mut Option<(usize, Vec<T>)>,
|
||||
compressed_pages_meta: &CompressedPagesMetadata,
|
||||
) -> Result<Option<T>> {
|
||||
let page_index = Self::index_to_page_index(index);
|
||||
|
||||
if decoded_page.as_ref().is_none_or(|b| b.0 != page_index) {
|
||||
let values = Self::decode_page_(stored_len, page_index, mmap, compressed_pages_meta)?;
|
||||
decoded_page.replace((page_index, values));
|
||||
}
|
||||
|
||||
Ok(decoded_page
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.1
|
||||
.get(index % Self::PER_PAGE)
|
||||
.cloned())
|
||||
}
|
||||
|
||||
fn decode_page(&self, page_index: usize, mmap: &Mmap) -> Result<Vec<T>> {
|
||||
Self::decode_page_(self.stored_len(), page_index, mmap, &self.pages_meta.load())
|
||||
}
|
||||
|
||||
fn decode_page_(
|
||||
stored_len: usize,
|
||||
page_index: usize,
|
||||
mmap: &Mmap,
|
||||
compressed_pages_meta: &CompressedPagesMetadata,
|
||||
) -> Result<Vec<T>> {
|
||||
if Self::page_index_to_index(page_index) >= stored_len {
|
||||
return Err(Error::IndexTooHigh);
|
||||
} else if compressed_pages_meta.len() <= page_index {
|
||||
return Err(Error::ExpectVecToHaveIndex);
|
||||
}
|
||||
|
||||
let page = compressed_pages_meta.get(page_index).unwrap();
|
||||
let len = page.bytes_len as usize;
|
||||
let offset = page.start as usize;
|
||||
|
||||
Ok(zstd::decode_all(&mmap[offset..offset + len])
|
||||
.inspect_err(|_| {
|
||||
dbg!((len, offset, page_index, &mmap[..], &mmap.len()));
|
||||
})?
|
||||
.chunks(Self::SIZE_OF_T)
|
||||
.map(|slice| T::try_read_from_bytes(slice).unwrap())
|
||||
.collect::<Vec<_>>())
|
||||
}
|
||||
|
||||
fn compress_page(chunk: &[T]) -> Vec<u8> {
|
||||
if chunk.len() > Self::PER_PAGE {
|
||||
panic!();
|
||||
}
|
||||
|
||||
let mut bytes: Vec<u8> = vec![0; chunk.len() * Self::SIZE_OF_T];
|
||||
|
||||
let unsafe_bytes = UnsafeSlice::new(&mut bytes);
|
||||
|
||||
chunk
|
||||
.into_par_iter()
|
||||
.enumerate()
|
||||
.for_each(|(i, v)| unsafe_bytes.copy_slice(i * Self::SIZE_OF_T, v.as_bytes()));
|
||||
|
||||
zstd::encode_all(bytes.as_slice(), DEFAULT_COMPRESSION_LEVEL).unwrap()
|
||||
}
|
||||
|
||||
pub fn enable_large_cache(&mut self) {
|
||||
self.decoded_pages.replace(vec![]);
|
||||
self.reset_large_cache();
|
||||
}
|
||||
|
||||
pub fn disable_large_cache(&mut self) {
|
||||
self.decoded_pages.take();
|
||||
}
|
||||
|
||||
fn reset_large_cache(&mut self) {
|
||||
let stored_len = self.stored_len();
|
||||
|
||||
if let Some(pages) = self.decoded_pages.as_mut() {
|
||||
pages.par_iter_mut().for_each(|lock| {
|
||||
lock.take();
|
||||
});
|
||||
|
||||
let len = (stored_len as f64 / Self::PER_PAGE as f64).ceil() as usize;
|
||||
let len = Self::CACHE_LENGTH.min(len);
|
||||
|
||||
if pages.len() != len {
|
||||
pages.resize_with(len, Default::default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn large_cache_len(&self) -> usize {
|
||||
self.decoded_pages.as_ref().map_or(0, |v| v.len())
|
||||
}
|
||||
|
||||
fn reset_small_cache(&mut self) {
|
||||
self.decoded_page.take();
|
||||
}
|
||||
|
||||
fn reset_caches(&mut self) {
|
||||
self.reset_small_cache();
|
||||
self.reset_large_cache();
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn index_to_page_index(index: usize) -> usize {
|
||||
index / Self::PER_PAGE
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn page_index_to_index(page_index: usize) -> usize {
|
||||
page_index * Self::PER_PAGE
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> DynamicVec for CompressedVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
type I = I;
|
||||
type T = T;
|
||||
|
||||
#[inline]
|
||||
fn get_stored_(&self, index: usize, mmap: &Mmap) -> Result<Option<T>> {
|
||||
let cached_start = self
|
||||
.stored_len()
|
||||
.checked_sub(Self::CACHE_LENGTH)
|
||||
.unwrap_or_default();
|
||||
|
||||
let decoded_index = index % Self::PER_PAGE;
|
||||
|
||||
if index >= cached_start {
|
||||
let trimmed_index = index - cached_start;
|
||||
if let Some(decoded_pages) = self.decoded_pages.as_ref() {
|
||||
let decoded_page = decoded_pages
|
||||
.get(Self::index_to_page_index(trimmed_index))
|
||||
.unwrap();
|
||||
|
||||
return Ok(decoded_page
|
||||
.get_or_init(|| {
|
||||
self.decode_page(Self::index_to_page_index(index), mmap)
|
||||
.unwrap()
|
||||
})
|
||||
.get(decoded_index)
|
||||
.cloned());
|
||||
}
|
||||
}
|
||||
|
||||
let page_index = Self::index_to_page_index(index);
|
||||
|
||||
Ok(self
|
||||
.decode_page(page_index, mmap)?
|
||||
.get(decoded_index)
|
||||
.cloned())
|
||||
}
|
||||
#[inline]
|
||||
fn cached_get_stored_(&mut self, index: usize, mmap: &Mmap) -> Result<Option<T>> {
|
||||
Self::cached_get_stored__(
|
||||
index,
|
||||
mmap,
|
||||
self.stored_len(),
|
||||
&mut self.decoded_page,
|
||||
&self.pages_meta.load(),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn mmap(&self) -> &ArcSwap<Mmap> {
|
||||
self.inner.mmap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn guard(&self) -> &Option<Guard<Arc<Mmap>>> {
|
||||
self.inner.guard()
|
||||
}
|
||||
#[inline]
|
||||
fn mut_guard(&mut self) -> &mut Option<Guard<Arc<Mmap>>> {
|
||||
self.inner.mut_guard()
|
||||
}
|
||||
|
||||
fn stored_len(&self) -> usize {
|
||||
let pages_meta = self.pages_meta.load();
|
||||
if let Some(last) = pages_meta.last() {
|
||||
(pages_meta.len() - 1) * Self::PER_PAGE + last.values_len as usize
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pushed(&self) -> &[T] {
|
||||
self.inner.pushed()
|
||||
}
|
||||
#[inline]
|
||||
fn mut_pushed(&mut self) -> &mut Vec<T> {
|
||||
self.inner.mut_pushed()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn path(&self) -> &Path {
|
||||
self.inner.path()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> GenericVec<I, T> for CompressedVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
fn iter_from<F>(&mut self, index: I, mut f: F) -> Result<()>
|
||||
where
|
||||
F: FnMut((I, T, &mut dyn DynamicVec<I = Self::I, T = Self::T>)) -> Result<()>,
|
||||
{
|
||||
if !self.is_pushed_empty() {
|
||||
return Err(Error::UnsupportedUnflushedState);
|
||||
}
|
||||
|
||||
let start = index.to_usize()?;
|
||||
|
||||
let stored_len = self.stored_len();
|
||||
if start >= stored_len {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mmap = self.mmap().load();
|
||||
let pages_meta = self.pages_meta.load();
|
||||
|
||||
(start..stored_len).try_for_each(|index| {
|
||||
let v = Self::cached_get_stored__(
|
||||
index,
|
||||
&mmap,
|
||||
stored_len,
|
||||
&mut self.decoded_page,
|
||||
&pages_meta,
|
||||
)?
|
||||
.unwrap();
|
||||
f((I::from(index), v, self as &mut dyn DynamicVec<I = I, T = T>))
|
||||
})
|
||||
}
|
||||
|
||||
fn collect_range(&self, from: Option<usize>, to: Option<usize>) -> Result<Vec<Self::T>> {
|
||||
if !self.is_pushed_empty() {
|
||||
return Err(Error::UnsupportedUnflushedState);
|
||||
}
|
||||
|
||||
let stored_len = self.stored_len();
|
||||
|
||||
let from = from.unwrap_or_default();
|
||||
let to = to.map_or(stored_len, |i| i.min(stored_len));
|
||||
|
||||
if from >= stored_len {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
|
||||
let mmap = self.mmap().load();
|
||||
let pages_meta = self.pages_meta.load();
|
||||
let mut decoded_page: Option<(usize, Vec<T>)> = None;
|
||||
|
||||
(from..to)
|
||||
.map(|index| {
|
||||
Self::cached_get_stored__(index, &mmap, stored_len, &mut decoded_page, &pages_meta)
|
||||
.map(|opt| opt.unwrap())
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> Result<()> {
|
||||
let pushed_len = self.pushed_len();
|
||||
|
||||
if pushed_len == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let stored_len = self.stored_len();
|
||||
|
||||
let mut pages_meta = (**self.pages_meta.load()).clone();
|
||||
|
||||
let mut starting_page_index = pages_meta.len();
|
||||
let mut values = vec![];
|
||||
let mut truncate_at = None;
|
||||
|
||||
if self.stored_len() % Self::PER_PAGE != 0 {
|
||||
if pages_meta.is_empty() {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
let last_page_index = pages_meta.len() - 1;
|
||||
|
||||
values = if let Some(values) = self
|
||||
.decoded_pages
|
||||
.as_mut()
|
||||
.and_then(|v| v.last_mut().and_then(|lock| lock.take()))
|
||||
{
|
||||
values
|
||||
} else if self
|
||||
.decoded_page
|
||||
.as_ref()
|
||||
.is_some_and(|(page_index, _)| *page_index == last_page_index)
|
||||
{
|
||||
self.decoded_page.take().unwrap().1
|
||||
} else {
|
||||
Self::decode_page_(
|
||||
stored_len,
|
||||
last_page_index,
|
||||
self.guard().as_ref().unwrap(),
|
||||
&pages_meta,
|
||||
)
|
||||
.inspect_err(|_| {
|
||||
dbg!(last_page_index, &pages_meta);
|
||||
})
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
truncate_at.replace(pages_meta.pop().unwrap().start);
|
||||
starting_page_index = last_page_index;
|
||||
}
|
||||
|
||||
let compressed = values
|
||||
.into_par_iter()
|
||||
.chain(mem::take(self.mut_pushed()).into_par_iter())
|
||||
.chunks(Self::PER_PAGE)
|
||||
.map(|chunk| (Self::compress_page(chunk.as_ref()), chunk.len()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
compressed
|
||||
.iter()
|
||||
.enumerate()
|
||||
.for_each(|(i, (compressed_bytes, values_len))| {
|
||||
let page_index = starting_page_index + i;
|
||||
|
||||
let start = if page_index != 0 {
|
||||
let prev = pages_meta.get(page_index - 1).unwrap();
|
||||
prev.start + prev.bytes_len as u64
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let bytes_len = compressed_bytes.len() as u32;
|
||||
let values_len = *values_len as u32;
|
||||
|
||||
let page = CompressedPageMetadata::new(start, bytes_len, values_len);
|
||||
|
||||
pages_meta.push(page_index, page);
|
||||
});
|
||||
|
||||
let buf = compressed
|
||||
.into_iter()
|
||||
.flat_map(|(v, _)| v)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
pages_meta.write()?;
|
||||
|
||||
if let Some(truncate_at) = truncate_at {
|
||||
self.file_set_len(truncate_at)?;
|
||||
}
|
||||
|
||||
self.file_write_all(&buf)?;
|
||||
|
||||
self.pages_meta.store(Arc::new(pages_meta));
|
||||
|
||||
self.reset_caches();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn reset(&mut self) -> Result<()> {
|
||||
let mut pages_meta = (**self.pages_meta.load()).clone();
|
||||
pages_meta.truncate(0);
|
||||
pages_meta.write()?;
|
||||
self.pages_meta.store(Arc::new(pages_meta));
|
||||
self.reset_caches();
|
||||
self.file_truncate_and_write_all(0, &[])
|
||||
}
|
||||
|
||||
fn truncate_if_needed(&mut self, index: I) -> Result<()> {
|
||||
let index = index.to_usize()?;
|
||||
|
||||
if index >= self.stored_len() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if index == 0 {
|
||||
self.reset()?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut pages_meta = (**self.pages_meta.load()).clone();
|
||||
|
||||
let page_index = Self::index_to_page_index(index);
|
||||
|
||||
let guard = self.guard().as_ref().unwrap();
|
||||
|
||||
let values = self.decode_page(page_index, guard)?;
|
||||
let mut buf = vec![];
|
||||
|
||||
let mut page = pages_meta.truncate(page_index).unwrap();
|
||||
|
||||
let len = page.start;
|
||||
|
||||
let decoded_index = index % Self::PER_PAGE;
|
||||
|
||||
if decoded_index != 0 {
|
||||
let chunk = &values[..decoded_index];
|
||||
|
||||
buf = Self::compress_page(chunk);
|
||||
|
||||
page.values_len = chunk.len() as u32;
|
||||
page.bytes_len = buf.len() as u32;
|
||||
|
||||
pages_meta.push(page_index, page);
|
||||
}
|
||||
|
||||
pages_meta.write()?;
|
||||
|
||||
self.pages_meta.store(Arc::new(pages_meta));
|
||||
|
||||
self.file_truncate_and_write_all(len, &buf)?;
|
||||
|
||||
self.reset_caches();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn version(&self) -> Version {
|
||||
self.inner.version()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> Clone for CompressedVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
inner: self.inner.clone(),
|
||||
decoded_page: None,
|
||||
decoded_pages: None,
|
||||
pages_meta: self.pages_meta.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
mod compressed;
|
||||
mod raw;
|
||||
|
||||
pub use compressed::*;
|
||||
pub use raw::*;
|
||||
@@ -0,0 +1,241 @@
|
||||
use std::{
|
||||
fs,
|
||||
marker::PhantomData,
|
||||
mem,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use arc_swap::{ArcSwap, Guard};
|
||||
use memmap2::Mmap;
|
||||
use rayon::prelude::*;
|
||||
|
||||
use crate::{DynamicVec, Error, GenericVec, Result, StoredIndex, StoredType, UnsafeSlice, Version};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RawVec<I, T> {
|
||||
version: Version,
|
||||
pathbuf: PathBuf,
|
||||
// Consider Arc<ArcSwap<Option<Mmap>>> for dataraces when reorg ?
|
||||
mmap: Arc<ArcSwap<Mmap>>,
|
||||
guard: Option<Guard<Arc<Mmap>>>,
|
||||
pushed: Vec<T>,
|
||||
phantom: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<I, T> RawVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
/// Same as import but will reset the folder under certain errors, so be careful !
|
||||
pub fn forced_import(path: &Path, version: Version) -> Result<Self> {
|
||||
let res = Self::import(path, version);
|
||||
match res {
|
||||
Err(Error::WrongEndian) | Err(Error::DifferentVersion { .. }) => {
|
||||
fs::remove_dir_all(path)?;
|
||||
Self::import(path, version)
|
||||
}
|
||||
_ => res,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn import(path: &Path, version: Version) -> Result<Self> {
|
||||
fs::create_dir_all(path)?;
|
||||
|
||||
let version_path = Self::path_version_(path);
|
||||
version.validate(version_path.as_ref())?;
|
||||
version.write(version_path.as_ref())?;
|
||||
|
||||
let file = Self::open_file_(Self::path_vec_(path).as_path())?;
|
||||
let mmap = Arc::new(ArcSwap::new(Self::new_mmap(file)?));
|
||||
let guard = Some(mmap.load());
|
||||
|
||||
Ok(Self {
|
||||
mmap,
|
||||
guard,
|
||||
version,
|
||||
pathbuf: path.to_owned(),
|
||||
pushed: vec![],
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> DynamicVec for RawVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
type I = I;
|
||||
type T = T;
|
||||
|
||||
#[inline]
|
||||
fn get_stored_(&self, index: usize, mmap: &Mmap) -> Result<Option<T>> {
|
||||
let index = index * Self::SIZE_OF_T;
|
||||
let slice = &mmap[index..(index + Self::SIZE_OF_T)];
|
||||
Self::T::try_read_from_bytes(slice)
|
||||
.map(|v| Some(v))
|
||||
.map_err(Error::from)
|
||||
}
|
||||
#[inline]
|
||||
fn cached_get_stored_(&mut self, index: usize, mmap: &Mmap) -> Result<Option<T>> {
|
||||
self.get_stored_(index, mmap)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn mmap(&self) -> &ArcSwap<Mmap> {
|
||||
&self.mmap
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn guard(&self) -> &Option<Guard<Arc<Mmap>>> {
|
||||
&self.guard
|
||||
}
|
||||
#[inline]
|
||||
fn mut_guard(&mut self) -> &mut Option<Guard<Arc<Mmap>>> {
|
||||
&mut self.guard
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn stored_len(&self) -> usize {
|
||||
if let Some(guard) = self.guard() {
|
||||
guard.len() / Self::SIZE_OF_T
|
||||
} else {
|
||||
self.mmap.load().len() / Self::SIZE_OF_T
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pushed(&self) -> &[T] {
|
||||
self.pushed.as_slice()
|
||||
}
|
||||
#[inline]
|
||||
fn mut_pushed(&mut self) -> &mut Vec<T> {
|
||||
&mut self.pushed
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn path(&self) -> &Path {
|
||||
self.pathbuf.as_path()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> GenericVec<I, T> for RawVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
fn iter_from<F>(&mut self, index: I, mut f: F) -> Result<()>
|
||||
where
|
||||
F: FnMut((I, T, &mut dyn DynamicVec<I = Self::I, T = Self::T>)) -> Result<()>,
|
||||
{
|
||||
if !self.is_pushed_empty() {
|
||||
return Err(Error::UnsupportedUnflushedState);
|
||||
}
|
||||
|
||||
let start = index.to_usize()?;
|
||||
|
||||
let stored_len = self.stored_len();
|
||||
if start >= stored_len {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let guard = self.mmap.load();
|
||||
|
||||
(start..stored_len).try_for_each(|index| {
|
||||
let v = self.get_stored_(index, &guard)?.unwrap();
|
||||
f((I::from(index), v, self as &mut dyn DynamicVec<I = I, T = T>))
|
||||
})
|
||||
}
|
||||
|
||||
fn collect_range(&self, from: Option<usize>, to: Option<usize>) -> Result<Vec<T>> {
|
||||
if !self.is_pushed_empty() {
|
||||
return Err(Error::UnsupportedUnflushedState);
|
||||
}
|
||||
|
||||
let stored_len = self.stored_len();
|
||||
|
||||
let from = from.unwrap_or_default();
|
||||
let to = to.map_or(stored_len, |i| i.min(stored_len));
|
||||
|
||||
if from >= stored_len {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
|
||||
let mmap = self.mmap.load();
|
||||
|
||||
(from..to)
|
||||
.map(|index| self.get_stored_(index, &mmap).map(|opt| opt.unwrap()))
|
||||
.collect::<Result<Vec<_>>>()
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> Result<()> {
|
||||
let pushed_len = self.pushed_len();
|
||||
|
||||
if pushed_len == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let bytes = {
|
||||
let pushed = &mut self.pushed;
|
||||
|
||||
let mut bytes: Vec<u8> = vec![0; pushed.len() * Self::SIZE_OF_T];
|
||||
|
||||
let unsafe_bytes = UnsafeSlice::new(&mut bytes);
|
||||
|
||||
mem::take(pushed)
|
||||
.into_par_iter()
|
||||
.enumerate()
|
||||
.for_each(|(i, v)| unsafe_bytes.copy_slice(i * Self::SIZE_OF_T, v.as_bytes()));
|
||||
|
||||
bytes
|
||||
};
|
||||
|
||||
self.file_write_all(&bytes)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn truncate_if_needed(&mut self, index: I) -> Result<()> {
|
||||
let index = index.to_usize()?;
|
||||
|
||||
if index >= self.stored_len() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if index == 0 {
|
||||
self.reset()?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let len = index * Self::SIZE_OF_T;
|
||||
|
||||
self.file_set_len(len as u64)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn version(&self) -> Version {
|
||||
self.version
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> Clone for RawVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
version: self.version,
|
||||
pathbuf: self.pathbuf.clone(),
|
||||
// Consider Arc<ArcSwap<Option<Mmap>>> for dataraces when reorg ?
|
||||
mmap: self.mmap.clone(),
|
||||
guard: None,
|
||||
pushed: vec![],
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
cargo clean
|
||||
|
||||
cargo build --all-targets
|
||||
|
||||
cd crates/brk
|
||||
|
||||
cd ../brk_core
|
||||
cargo publish
|
||||
|
||||
cd ../brk_exit
|
||||
cargo publish
|
||||
|
||||
cd ../brk_vec
|
||||
cargo publish
|
||||
|
||||
cd ../brk_logger
|
||||
cargo publish
|
||||
|
||||
cd ../brk_indexer
|
||||
cargo publish
|
||||
|
||||
cd ../brk_parser
|
||||
cargo publish
|
||||
|
||||
cd ../brk_fetcher
|
||||
cargo publish
|
||||
|
||||
cd ../brk_computer
|
||||
cargo publish
|
||||
|
||||
cd ../brk_query
|
||||
cargo publish
|
||||
|
||||
cd ../brk_server
|
||||
cargo publish
|
||||
|
||||
cd ../brk_cli
|
||||
cargo publish
|
||||
|
||||
cd ../brk
|
||||
cargo publish
|
||||
|
||||
cd ../..
|
||||
@@ -1,5 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
cargo clean
|
||||
rustup update
|
||||
cargo upgrade --incompatible
|
||||
cargo update
|
||||
cargo build --all-targets
|
||||
|
||||
@@ -877,9 +877,10 @@
|
||||
background-image: linear-gradient(
|
||||
to bottom,
|
||||
transparent,
|
||||
var(--background-color) 90%,
|
||||
var(--background-color)
|
||||
);
|
||||
height: 24rem;
|
||||
height: 21rem;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
@@ -1050,12 +1051,32 @@
|
||||
margin-left: var(--negative-main-padding);
|
||||
|
||||
fieldset {
|
||||
padding-left: var(--main-padding);
|
||||
padding-top: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
|
||||
&[data-position="nw"] {
|
||||
padding-left: var(--main-padding);
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
&[data-position="ne"] {
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
&[data-position="se"] {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
&[data-position="sw"] {
|
||||
padding-left: var(--main-padding);
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
gap: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @ts-check
|
||||
|
||||
/** @import {IChartApi, ISeriesApi, SeriesDefinition, SingleValueData as _SingleValueData, CandlestickData as _CandlestickData, BaselineData, SeriesType} from './v5.0.5-treeshaked/types' */
|
||||
/** @import {IChartApi, ISeriesApi, SeriesDefinition, SingleValueData as _SingleValueData, CandlestickData as _CandlestickData, BaselineData, SeriesType, IPaneApi, LineSeriesOptions} from './v5.0.5-treeshaked/types' */
|
||||
|
||||
/**
|
||||
* @typedef {[number, number, number, number]} OHLCTuple
|
||||
@@ -47,7 +47,7 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
|
||||
autoSize: true,
|
||||
layout: {
|
||||
fontFamily: "Geist mono",
|
||||
fontSize: 13,
|
||||
// fontSize: 13,
|
||||
background: { color: "transparent" },
|
||||
attributionLogo: false,
|
||||
colorSpace: "display-p3",
|
||||
@@ -57,9 +57,6 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
|
||||
vertLines: { visible: false },
|
||||
horzLines: { visible: false },
|
||||
},
|
||||
timeScale: {
|
||||
minBarSpacing: 2.1,
|
||||
},
|
||||
localization: {
|
||||
priceFormatter: utils.locale.numberToShortUSFormat,
|
||||
locale: "en-us",
|
||||
@@ -101,6 +98,16 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
|
||||
index === /** @satisfies {Height} */ (0) ||
|
||||
index === /** @satisfies {Difficultyepoch} */ (3) ||
|
||||
index === /** @satisfies {Halvingepoch} */ (8),
|
||||
minBarSpacing:
|
||||
index === /** @satisfies {Monthindex} */ (4)
|
||||
? 1
|
||||
: index === /** @satisfies {Quarterindex} */ (5)
|
||||
? 3
|
||||
: index === /** @satisfies {Yearindex} */ (6)
|
||||
? 12
|
||||
: index === /** @satisfies {Decadeindex} */ (7)
|
||||
? 120
|
||||
: undefined,
|
||||
},
|
||||
crosshair: {
|
||||
horzLine: {
|
||||
@@ -294,6 +301,7 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
|
||||
* @param {Accessor<CandlestickData[]>} [args.data]
|
||||
* @param {number} [args.paneIndex]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
* @param {boolean} [args.inverse]
|
||||
*/
|
||||
addCandlestickSeries({
|
||||
vecId,
|
||||
@@ -302,13 +310,14 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
|
||||
paneIndex: _paneIndex,
|
||||
defaultActive,
|
||||
data,
|
||||
inverse,
|
||||
}) {
|
||||
const paneIndex = _paneIndex ?? 0;
|
||||
|
||||
if (!ichart || !timeResource) throw Error("Chart not fully set");
|
||||
|
||||
const green = colors.green();
|
||||
const red = colors.red();
|
||||
const green = inverse ? colors.red() : colors.green();
|
||||
const red = inverse ? colors.green() : colors.red();
|
||||
const series = ichart.addSeries(
|
||||
/** @type {SeriesDefinition<'Candlestick'>} */ (lc.CandlestickSeries),
|
||||
{
|
||||
@@ -354,14 +363,11 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
|
||||
utils,
|
||||
});
|
||||
|
||||
createPriceScaleSelectorIfNeeded({
|
||||
ichart,
|
||||
this.addPriceScaleSelectorIfNeeded({
|
||||
paneIndex,
|
||||
seriesType: "Candlestick",
|
||||
signals,
|
||||
id,
|
||||
unit,
|
||||
utils,
|
||||
});
|
||||
|
||||
return series;
|
||||
@@ -375,6 +381,7 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
|
||||
* @param {Color} [args.color]
|
||||
* @param {number} [args.paneIndex]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
* @param {DeepPartial<LineStyleOptions & SeriesOptionsCommon>} [args.options]
|
||||
*/
|
||||
addLineSeries({
|
||||
vecId,
|
||||
@@ -384,12 +391,13 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
|
||||
paneIndex: _paneIndex,
|
||||
defaultActive,
|
||||
data,
|
||||
options,
|
||||
}) {
|
||||
if (!ichart || !timeResource) throw Error("Chart not fully set");
|
||||
|
||||
const paneIndex = _paneIndex ?? 0;
|
||||
|
||||
color ||= colors.orange;
|
||||
color ||= unit === "USD" ? colors.dollars : colors.bitcoin;
|
||||
|
||||
const series = ichart.addSeries(
|
||||
/** @type {SeriesDefinition<'Line'>} */ (lc.LineSeries),
|
||||
@@ -398,6 +406,7 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
|
||||
visible: defaultActive !== false,
|
||||
priceLineVisible: false,
|
||||
color: color(),
|
||||
...options,
|
||||
},
|
||||
paneIndex,
|
||||
);
|
||||
@@ -437,14 +446,11 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
|
||||
utils,
|
||||
});
|
||||
|
||||
createPriceScaleSelectorIfNeeded({
|
||||
ichart,
|
||||
this.addPriceScaleSelectorIfNeeded({
|
||||
paneIndex,
|
||||
signals,
|
||||
seriesType: "Line",
|
||||
id,
|
||||
unit,
|
||||
utils,
|
||||
});
|
||||
|
||||
return series;
|
||||
@@ -523,18 +529,99 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
|
||||
utils,
|
||||
});
|
||||
|
||||
createPriceScaleSelectorIfNeeded({
|
||||
ichart,
|
||||
this.addPriceScaleSelectorIfNeeded({
|
||||
paneIndex,
|
||||
signals,
|
||||
seriesType: "Baseline",
|
||||
id,
|
||||
unit,
|
||||
utils,
|
||||
});
|
||||
|
||||
return series;
|
||||
},
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} args.id
|
||||
* @param {SeriesType} args.seriesType
|
||||
* @param {number} args.paneIndex
|
||||
*/
|
||||
addPriceScaleSelectorIfNeeded({ unit, paneIndex, id, seriesType }) {
|
||||
id = `${id}-scale`;
|
||||
|
||||
this.addFieldsetIfNeeded({
|
||||
id,
|
||||
paneIndex,
|
||||
position: "sw",
|
||||
createChild({ owner, pane }) {
|
||||
const { field, selected } = utils.dom.createHorizontalChoiceField({
|
||||
choices: /** @type {const} */ (["lin", "log"]),
|
||||
id: utils.stringToId(`${id} ${unit}`),
|
||||
defaultValue:
|
||||
unit === "USD" && seriesType !== "Baseline" ? "log" : "lin",
|
||||
key: `${id}-price-scale-${paneIndex}`,
|
||||
signals,
|
||||
});
|
||||
|
||||
signals.runWithOwner(owner, () => {
|
||||
signals.createEffect(selected, (selected) => {
|
||||
try {
|
||||
pane.priceScale("right").applyOptions({
|
||||
mode: selected === "lin" ? 0 : 1,
|
||||
});
|
||||
} catch {}
|
||||
});
|
||||
});
|
||||
|
||||
return field;
|
||||
},
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {string} args.id
|
||||
* @param {number} args.paneIndex
|
||||
* @param {"nw" | "ne" | "se" | "sw"} args.position
|
||||
* @param {number} [args.timeout]
|
||||
* @param {(args: {owner: Owner | null, pane: IPaneApi<Time>}) => HTMLElement} args.createChild
|
||||
*/
|
||||
addFieldsetIfNeeded({ paneIndex, id, position, createChild }) {
|
||||
const owner = signals.getOwner();
|
||||
setTimeout(
|
||||
() => {
|
||||
const parent = ichart
|
||||
?.panes()
|
||||
.at(paneIndex)
|
||||
?.getHTMLElement()
|
||||
.children?.item(1)?.firstChild;
|
||||
|
||||
if (!parent) throw Error("Parent should exist");
|
||||
|
||||
if (
|
||||
Array.from(parent.childNodes).filter(
|
||||
(element) =>
|
||||
/** @type {HTMLElement} */ (element).dataset.position ===
|
||||
position,
|
||||
).length
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fieldset = window.document.createElement("fieldset");
|
||||
fieldset.dataset.size = "xs";
|
||||
fieldset.dataset.position = position;
|
||||
fieldset.id = `${id}-${paneIndex}`;
|
||||
const pane = ichart?.panes().at(paneIndex);
|
||||
if (!pane) throw Error("Expect pane");
|
||||
pane
|
||||
.getHTMLElement()
|
||||
.children?.item(1)
|
||||
?.firstChild?.appendChild(fieldset);
|
||||
|
||||
fieldset.append(createChild({ owner, pane }));
|
||||
},
|
||||
paneIndex ? 50 : 0,
|
||||
);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {Object} args
|
||||
@@ -897,106 +984,3 @@ function createPaneHeightObserver({ ichart, paneIndex, signals, utils }) {
|
||||
|
||||
callback();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {IChartApi} args.ichart
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} args.id
|
||||
* @param {SeriesType} args.seriesType
|
||||
* @param {number} args.paneIndex
|
||||
* @param {Signals} args.signals
|
||||
* @param {Utilities} args.utils
|
||||
*/
|
||||
function createPriceScaleSelectorIfNeeded({
|
||||
ichart,
|
||||
unit,
|
||||
paneIndex,
|
||||
id,
|
||||
seriesType,
|
||||
signals,
|
||||
utils,
|
||||
}) {
|
||||
const owner = signals.getOwner();
|
||||
|
||||
setTimeout(
|
||||
() => {
|
||||
const parent = ichart
|
||||
?.panes()
|
||||
.at(paneIndex)
|
||||
?.getHTMLElement()
|
||||
.children?.item(1)?.firstChild;
|
||||
|
||||
if (!parent) throw Error("Parent should exist");
|
||||
|
||||
const tagName = "fieldset";
|
||||
|
||||
if (parent.lastChild?.nodeName.toLowerCase() === tagName) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(id);
|
||||
|
||||
const choices = /**@type {const} */ (["lin", "log"]);
|
||||
|
||||
/** @typedef {(typeof choices)[number]} Choices */
|
||||
const serializedValue = signals.createSignal(
|
||||
/** @satisfies {Choices} */ (
|
||||
unit === "US Dollars" && seriesType !== "Baseline" ? "log" : "lin"
|
||||
),
|
||||
{
|
||||
save: {
|
||||
...utils.serde.string,
|
||||
keyPrefix: "",
|
||||
key: `${id}-price-scale-${paneIndex}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const field = utils.dom.createHorizontalChoiceField({
|
||||
title: unit,
|
||||
selected: serializedValue(),
|
||||
choices: choices,
|
||||
id: `${id}-${unit.replace(" ", "-")}`,
|
||||
signals,
|
||||
});
|
||||
|
||||
field.addEventListener("change", (event) => {
|
||||
// @ts-ignore
|
||||
const value = event.target.value;
|
||||
serializedValue.set(value);
|
||||
});
|
||||
|
||||
const element = window.document.createElement(tagName);
|
||||
element.dataset.size = "xs";
|
||||
element.id = `${id}-price-scale-${paneIndex}`;
|
||||
element.append(field);
|
||||
|
||||
const mode = signals.createMemo(() => {
|
||||
switch (serializedValue()) {
|
||||
case "lin":
|
||||
return 0;
|
||||
case "log":
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
|
||||
const pane = ichart?.panes().at(paneIndex);
|
||||
|
||||
if (!pane) throw Error("Expect pane");
|
||||
|
||||
signals.runWithOwner(owner, () => {
|
||||
signals.createEffect(mode, (mode) => {
|
||||
try {
|
||||
pane.priceScale("right").applyOptions({
|
||||
mode,
|
||||
});
|
||||
} catch {}
|
||||
});
|
||||
});
|
||||
|
||||
pane.getHTMLElement().children?.item(1)?.firstChild?.appendChild(element);
|
||||
},
|
||||
paneIndex ? 10 : 0,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -40,93 +40,218 @@ export function init({
|
||||
vecsResources,
|
||||
});
|
||||
|
||||
const index_ = createIndexSelector({ elements, signals, utils });
|
||||
const index = createIndexSelector({ elements, signals, utils });
|
||||
|
||||
let firstRun = true;
|
||||
|
||||
signals.createEffect(selected, (option) => {
|
||||
headingElement.innerHTML = option.title;
|
||||
signals.createEffect(index_, (index) => {
|
||||
chart.reset({ owner: signals.getOwner() });
|
||||
signals.createEffect(index, (index) => {
|
||||
const { field: topUnitField, selected: topUnit } =
|
||||
utils.dom.createHorizontalChoiceField({
|
||||
defaultValue: "USD",
|
||||
keyPrefix: "charts",
|
||||
key: "unit-0",
|
||||
choices: /** @type {const} */ ([
|
||||
/** @satisfies {Unit} */ ("USD"),
|
||||
/** @satisfies {Unit} */ ("Sats"),
|
||||
]),
|
||||
signals,
|
||||
});
|
||||
|
||||
const TIMERANGE_LS_KEY = `chart-timerange-${index}`;
|
||||
signals.createEffect(topUnit, (topUnit) => {
|
||||
const { field: seriesTypeField, selected: topSeriesType } =
|
||||
utils.dom.createHorizontalChoiceField({
|
||||
defaultValue: "Candles",
|
||||
keyPrefix: "charts",
|
||||
key: "seriestype-0",
|
||||
choices: /** @type {const} */ (["Candles", "Line"]),
|
||||
signals,
|
||||
});
|
||||
|
||||
const from = signals.createSignal(/** @type {number | null} */ (null), {
|
||||
save: {
|
||||
...utils.serde.optNumber,
|
||||
keyPrefix: TIMERANGE_LS_KEY,
|
||||
key: "from",
|
||||
serializeParam: firstRun,
|
||||
},
|
||||
});
|
||||
const to = signals.createSignal(/** @type {number | null} */ (null), {
|
||||
save: {
|
||||
...utils.serde.optNumber,
|
||||
keyPrefix: TIMERANGE_LS_KEY,
|
||||
key: "to",
|
||||
serializeParam: firstRun,
|
||||
},
|
||||
});
|
||||
|
||||
chart.create({
|
||||
index,
|
||||
timeScaleSetCallback: (unknownTimeScaleCallback) => {
|
||||
const from_ = from();
|
||||
const to_ = to();
|
||||
if (from_ !== null && to_ !== null) {
|
||||
chart.inner()?.timeScale().setVisibleLogicalRange({
|
||||
from: from_,
|
||||
to: to_,
|
||||
signals.createEffect(topSeriesType, (topSeriesType) => {
|
||||
const bottomUnits = /** @type {readonly Unit[]} */ (
|
||||
Object.keys(option.bottom)
|
||||
);
|
||||
const { field: bottomUnitField, selected: bottomUnit } =
|
||||
utils.dom.createHorizontalChoiceField({
|
||||
defaultValue: bottomUnits.at(0) || "",
|
||||
keyPrefix: "charts",
|
||||
key: "unit-1",
|
||||
choices: bottomUnits,
|
||||
signals,
|
||||
});
|
||||
} else {
|
||||
unknownTimeScaleCallback();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const candles = chart.addCandlestickSeries({
|
||||
vecId: "ohlc",
|
||||
name: "Price",
|
||||
unit: "US Dollars",
|
||||
});
|
||||
signals.createEffect(webSockets.kraken1dCandle.latest, (latest) => {
|
||||
if (!latest) return;
|
||||
const last = /** @type { CandlestickData | undefined} */ (
|
||||
candles.data().at(-1)
|
||||
);
|
||||
if (!last) return;
|
||||
candles?.update({ ...last, close: latest.close });
|
||||
});
|
||||
signals.createEffect(bottomUnit, (bottomUnit) => {
|
||||
chart.reset({ owner: signals.getOwner() });
|
||||
|
||||
[
|
||||
{ blueprints: option.top, paneIndex: 0 },
|
||||
{ blueprints: option.bottom, paneIndex: 1 },
|
||||
].forEach(({ blueprints, paneIndex }) => {
|
||||
blueprints?.forEach((blueprint) => {
|
||||
if (vecIdToIndexes[blueprint.key].includes(index)) {
|
||||
chart.addLineSeries({
|
||||
vecId: blueprint.key,
|
||||
color: blueprint.color,
|
||||
name: blueprint.title,
|
||||
unit: option.unit,
|
||||
defaultActive: blueprint.defaultActive,
|
||||
paneIndex,
|
||||
chart.addFieldsetIfNeeded({
|
||||
id: "charts-unit-0",
|
||||
paneIndex: 0,
|
||||
position: "nw",
|
||||
createChild() {
|
||||
return topUnitField;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (bottomUnits.length) {
|
||||
chart.addFieldsetIfNeeded({
|
||||
id: "charts-unit-1",
|
||||
paneIndex: 1,
|
||||
position: "nw",
|
||||
createChild() {
|
||||
return bottomUnitField;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
chart.addFieldsetIfNeeded({
|
||||
id: "charts-seriestype-0",
|
||||
paneIndex: 0,
|
||||
position: "ne",
|
||||
createChild() {
|
||||
return seriesTypeField;
|
||||
},
|
||||
});
|
||||
|
||||
const TIMERANGE_LS_KEY = `chart-timerange-${index}`;
|
||||
|
||||
const from = signals.createSignal(
|
||||
/** @type {number | null} */ (null),
|
||||
{
|
||||
save: {
|
||||
...utils.serde.optNumber,
|
||||
keyPrefix: TIMERANGE_LS_KEY,
|
||||
key: "from",
|
||||
serializeParam: firstRun,
|
||||
},
|
||||
},
|
||||
);
|
||||
const to = signals.createSignal(
|
||||
/** @type {number | null} */ (null),
|
||||
{
|
||||
save: {
|
||||
...utils.serde.optNumber,
|
||||
keyPrefix: TIMERANGE_LS_KEY,
|
||||
key: "to",
|
||||
serializeParam: firstRun,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
chart.create({
|
||||
index,
|
||||
timeScaleSetCallback: (unknownTimeScaleCallback) => {
|
||||
const from_ = from();
|
||||
const to_ = to();
|
||||
if (from_ !== null && to_ !== null) {
|
||||
chart.inner()?.timeScale().setVisibleLogicalRange({
|
||||
from: from_,
|
||||
to: to_,
|
||||
});
|
||||
} else {
|
||||
unknownTimeScaleCallback();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
switch (topUnit) {
|
||||
case "USD": {
|
||||
switch (topSeriesType) {
|
||||
case "Candles": {
|
||||
const candles = chart.addCandlestickSeries({
|
||||
vecId: "ohlc",
|
||||
name: "Price",
|
||||
unit: topUnit,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "Line": {
|
||||
const line = chart.addLineSeries({
|
||||
vecId: "close",
|
||||
name: "Price",
|
||||
unit: topUnit,
|
||||
color: colors.default,
|
||||
options: {
|
||||
priceLineVisible: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
// signals.createEffect(webSockets.kraken1dCandle.latest, (latest) => {
|
||||
// if (!latest) return;
|
||||
// const last = /** @type { CandlestickData | undefined} */ (
|
||||
// candles.data().at(-1)
|
||||
// );
|
||||
// if (!last) return;
|
||||
// candles?.update({ ...last, close: latest.close });
|
||||
// });
|
||||
break;
|
||||
}
|
||||
case "Sats": {
|
||||
switch (topSeriesType) {
|
||||
case "Candles": {
|
||||
const candles = chart.addCandlestickSeries({
|
||||
vecId: "ohlc-in-sats",
|
||||
name: "Price",
|
||||
unit: topUnit,
|
||||
inverse: true,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "Line": {
|
||||
const line = chart.addLineSeries({
|
||||
vecId: "close-in-sats",
|
||||
name: "Price",
|
||||
unit: topUnit,
|
||||
color: colors.default,
|
||||
options: {
|
||||
priceLineVisible: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[
|
||||
{ blueprints: option.top, paneIndex: 0 },
|
||||
{ blueprints: option.bottom, paneIndex: 1 },
|
||||
].forEach(({ blueprints, paneIndex }) => {
|
||||
const unit = paneIndex ? bottomUnit : topUnit;
|
||||
console.log({ unit });
|
||||
blueprints[unit]?.forEach((blueprint) => {
|
||||
const indexes = /** @type {readonly number[]} */ (
|
||||
vecIdToIndexes[blueprint.key]
|
||||
);
|
||||
if (indexes.includes(index)) {
|
||||
chart.addLineSeries({
|
||||
vecId: blueprint.key,
|
||||
color: blueprint.color,
|
||||
name: blueprint.title,
|
||||
unit,
|
||||
defaultActive: blueprint.defaultActive,
|
||||
paneIndex,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
chart
|
||||
.inner()
|
||||
?.timeScale()
|
||||
.subscribeVisibleLogicalRangeChange(
|
||||
utils.debounce((t) => {
|
||||
from.set(t.from);
|
||||
to.set(t.to);
|
||||
}),
|
||||
);
|
||||
|
||||
firstRun = false;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
chart
|
||||
.inner()
|
||||
?.timeScale()
|
||||
.subscribeVisibleLogicalRangeChange(
|
||||
utils.debounce((t) => {
|
||||
from.set(t.from);
|
||||
to.set(t.to);
|
||||
}),
|
||||
);
|
||||
|
||||
firstRun = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -138,48 +263,34 @@ export function init({
|
||||
* @param {Utilities} args.utils
|
||||
*/
|
||||
function createIndexSelector({ elements, signals, utils }) {
|
||||
const indexChoices = /**@type {const} */ ([
|
||||
"timestamp",
|
||||
"date",
|
||||
"week",
|
||||
// "difficulty epoch",
|
||||
"month",
|
||||
"quarter",
|
||||
"year",
|
||||
// "halving epoch",
|
||||
"decade",
|
||||
]);
|
||||
/** @typedef {(typeof indexChoices)[number]} SerializedIndex */
|
||||
const serializedIndex = /** @type {Signal<SerializedIndex>} */ (
|
||||
signals.createSignal("date", {
|
||||
save: {
|
||||
keyPrefix: "charts",
|
||||
key: "index",
|
||||
...utils.serde.string,
|
||||
},
|
||||
})
|
||||
);
|
||||
const indexesField = utils.dom.createHorizontalChoiceField({
|
||||
const { field, selected } = utils.dom.createHorizontalChoiceField({
|
||||
title: "Index",
|
||||
selected: serializedIndex(),
|
||||
choices: indexChoices,
|
||||
defaultValue: "date",
|
||||
keyPrefix: "charts",
|
||||
key: "index",
|
||||
choices: /**@type {const} */ ([
|
||||
"timestamp",
|
||||
"date",
|
||||
"week",
|
||||
// "difficulty epoch",
|
||||
"month",
|
||||
"quarter",
|
||||
"year",
|
||||
// "halving epoch",
|
||||
"decade",
|
||||
]),
|
||||
id: "index",
|
||||
signals,
|
||||
});
|
||||
indexesField.addEventListener("change", (event) => {
|
||||
// @ts-ignore
|
||||
const value = event.target.value;
|
||||
serializedIndex.set(value);
|
||||
});
|
||||
|
||||
const fieldset = window.document.createElement("fieldset");
|
||||
fieldset.append(indexesField);
|
||||
fieldset.append(field);
|
||||
fieldset.dataset.size = "sm";
|
||||
elements.charts.append(fieldset);
|
||||
|
||||
const index = signals.createMemo(
|
||||
/** @returns {Index} */ () => {
|
||||
switch (serializedIndex()) {
|
||||
/** @returns {ChartableIndex} */ () => {
|
||||
switch (selected()) {
|
||||
case "timestamp":
|
||||
return /** @satisfies {Height} */ (0);
|
||||
case "date":
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
// @ts-check
|
||||
|
||||
/**
|
||||
* @import { Option, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, SimulationOption, Unit, AnySeriesBlueprint } from "./options"
|
||||
* @import { Option, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, SimulationOption, Unit, AnySeriesBlueprint, ChartableIndex } from "./options"
|
||||
* @import {Valued, SingleValueData, CandlestickData, ChartData, OHLCTuple} from "../packages/lightweight-charts/wrapper"
|
||||
* @import * as _ from "../packages/ufuzzy/v1.0.14/types"
|
||||
* @import { createChart as CreateClassicChart, LineStyleOptions, DeepPartial, ChartOptions, IChartApi, IHorzScaleBehavior, WhitespaceData, ISeriesApi, Time, LineData, LogicalRange, SeriesType, BaselineStyleOptions, SeriesOptionsCommon, BaselineData, CandlestickStyleOptions } from "../packages/lightweight-charts/v5.0.5-treeshaked/types"
|
||||
* @import { SignalOptions } from "../packages/solid-signals/v0.2.4-treeshaked/types/core/core"
|
||||
* @import { getOwner as GetOwner, onCleanup as OnCleanup, Owner } from "../packages/solid-signals/v0.2.4-treeshaked/types/core/owner"
|
||||
* @import { createSignal as CreateSignal, createEffect as CreateEffect, Accessor, Setter, createMemo as CreateMemo } from "../packages/solid-signals/v0.2.4-treeshaked/types/signals";
|
||||
* @import {Signal, Signals} from "../packages/solid-signals/types";
|
||||
* @import { getOwner as GetOwner, onCleanup as OnCleanup, Owner } from "../packages/solid-signals/v0.2.4-treeshaked/types/core/owner"
|
||||
* @import { createEffect as CreateEffect, Accessor, Setter, createMemo as CreateMemo } from "../packages/solid-signals/v0.2.4-treeshaked/types/signals";
|
||||
* @import {Addressindex, Dateindex, Decadeindex, Difficultyepoch, Index, Halvingepoch, Height, Monthindex, P2PK33index, P2PK65index, P2PKHindex, P2SHindex, P2TRindex, P2WPKHindex, P2WSHindex, Txindex, Txinindex, Txoutindex, VecId, Weekindex, Yearindex, VecIdToIndexes, Quarterindex} from "./vecid-to-indexes"
|
||||
*/
|
||||
|
||||
@@ -322,40 +322,62 @@ function createUtils() {
|
||||
this.importStyle(href).addEventListener("load", callback);
|
||||
},
|
||||
/**
|
||||
* @template {Readonly<string[]>} T
|
||||
* @param {Object} args
|
||||
* @param {string | Accessor<string>} args.title
|
||||
* @param {string} args.id
|
||||
* @param {Readonly<string[]>} args.choices
|
||||
* @param {string} args.selected
|
||||
* @param {{createEffect: CreateEffect}} args.signals
|
||||
* @param {string | Accessor<string>} [args.title]
|
||||
* @param {T[number]} args.defaultValue
|
||||
* @param {string} [args.id]
|
||||
* @param {T} args.choices
|
||||
* @param {string} [args.keyPrefix]
|
||||
* @param {string} args.key
|
||||
* @param {{createEffect: CreateEffect, createSignal: Signals["createSignal"]}} args.signals
|
||||
*/
|
||||
createHorizontalChoiceField({ title, id, choices, selected, signals }) {
|
||||
createHorizontalChoiceField({
|
||||
title,
|
||||
id,
|
||||
choices,
|
||||
defaultValue,
|
||||
keyPrefix,
|
||||
key,
|
||||
signals,
|
||||
}) {
|
||||
/** @type {Signal<T[number]>} */
|
||||
const selected = signals.createSignal(defaultValue, {
|
||||
save: {
|
||||
...serde.string,
|
||||
keyPrefix: keyPrefix ?? "",
|
||||
key,
|
||||
},
|
||||
});
|
||||
|
||||
const field = window.document.createElement("div");
|
||||
field.classList.add("field");
|
||||
|
||||
const legend = window.document.createElement("legend");
|
||||
if (typeof title === "string") {
|
||||
legend.innerHTML = title;
|
||||
} else {
|
||||
signals.createEffect(title, (title) => {
|
||||
if (title) {
|
||||
const legend = window.document.createElement("legend");
|
||||
if (typeof title === "string") {
|
||||
legend.innerHTML = title;
|
||||
});
|
||||
}
|
||||
field.append(legend);
|
||||
} else {
|
||||
signals.createEffect(title, (title) => {
|
||||
legend.innerHTML = title;
|
||||
});
|
||||
}
|
||||
field.append(legend);
|
||||
|
||||
const hr = window.document.createElement("hr");
|
||||
field.append(hr);
|
||||
const hr = window.document.createElement("hr");
|
||||
field.append(hr);
|
||||
}
|
||||
|
||||
const div = window.document.createElement("div");
|
||||
field.append(div);
|
||||
|
||||
choices.forEach((choice) => {
|
||||
const inputValue = choice.toLowerCase();
|
||||
const inputValue = choice;
|
||||
const { label } = this.createLabeledInput({
|
||||
inputId: `${id}-${choice.toLowerCase()}`,
|
||||
inputName: id,
|
||||
inputId: `${id ?? key}-${choice.toLowerCase()}`,
|
||||
inputName: id ?? key,
|
||||
inputValue,
|
||||
inputChecked: inputValue === selected,
|
||||
inputChecked: inputValue === selected(),
|
||||
labelTitle: choice,
|
||||
type: "radio",
|
||||
});
|
||||
@@ -365,7 +387,13 @@ function createUtils() {
|
||||
div.append(label);
|
||||
});
|
||||
|
||||
return field;
|
||||
field.addEventListener("change", (event) => {
|
||||
// @ts-ignore
|
||||
const value = event.target.value;
|
||||
selected.set(value);
|
||||
});
|
||||
|
||||
return { field, selected };
|
||||
},
|
||||
/**
|
||||
* @param {Object} args
|
||||
@@ -436,7 +464,7 @@ function createUtils() {
|
||||
createInputDollar({ id, title, signal, signals }) {
|
||||
return this.createInputNumberElement({
|
||||
id,
|
||||
placeholder: "US Dollars",
|
||||
placeholder: "USD",
|
||||
min: 0,
|
||||
title,
|
||||
signal,
|
||||
@@ -767,13 +795,13 @@ function createUtils() {
|
||||
return numberToUSFormat(value, 0);
|
||||
} else if (absoluteValue < 1_000_000) {
|
||||
return `${numberToUSFormat(value / 1_000, 1)}K`;
|
||||
} else if (absoluteValue >= 9_000_000_000_000_000) {
|
||||
} else if (absoluteValue >= 900_000_000_000_000_000) {
|
||||
return "Inf.";
|
||||
}
|
||||
|
||||
const log = Math.floor(Math.log10(absoluteValue) - 6);
|
||||
|
||||
const suffices = ["M", "B", "T", "Q"];
|
||||
const suffices = ["M", "B", "T", "P", "E"];
|
||||
const letterIndex = Math.floor(log / 3);
|
||||
const letter = suffices[letterIndex];
|
||||
|
||||
@@ -1216,9 +1244,10 @@ function createUtils() {
|
||||
/**
|
||||
* @param {Index} index
|
||||
* @param {VecId} vecId
|
||||
* @param {number} from
|
||||
*/
|
||||
genUrl(index, vecId) {
|
||||
return `/api${genPath(index, vecId)}`;
|
||||
genUrl(index, vecId, from) {
|
||||
return `/api${genPath(index, vecId, from)}`;
|
||||
},
|
||||
/**
|
||||
* @template {number | OHLCTuple} [T=number]
|
||||
@@ -1284,8 +1313,10 @@ function createVecsResources(signals, utils) {
|
||||
let loading = false;
|
||||
let at = /** @type {Date | null} */ (null);
|
||||
|
||||
const from = -10_000;
|
||||
|
||||
return {
|
||||
url: utils.api.genUrl(index, id),
|
||||
url: utils.api.genUrl(index, id, from),
|
||||
fetched,
|
||||
async fetch() {
|
||||
if (loading) return fetched();
|
||||
@@ -1302,7 +1333,7 @@ function createVecsResources(signals, utils) {
|
||||
},
|
||||
index,
|
||||
id,
|
||||
-10_000,
|
||||
from,
|
||||
)
|
||||
);
|
||||
at = new Date();
|
||||
|
||||
+1055
-657
File diff suppressed because it is too large
Load Diff
@@ -557,7 +557,7 @@ export function init({
|
||||
utils,
|
||||
config: [
|
||||
{
|
||||
unit: "US Dollars",
|
||||
unit: "USD",
|
||||
blueprints: [
|
||||
{
|
||||
title: "Bitcoin Value",
|
||||
@@ -600,7 +600,7 @@ export function init({
|
||||
utils,
|
||||
config: [
|
||||
{
|
||||
unit: "Bitcoin",
|
||||
unit: "BTC",
|
||||
blueprints: [
|
||||
{
|
||||
title: "Bitcoin Stack",
|
||||
@@ -623,7 +623,7 @@ export function init({
|
||||
utils,
|
||||
config: [
|
||||
{
|
||||
unit: "US Dollars",
|
||||
unit: "USD",
|
||||
blueprints: [
|
||||
{
|
||||
title: "Bitcoin Price",
|
||||
@@ -652,7 +652,7 @@ export function init({
|
||||
utils,
|
||||
config: [
|
||||
{
|
||||
unit: "US Dollars",
|
||||
unit: "USD",
|
||||
blueprints: [
|
||||
{
|
||||
title: "Return Of Investment",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// File auto-generated, any modification will be overwritten
|
||||
// File auto-generated, any modifications will be overwritten
|
||||
//
|
||||
|
||||
/** @typedef {0} Height */
|
||||
@@ -22,8 +22,13 @@
|
||||
/** @typedef {17} Txindex */
|
||||
/** @typedef {18} Txinindex */
|
||||
/** @typedef {19} Txoutindex */
|
||||
/** @typedef {20} Emptyindex */
|
||||
/** @typedef {21} Multisigindex */
|
||||
/** @typedef {22} Opreturnindex */
|
||||
/** @typedef {23} Pushonlyindex */
|
||||
/** @typedef {24} Unknownindex */
|
||||
|
||||
/** @typedef {Height | Dateindex | Weekindex | Difficultyepoch | Monthindex | Quarterindex | Yearindex | Decadeindex | Halvingepoch | Addressindex | P2PK33index | P2PK65index | P2PKHindex | P2SHindex | P2TRindex | P2WPKHindex | P2WSHindex | Txindex | Txinindex | Txoutindex} Index */
|
||||
/** @typedef {Height | Dateindex | Weekindex | Difficultyepoch | Monthindex | Quarterindex | Yearindex | Decadeindex | Halvingepoch | Addressindex | P2PK33index | P2PK65index | P2PKHindex | P2SHindex | P2TRindex | P2WPKHindex | P2WSHindex | Txindex | Txinindex | Txoutindex | Emptyindex | Multisigindex | Opreturnindex | Pushonlyindex | Unknownindex} Index */
|
||||
|
||||
export function createVecIdToIndexes() {
|
||||
const Height = /** @satisfies {Height} */ (0);
|
||||
@@ -46,14 +51,19 @@ export function createVecIdToIndexes() {
|
||||
const Txindex = /** @satisfies {Txindex} */ (17);
|
||||
const Txinindex = /** @satisfies {Txinindex} */ (18);
|
||||
const Txoutindex = /** @satisfies {Txoutindex} */ (19);
|
||||
const Emptyindex = /** @satisfies {Emptyindex} */ (20);
|
||||
const Multisigindex = /** @satisfies {Multisigindex} */ (21);
|
||||
const Opreturnindex = /** @satisfies {Opreturnindex} */ (22);
|
||||
const Pushonlyindex = /** @satisfies {Pushonlyindex} */ (23);
|
||||
const Unknownindex = /** @satisfies {Unknownindex} */ (24);
|
||||
|
||||
return {
|
||||
return /** @type {const} */ ({
|
||||
addressindex: [Txoutindex],
|
||||
addresstype: [Addressindex],
|
||||
addresstypeindex: [Addressindex],
|
||||
"base-size": [Txindex],
|
||||
"block-count": [Dateindex],
|
||||
"block-interval": [Height],
|
||||
"block-count": [Height],
|
||||
"block-count-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"block-interval-10p": [Dateindex],
|
||||
"block-interval-25p": [Dateindex],
|
||||
"block-interval-75p": [Dateindex],
|
||||
@@ -62,14 +72,87 @@ export function createVecIdToIndexes() {
|
||||
"block-interval-max": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"block-interval-median": [Dateindex],
|
||||
"block-interval-min": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"block-size-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"block-vbytes-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"block-weight-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
blockhash: [Height],
|
||||
close: [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"close-in-cents": [Dateindex, Height],
|
||||
"close-in-sats": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
coinbase: [Height],
|
||||
"coinbase-10p": [Dateindex],
|
||||
"coinbase-25p": [Dateindex],
|
||||
"coinbase-75p": [Dateindex],
|
||||
"coinbase-90p": [Dateindex],
|
||||
"coinbase-average": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"coinbase-in-btc": [Height],
|
||||
"coinbase-in-btc-10p": [Dateindex],
|
||||
"coinbase-in-btc-25p": [Dateindex],
|
||||
"coinbase-in-btc-75p": [Dateindex],
|
||||
"coinbase-in-btc-90p": [Dateindex],
|
||||
"coinbase-in-btc-average": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"coinbase-in-btc-max": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"coinbase-in-btc-median": [Dateindex],
|
||||
"coinbase-in-btc-min": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"coinbase-in-btc-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"coinbase-in-usd": [Height],
|
||||
"coinbase-in-usd-10p": [Dateindex],
|
||||
"coinbase-in-usd-25p": [Dateindex],
|
||||
"coinbase-in-usd-75p": [Dateindex],
|
||||
"coinbase-in-usd-90p": [Dateindex],
|
||||
"coinbase-in-usd-average": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"coinbase-in-usd-max": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"coinbase-in-usd-median": [Dateindex],
|
||||
"coinbase-in-usd-min": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"coinbase-in-usd-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"coinbase-max": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"coinbase-median": [Dateindex],
|
||||
"coinbase-min": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"coinbase-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
date: [Dateindex],
|
||||
dateindex: [Dateindex, Height],
|
||||
decadeindex: [Yearindex, Decadeindex],
|
||||
difficulty: [Height],
|
||||
difficultyepoch: [Height, Difficultyepoch],
|
||||
fee: [Txindex],
|
||||
"fee-10p": [Height],
|
||||
"fee-25p": [Height],
|
||||
"fee-75p": [Height],
|
||||
"fee-90p": [Height],
|
||||
"fee-average": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"fee-in-btc": [Txindex],
|
||||
"fee-in-btc-10p": [Height],
|
||||
"fee-in-btc-25p": [Height],
|
||||
"fee-in-btc-75p": [Height],
|
||||
"fee-in-btc-90p": [Height],
|
||||
"fee-in-btc-average": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"fee-in-btc-max": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"fee-in-btc-median": [Height],
|
||||
"fee-in-btc-min": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"fee-in-btc-sum": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"fee-in-usd": [Txindex],
|
||||
"fee-in-usd-10p": [Height],
|
||||
"fee-in-usd-25p": [Height],
|
||||
"fee-in-usd-75p": [Height],
|
||||
"fee-in-usd-90p": [Height],
|
||||
"fee-in-usd-average": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"fee-in-usd-max": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"fee-in-usd-median": [Height],
|
||||
"fee-in-usd-min": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"fee-in-usd-sum": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"fee-max": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"fee-median": [Height],
|
||||
"fee-min": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"fee-sum": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
feerate: [Txindex],
|
||||
"feerate-10p": [Height],
|
||||
"feerate-25p": [Height],
|
||||
"feerate-75p": [Height],
|
||||
"feerate-90p": [Height],
|
||||
"feerate-average": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"feerate-max": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"feerate-median": [Height],
|
||||
"feerate-min": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"first-addressindex": [Height],
|
||||
"first-dateindex": [Weekindex, Monthindex],
|
||||
"first-emptyindex": [Height],
|
||||
@@ -93,10 +176,24 @@ export function createVecIdToIndexes() {
|
||||
"fixed-date": [Height],
|
||||
"fixed-timestamp": [Height],
|
||||
halvingepoch: [Height, Halvingepoch],
|
||||
height: [Addressindex, Height, Txindex],
|
||||
height: [Addressindex, Height, P2PK33index, P2PK65index, P2PKHindex, P2SHindex, P2TRindex, P2WPKHindex, P2WSHindex, Txindex, Txinindex, Txoutindex, Emptyindex, Multisigindex, Opreturnindex, Pushonlyindex, Unknownindex],
|
||||
high: [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"high-in-cents": [Dateindex, Height],
|
||||
"inputs-count": [Txindex],
|
||||
"high-in-sats": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"input-count": [Txindex],
|
||||
"input-count-10p": [Height],
|
||||
"input-count-25p": [Height],
|
||||
"input-count-75p": [Height],
|
||||
"input-count-90p": [Height],
|
||||
"input-count-average": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"input-count-max": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"input-count-median": [Height],
|
||||
"input-count-min": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"input-count-sum": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"input-value": [Txindex],
|
||||
"input-value-average": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"input-value-sum": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
interval: [Height],
|
||||
"is-coinbase": [Txindex],
|
||||
"is-explicitly-rbf": [Txindex],
|
||||
"last-dateindex": [Weekindex, Monthindex],
|
||||
@@ -109,12 +206,27 @@ export function createVecIdToIndexes() {
|
||||
locktime: [Txindex],
|
||||
low: [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"low-in-cents": [Dateindex, Height],
|
||||
"low-in-sats": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
monthindex: [Dateindex, Monthindex],
|
||||
ohlc: [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"ohlc-in-cents": [Dateindex, Height],
|
||||
"ohlc-in-sats": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
open: [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"open-in-cents": [Dateindex, Height],
|
||||
"outputs-count": [Txindex],
|
||||
"open-in-sats": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"output-count": [Txindex],
|
||||
"output-count-10p": [Height],
|
||||
"output-count-25p": [Height],
|
||||
"output-count-75p": [Height],
|
||||
"output-count-90p": [Height],
|
||||
"output-count-average": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"output-count-max": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"output-count-median": [Height],
|
||||
"output-count-min": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"output-count-sum": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"output-value": [Txindex],
|
||||
"output-value-average": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"output-value-sum": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
p2pk33addressbytes: [P2PK33index],
|
||||
p2pk65addressbytes: [P2PK65index],
|
||||
p2pkhaddressbytes: [P2PKHindex],
|
||||
@@ -124,19 +236,101 @@ export function createVecIdToIndexes() {
|
||||
p2wshaddressbytes: [P2WSHindex],
|
||||
quarterindex: [Monthindex, Quarterindex],
|
||||
"real-date": [Height],
|
||||
"sats-per-dollar": [Dateindex, Height],
|
||||
size: [Height],
|
||||
subsidy: [Height],
|
||||
"subsidy-10p": [Dateindex],
|
||||
"subsidy-25p": [Dateindex],
|
||||
"subsidy-75p": [Dateindex],
|
||||
"subsidy-90p": [Dateindex],
|
||||
"subsidy-average": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"subsidy-in-btc": [Height],
|
||||
"subsidy-in-btc-10p": [Dateindex],
|
||||
"subsidy-in-btc-25p": [Dateindex],
|
||||
"subsidy-in-btc-75p": [Dateindex],
|
||||
"subsidy-in-btc-90p": [Dateindex],
|
||||
"subsidy-in-btc-average": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"subsidy-in-btc-max": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"subsidy-in-btc-median": [Dateindex],
|
||||
"subsidy-in-btc-min": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"subsidy-in-btc-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"subsidy-in-usd": [Height],
|
||||
"subsidy-in-usd-10p": [Dateindex],
|
||||
"subsidy-in-usd-25p": [Dateindex],
|
||||
"subsidy-in-usd-75p": [Dateindex],
|
||||
"subsidy-in-usd-90p": [Dateindex],
|
||||
"subsidy-in-usd-average": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"subsidy-in-usd-max": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"subsidy-in-usd-median": [Dateindex],
|
||||
"subsidy-in-usd-min": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"subsidy-in-usd-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"subsidy-max": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"subsidy-median": [Dateindex],
|
||||
"subsidy-min": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"subsidy-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
timestamp: [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch, Halvingepoch],
|
||||
"total-block-count": [Dateindex],
|
||||
"total-size": [Txindex],
|
||||
"total-block-count": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"total-block-size": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"total-block-vbytes": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"total-block-weight": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"total-coinbase": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"total-coinbase-in-btc": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"total-coinbase-in-usd": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"total-fee": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"total-fee-in-btc": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"total-fee-in-usd": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"total-input-count": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"total-input-value": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"total-output-count": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"total-output-value": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"total-size": [Height, Txindex],
|
||||
"total-subsidy": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"total-subsidy-in-btc": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"total-subsidy-in-usd": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"total-tx-count": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"total-tx-v1": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"total-tx-v2": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"total-tx-v3": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"tx-count": [Height],
|
||||
"tx-count-10p": [Dateindex],
|
||||
"tx-count-25p": [Dateindex],
|
||||
"tx-count-75p": [Dateindex],
|
||||
"tx-count-90p": [Dateindex],
|
||||
"tx-count-average": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"tx-count-max": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"tx-count-median": [Dateindex],
|
||||
"tx-count-min": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"tx-count-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"tx-v1": [Height],
|
||||
"tx-v1-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"tx-v2": [Height],
|
||||
"tx-v2-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"tx-v3": [Height],
|
||||
"tx-v3-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"tx-vsize-10p": [Height],
|
||||
"tx-vsize-25p": [Height],
|
||||
"tx-vsize-75p": [Height],
|
||||
"tx-vsize-90p": [Height],
|
||||
"tx-vsize-average": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"tx-vsize-max": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"tx-vsize-median": [Height],
|
||||
"tx-vsize-min": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"tx-weight-10p": [Height],
|
||||
"tx-weight-25p": [Height],
|
||||
"tx-weight-75p": [Height],
|
||||
"tx-weight-90p": [Height],
|
||||
"tx-weight-average": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"tx-weight-max": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
"tx-weight-median": [Height],
|
||||
"tx-weight-min": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
|
||||
txid: [Txindex],
|
||||
txoutindex: [Txinindex],
|
||||
txversion: [Txindex],
|
||||
value: [Txoutindex],
|
||||
value: [Txinindex, Txoutindex],
|
||||
vbytes: [Height],
|
||||
vsize: [Txindex],
|
||||
weekindex: [Dateindex, Weekindex],
|
||||
weight: [Height],
|
||||
weight: [Height, Txindex],
|
||||
yearindex: [Monthindex, Yearindex],
|
||||
}
|
||||
});
|
||||
}
|
||||
/** @typedef {ReturnType<typeof createVecIdToIndexes>} VecIdToIndexes */
|
||||
/** @typedef {keyof VecIdToIndexes} VecId */
|
||||
|
||||
Reference in New Issue
Block a user