mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-22 12:23:04 -07:00
Compare commits
87 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6fb6abcbe5 | |||
| dc449dafd1 | |||
| ecdaeebbfb | |||
| fa958b59bd | |||
| fb3d8521cd | |||
| 608c401cf3 | |||
| 1c3da90a24 | |||
| 34567f3375 | |||
| 51bcbeb48f | |||
| cc0f9c42df | |||
| a11bf5523b | |||
| 1921c3d901 | |||
| d568469e8b | |||
| 20d5c7e8d5 | |||
| 9f289ed9de | |||
| 93ee5e480b | |||
| 98a312701f | |||
| cbcf603b63 | |||
| f976f672cf | |||
| cfc3081e8a | |||
| 99818924ee | |||
| 9bbf3a027f | |||
| 93e01902e3 | |||
| 34919aba05 | |||
| a8ee4cf57f | |||
| b39548b4c6 | |||
| 4217c22ff6 | |||
| 4ab10670c9 | |||
| 2883f88de6 | |||
| e002a61a19 | |||
| 5893376279 | |||
| 411c5e4c4d | |||
| c2a77072d2 | |||
| c8a25934a6 | |||
| 7b38355cd4 | |||
| ddc54e0b98 | |||
| 8a7003782b | |||
| 8e6464dacb | |||
| 92b1dc0afb | |||
| 7562f51e07 | |||
| 09bba99e68 | |||
| 9d674cd49b | |||
| 88a0c9ea03 | |||
| 5014e0ce3e | |||
| b7a1ee9ebc | |||
| 292ceddd66 | |||
| 4b52b80000 | |||
| 9f20664c6e | |||
| 851a6aac0e | |||
| 1f1e73c47a | |||
| 112f61ca18 | |||
| 96eeacbe2b | |||
| 3f62da879c | |||
| aa30feb875 | |||
| 9ba3c2b7c5 | |||
| 320c708e10 | |||
| efa7294f59 | |||
| ae0e092935 | |||
| c77aecbfce | |||
| 700352ec45 | |||
| 664b125ce2 | |||
| 5f4b1c9e32 | |||
| d11d3f19bd | |||
| f34f4f2738 | |||
| 15db7c2310 | |||
| f9257ed04d | |||
| 15e6ef8488 | |||
| 9ae0a57f22 | |||
| 1e38c21f8e | |||
| bdc3c19163 | |||
| d55478da54 | |||
| 82bcc55645 | |||
| 07618ebe43 | |||
| 1492834d1e | |||
| 5ab6197356 | |||
| 0a789fe551 | |||
| caa8ff23ed | |||
| ee30d1d36d | |||
| 0d9415db9d | |||
| 8020e1126f | |||
| 3439422057 | |||
| 68d2bf736f | |||
| d78c39fd8c | |||
| b1dcad86b4 | |||
| 9b6124074d | |||
| 02cbaa1e80 | |||
| a12f1321c7 |
@@ -39,11 +39,10 @@ permissions:
|
||||
# If there's a prerelease-style suffix to the version, then the release(s)
|
||||
# will be marked as a prerelease.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
push:
|
||||
tags:
|
||||
- "**[0-9]+.[0-9]+.[0-9]+*"
|
||||
- '**[0-9]+.[0-9]+.[0-9]+*'
|
||||
|
||||
jobs:
|
||||
# Run 'dist plan' (or host) to determine what tasks we need to do
|
||||
|
||||
+1
-21
@@ -8,31 +8,11 @@ target
|
||||
*\ copy*
|
||||
|
||||
# Ignored
|
||||
/_*
|
||||
_*
|
||||
|
||||
# Editors
|
||||
.vscode
|
||||
.zed
|
||||
|
||||
# Flamegraph
|
||||
flamegraph/
|
||||
flamegraph.svg
|
||||
|
||||
# Benchmarks
|
||||
benches
|
||||
|
||||
# Snapshots
|
||||
snapshots*/
|
||||
|
||||
# Docker
|
||||
docker/kibo
|
||||
|
||||
# Types
|
||||
paths.d.ts
|
||||
|
||||
# Outputs
|
||||
_outputs
|
||||
|
||||
|
||||
# Logs
|
||||
.log
|
||||
|
||||
+2
-31
@@ -3,38 +3,9 @@
|
||||

|
||||
-->
|
||||
|
||||
# v0.6.0 | WIP | A new beginning
|
||||
# v0.X.0 | WIP | A new beginning
|
||||
|
||||
## Global
|
||||
|
||||
- Completely redesign the back-end
|
||||
|
||||
- Merged parser and server crates into a single project (and thus executable), so now both will run at the same time with a single `cargo run -r` [#7392982](https://github.com/kibo-money/kibo/commit/7392982824c2db94bcd57251fd41986117c29a23)
|
||||
- Added `--no-server` and `--no-parser` to disable each if needed
|
||||
- Improved executable parameters
|
||||
- Started using `log` and `env_logger` crates instead of custom code [#7392982](https://github.com/kibo-money/kibo/commit/7392982824c2db94bcd57251fd41986117c29a23)
|
||||
- Improved logs
|
||||
- Fixed input being unfocused right after being focused in Brave browser [#9a9ae61](https://github.com/kibo-money/kibo/commit/9a9ae614d07b54c08b7e9c0e2aefe3b52fdb93c5)
|
||||
|
||||
- Reworked server's API code [#6ab0f46]( https://github.com/kibo-money/kibo/commit/6ab0f463119a902a1b7ca9691b54f61543bb8f2f)
|
||||
- New route format: `/api/date-to-realized-price` is now `/api/realized-price?kind=date`
|
||||
- Added status and timing to logs
|
||||
- Updated website packages
|
||||
- Added API support for datasets by timestamp (by merging any dataset by height with the height to timestamp dataset and so it still uses heights as chunk ids) [#ca00f3f](https://github.com/kibo-money/kibo/commit/ca00f3f71526f0c5c16021024fec7e5c6e47221c)
|
||||
- `/api/realized-price?kind=t`
|
||||
- `/api/realized-price?kind=timestamp&chunk=860000`
|
||||
- Created separate crate for indexing called `bindex`
|
||||
- Created a crate a storage engine specialized in storing datasets that have indexes as keys and thus can be represented by an array/vec called `storable-vec`
|
||||
- Removed the need for the `-txindex=1` parameter when starting your Bitcoin Core node as kibo has its own indexes now
|
||||
|
||||
## Git
|
||||
|
||||
Added git tags for each version though Markdown won't display formatted on Github so left the default text
|
||||
|
||||
## Deprecated
|
||||
|
||||
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.
|
||||
Full rewrite
|
||||
|
||||
# [kibo-v0.5.0](https://github.com/kibo-money/kibo/tree/eea56d394bf92c62c81da8b78b8c47ea730683f5) | [873199](https://mempool.space/block/0000000000000000000270925aa6a565be92e13164565a3f7994ca1966e48050) - 2024/12/04
|
||||
|
||||
|
||||
Generated
+381
-336
File diff suppressed because it is too large
Load Diff
+29
-17
@@ -4,7 +4,8 @@ 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.25"
|
||||
package.version = "0.0.44"
|
||||
package.homepage = "https://bitcoinresearchkit.org"
|
||||
package.repository = "https://github.com/bitcoinresearchkit/brk"
|
||||
|
||||
[profile.release]
|
||||
@@ -16,8 +17,10 @@ panic = "abort"
|
||||
inherits = "release"
|
||||
|
||||
[workspace.dependencies]
|
||||
axum = "0.8.3"
|
||||
bitcoin = { version = "0.32.5", features = ["serde"] }
|
||||
arc-swap = "1.7.1"
|
||||
axum = "0.8.4"
|
||||
bincode = { version = "2.0.1", features = ["serde"] }
|
||||
bitcoin = { version = "0.32.6", features = ["serde"] }
|
||||
bitcoincore-rpc = "0.19.0"
|
||||
brk_cli = { version = "0", path = "crates/brk_cli" }
|
||||
brk_computer = { version = "0", path = "crates/brk_computer" }
|
||||
@@ -29,20 +32,27 @@ brk_logger = { version = "0", path = "crates/brk_logger" }
|
||||
brk_parser = { version = "0", path = "crates/brk_parser" }
|
||||
brk_query = { version = "0", path = "crates/brk_query" }
|
||||
brk_server = { version = "0", path = "crates/brk_server" }
|
||||
brk_state = { version = "0", path = "crates/brk_state" }
|
||||
brk_store = { version = "0", path = "crates/brk_store" }
|
||||
brk_vec = { version = "0", path = "crates/brk_vec" }
|
||||
byteview = "0.6.1"
|
||||
clap = { version = "4.5.36", features = ["derive", "string"] }
|
||||
color-eyre = "0.6.3"
|
||||
byteview = "=0.6.1"
|
||||
clap = { version = "4.5.39", features = ["string"] }
|
||||
clap_derive = "4.5.32"
|
||||
color-eyre = "0.6.5"
|
||||
derive_deref = "1.1.1"
|
||||
fjall = "2.8.0"
|
||||
jiff = "0.2.8"
|
||||
fjall = "2.11.0"
|
||||
jiff = "0.2.14"
|
||||
log = { version = "0.4.27" }
|
||||
minreq = { version = "2.13.4", features = ["https", "serde_json"] }
|
||||
rayon = "1.10.0"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
serde = { version = "1.0.219" }
|
||||
serde_bytes = "0.11.17"
|
||||
serde_derive = "1.0.219"
|
||||
serde_json = { version = "1.0.140", features = ["float_roundtrip"] }
|
||||
tabled = "0.18.0"
|
||||
zerocopy = { version = "0.8.24", features = ["derive"] }
|
||||
tabled = "0.20.0"
|
||||
tokio = { version = "1.45.1", features = ["rt-multi-thread"] }
|
||||
zerocopy = { version = "0.8.25" }
|
||||
zerocopy-derive = "0.8.25"
|
||||
|
||||
[workspace.metadata.release]
|
||||
shared-version = true
|
||||
@@ -50,19 +60,21 @@ tag-name = "v{{version}}"
|
||||
pre-release-commit-message = "release: v{{version}}"
|
||||
tag-message = "release: v{{version}}"
|
||||
|
||||
# Config for 'dist'
|
||||
[workspace.metadata.dist]
|
||||
# The preferred dist version to use in CI (Cargo.toml SemVer syntax)
|
||||
cargo-dist-version = "0.28.0"
|
||||
# CI backends to support
|
||||
ci = "github"
|
||||
# The installers to generate for each app
|
||||
installers = []
|
||||
# Target platforms to build apps for (Rust target-triple syntax)
|
||||
targets = [
|
||||
"aarch64-apple-darwin",
|
||||
"aarch64-unknown-linux-gnu",
|
||||
"x86_64-apple-darwin",
|
||||
"x86_64-unknown-linux-gnu",
|
||||
]
|
||||
github-custom-runners.global = "ubuntu-latest"
|
||||
|
||||
[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" }
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 bitcoinresearchkit, kibo.money
|
||||
Copyright (c) 2025 bitcoinresearchkit, kibo.money, satonomics
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
<a href="https://github.com/bitcoinresearchkit/brk">
|
||||
<img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/bitcoinresearchkit/brk?style=social">
|
||||
</a>
|
||||
<a href="https://kibo.money">
|
||||
<img alt="kibo.money" src="https://img.shields.io/badge/showcase-kib%C5%8D.money-orange">
|
||||
</a>
|
||||
<a href="https://github.com/bitcoinresearchkit/brk/blob/main/LICENSE.md">
|
||||
<img src="https://img.shields.io/crates/l/brk" alt="License" />
|
||||
</a>
|
||||
@@ -29,7 +26,7 @@
|
||||
<a href="https://bsky.app/profile/bitcoinresearchkit.org">
|
||||
<img src="https://img.shields.io/badge/bluesky-blue?link=https%3A%2F%2Fbsky.app%2Fprofile%2Fbitcoinresearchkit.org" alt="Bluesky" />
|
||||
</a>
|
||||
<a href="https://x.com/0xbrk">
|
||||
<a href="https://x.com/brkdotorg">
|
||||
<img src="https://img.shields.io/badge/x.com-black" alt="X" />
|
||||
</a>
|
||||
</p>
|
||||
@@ -77,6 +74,8 @@ 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_state`](https://crates.io/crates/brk_state): Various states used mainly by the computer
|
||||
- [`brk_store`](https://crates.io/crates/brk_store): A thin wrapper around [`fjall`](https://crates.io/crates/fjall)
|
||||
- [`brk_vec`](https://crates.io/crates/brk_vec): A push-only, truncable, compressable, saveable Vec
|
||||
|
||||
## Acknowledgments
|
||||
@@ -92,8 +91,11 @@ Heartfelt thanks go out to every donor on [Nostr](https://primal.net/p/npub1jagm
|
||||
If you'd like to have your own instance hosted for you please contact [hosting@bitcoinresearchkit.org](mailto:hosting@bitcoinresearchkit.org).
|
||||
|
||||
- 2 separate dedicated servers (1 GB/s each) with different ISPs and Cloudflare integration for enhanced performance and optimal availability
|
||||
- Direct communication for feature requests and support
|
||||
- 99.99% SLA
|
||||
- Configurated for speed (`raw + eager`)
|
||||
- Updates delivered at your convenience
|
||||
- Direct communication for feature requests and support
|
||||
- Bitcoin Core or Knots with desired version
|
||||
- Optional subdomains: `*.bitcoinresearchkit.org`, `*.kibo.money` and `*.satonomics.xyz`
|
||||
- Logo featured in the Readme if desired
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ name = "brk"
|
||||
description.workspace = true
|
||||
license.workspace = true
|
||||
readme.workspace = true
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
@@ -18,6 +19,8 @@ full = [
|
||||
"parser",
|
||||
"query",
|
||||
"server",
|
||||
"state",
|
||||
"store",
|
||||
"vec",
|
||||
]
|
||||
core = ["brk_core"]
|
||||
@@ -29,6 +32,8 @@ logger = ["brk_logger"]
|
||||
parser = ["brk_parser"]
|
||||
query = ["brk_query"]
|
||||
server = ["brk_server"]
|
||||
state = ["brk_state"]
|
||||
store = ["brk_store"]
|
||||
vec = ["brk_vec"]
|
||||
|
||||
[dependencies]
|
||||
@@ -42,6 +47,8 @@ brk_logger = { workspace = true, optional = true }
|
||||
brk_parser = { workspace = true, optional = true }
|
||||
brk_query = { workspace = true, optional = true }
|
||||
brk_server = { workspace = true, optional = true }
|
||||
brk_state = { workspace = true, optional = true }
|
||||
brk_store = { workspace = true, optional = true }
|
||||
brk_vec = { workspace = true, optional = true }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
|
||||
@@ -36,6 +36,14 @@ pub use brk_query as query;
|
||||
#[doc(inline)]
|
||||
pub use brk_server as server;
|
||||
|
||||
#[cfg(feature = "state")]
|
||||
#[doc(inline)]
|
||||
pub use brk_state as state;
|
||||
|
||||
#[cfg(feature = "store")]
|
||||
#[doc(inline)]
|
||||
pub use brk_store as store;
|
||||
|
||||
#[cfg(feature = "vec")]
|
||||
#[doc(inline)]
|
||||
pub use brk_vec as vec;
|
||||
|
||||
@@ -4,9 +4,11 @@ description = "A command line interface to interact with the full Bitcoin Resear
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
bitcoincore-rpc = { workspace = true }
|
||||
brk_computer = { workspace = true }
|
||||
brk_core = { workspace = true }
|
||||
brk_exit = { workspace = true }
|
||||
@@ -16,12 +18,15 @@ brk_logger = { workspace = true }
|
||||
brk_parser = { workspace = true }
|
||||
brk_query = { workspace = true }
|
||||
brk_server = { workspace = true }
|
||||
clap = { workspace = true, features = ["string"] }
|
||||
brk_vec = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
clap_derive = { workspace = true }
|
||||
color-eyre = { workspace = true }
|
||||
log = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
tabled = { workspace = true }
|
||||
toml = "0.8.20"
|
||||
tokio = { workspace = true }
|
||||
toml = "0.8.23"
|
||||
|
||||
[[bin]]
|
||||
name = "brk"
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
<a href="https://github.com/bitcoinresearchkit/brk">
|
||||
<img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/bitcoinresearchkit/brk?style=social">
|
||||
</a>
|
||||
<a href="https://kibo.money">
|
||||
<img alt="kibo.money" src="https://img.shields.io/badge/showcase-kib%C5%8D.money-orange">
|
||||
</a>
|
||||
<a href="https://github.com/bitcoinresearchkit/brk/blob/main/LICENSE.md">
|
||||
<img src="https://img.shields.io/crates/l/brk" alt="License" />
|
||||
</a>
|
||||
@@ -29,7 +26,7 @@
|
||||
<a href="https://bsky.app/profile/bitcoinresearchkit.org">
|
||||
<img src="https://img.shields.io/badge/bluesky-blue?link=https%3A%2F%2Fbsky.app%2Fprofile%2Fbitcoinresearchkit.org" alt="Bluesky" />
|
||||
</a>
|
||||
<a href="https://x.com/0xbrk">
|
||||
<a href="https://x.com/brkdotorg">
|
||||
<img src="https://img.shields.io/badge/x.com-black" alt="X" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -2,7 +2,8 @@ use std::fs;
|
||||
|
||||
use brk_core::{dot_brk_log_path, dot_brk_path};
|
||||
use brk_query::Params as QueryArgs;
|
||||
use clap::{Parser, Subcommand};
|
||||
use clap::Parser;
|
||||
use clap_derive::{Parser, Subcommand};
|
||||
use query::query;
|
||||
use run::{RunConfig, run};
|
||||
|
||||
|
||||
@@ -8,13 +8,13 @@ use crate::run::RunConfig;
|
||||
pub fn query(params: QueryParams) -> color_eyre::Result<()> {
|
||||
let config = RunConfig::import(None)?;
|
||||
|
||||
let compressed = config.compressed();
|
||||
let format = config.format();
|
||||
|
||||
let mut indexer = Indexer::new(config.indexeddir(), compressed, config.check_collisions())?;
|
||||
let mut indexer = Indexer::new(&config.outputsdir(), format, config.check_collisions())?;
|
||||
indexer.import_vecs()?;
|
||||
|
||||
let mut computer = Computer::new(config.computeddir(), config.fetcher(), compressed);
|
||||
computer.import_vecs()?;
|
||||
let mut computer = Computer::new(&config.outputsdir(), config.fetcher(), format);
|
||||
computer.import_vecs(&indexer, config.computation())?;
|
||||
|
||||
let query = Query::build(&indexer, &computer);
|
||||
|
||||
|
||||
+96
-83
@@ -1,18 +1,19 @@
|
||||
use std::{
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
thread::sleep,
|
||||
thread::{self, sleep},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use bitcoincore_rpc::{self, Auth, Client, RpcApi};
|
||||
use brk_computer::Computer;
|
||||
use brk_core::{default_bitcoin_path, default_brk_path, dot_brk_path};
|
||||
use brk_exit::Exit;
|
||||
use brk_fetcher::Fetcher;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_parser::rpc::{self, Auth, Client, RpcApi};
|
||||
use brk_server::{Server, Website, tokio};
|
||||
use clap::{Parser, ValueEnum};
|
||||
use brk_server::{Server, Website};
|
||||
use brk_vec::{Computation, Format};
|
||||
use clap_derive::{Parser, ValueEnum};
|
||||
use color_eyre::eyre::eyre;
|
||||
use log::info;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -26,83 +27,91 @@ pub fn run(config: RunConfig) -> color_eyre::Result<()> {
|
||||
|
||||
let parser = brk_parser::Parser::new(config.blocksdir(), rpc);
|
||||
|
||||
let compressed = config.compressed();
|
||||
let format = config.format();
|
||||
|
||||
let mut indexer = Indexer::new(config.indexeddir(), compressed, config.check_collisions())?;
|
||||
let mut indexer = Indexer::new(&config.outputsdir(), format, config.check_collisions())?;
|
||||
indexer.import_stores()?;
|
||||
indexer.import_vecs()?;
|
||||
|
||||
let mut computer = Computer::new(config.computeddir(), config.fetcher(), compressed);
|
||||
computer.import_stores()?;
|
||||
computer.import_vecs()?;
|
||||
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)
|
||||
};
|
||||
|
||||
tokio::runtime::Builder::new_multi_thread()
|
||||
.enable_all()
|
||||
.build()?
|
||||
.block_on(async {
|
||||
let server = if config.serve() {
|
||||
let served_indexer = indexer.clone();
|
||||
let served_computer = computer.clone();
|
||||
if !is_synced()? {
|
||||
info!("Waiting for node to be synced...");
|
||||
while !is_synced()? {
|
||||
sleep(Duration::from_secs(1))
|
||||
}
|
||||
}
|
||||
|
||||
let server = Server::new(served_indexer, served_computer, config.website())?;
|
||||
Ok(())
|
||||
};
|
||||
|
||||
let opt = Some(tokio::spawn(async move {
|
||||
server.serve().await.unwrap();
|
||||
}));
|
||||
let f = move || -> color_eyre::Result<()> {
|
||||
let mut computer = Computer::new(&config.outputsdir(), config.fetcher(), format);
|
||||
computer.import_stores(&indexer)?;
|
||||
computer.import_vecs(&indexer, config.computation())?;
|
||||
|
||||
sleep(Duration::from_secs(1));
|
||||
tokio::runtime::Builder::new_multi_thread()
|
||||
.enable_all()
|
||||
.build()?
|
||||
.block_on(async {
|
||||
let server = if config.serve() {
|
||||
let served_indexer = indexer.clone();
|
||||
let served_computer = computer.clone();
|
||||
|
||||
opt
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let server = Server::new(served_indexer, served_computer, config.website())?;
|
||||
|
||||
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)
|
||||
};
|
||||
let opt = Some(tokio::spawn(async move {
|
||||
server.serve().await.unwrap();
|
||||
}));
|
||||
|
||||
if !is_synced()? {
|
||||
info!("Waiting for node to be synced...");
|
||||
while !is_synced()? {
|
||||
sleep(Duration::from_secs(1));
|
||||
|
||||
opt
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if config.process() {
|
||||
loop {
|
||||
wait_for_synced_node()?;
|
||||
|
||||
let block_count = rpc.get_block_count()?;
|
||||
|
||||
info!("{} blocks found.", block_count + 1);
|
||||
|
||||
let starting_indexes = indexer.index(&parser, rpc, &exit)?;
|
||||
|
||||
computer.compute(&mut indexer, starting_indexes, &exit)?;
|
||||
|
||||
if let Some(delay) = config.delay() {
|
||||
sleep(Duration::from_secs(delay))
|
||||
}
|
||||
|
||||
info!("Waiting for new blocks...");
|
||||
|
||||
while block_count == rpc.get_block_count()? {
|
||||
sleep(Duration::from_secs(1))
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
};
|
||||
|
||||
loop {
|
||||
wait_for_synced_node()?;
|
||||
|
||||
let block_count = rpc.get_block_count()?;
|
||||
|
||||
info!("{} blocks found.", block_count + 1);
|
||||
|
||||
let starting_indexes = indexer.index(&parser, rpc, &exit)?;
|
||||
|
||||
computer.compute(&mut indexer, starting_indexes, &exit)?;
|
||||
|
||||
if let Some(delay) = config.delay() {
|
||||
sleep(Duration::from_secs(delay))
|
||||
}
|
||||
|
||||
info!("Waiting for new blocks...");
|
||||
|
||||
while block_count == rpc.get_block_count()? {
|
||||
sleep(Duration::from_secs(1))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(handle) = server {
|
||||
handle.await.unwrap();
|
||||
}
|
||||
if let Some(handle) = server {
|
||||
handle.await.unwrap();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
Ok(())
|
||||
})
|
||||
};
|
||||
|
||||
thread::Builder::new()
|
||||
.stack_size(128 * 1024 * 1024)
|
||||
.spawn(f)?
|
||||
.join()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
|
||||
@@ -123,15 +132,19 @@ pub struct RunConfig {
|
||||
#[arg(short, long)]
|
||||
mode: Option<Mode>,
|
||||
|
||||
/// Computation mode for compatible datasets, `lazy` computes data whenever requested without saving it, `eager` computes the data once and saves it to disk, default: Lazy, saved
|
||||
#[arg(short, long)]
|
||||
computation: Option<Computation>,
|
||||
|
||||
/// Activate compression of datasets, set to true to save disk space or false if prioritize speed, default: true, saved
|
||||
#[arg(short, long, value_name = "BOOL")]
|
||||
compressed: Option<bool>,
|
||||
#[arg(short, long, value_name = "FORMAT")]
|
||||
format: Option<Format>,
|
||||
|
||||
/// Activate fetching prices from exchanges APIs and the computation of all related datasets, default: true, saved
|
||||
#[arg(short, long, value_name = "BOOL")]
|
||||
#[arg(short = 'F', long, value_name = "BOOL")]
|
||||
fetch: Option<bool>,
|
||||
|
||||
/// Website served by the server (if active), default: kibo.money, saved
|
||||
/// Website served by the server (if active), default: default, saved
|
||||
#[arg(short, long)]
|
||||
website: Option<Website>,
|
||||
|
||||
@@ -191,12 +204,16 @@ impl RunConfig {
|
||||
config_saved.mode = Some(mode);
|
||||
}
|
||||
|
||||
if let Some(computation) = config_args.computation.take() {
|
||||
config_saved.computation = Some(computation);
|
||||
}
|
||||
|
||||
if let Some(fetch) = config_args.fetch.take() {
|
||||
config_saved.fetch = Some(fetch);
|
||||
}
|
||||
|
||||
if let Some(compressed) = config_args.compressed.take() {
|
||||
config_saved.compressed = Some(compressed);
|
||||
if let Some(format) = config_args.format.take() {
|
||||
config_saved.format = Some(format);
|
||||
}
|
||||
|
||||
if let Some(website) = config_args.website.take() {
|
||||
@@ -301,7 +318,7 @@ impl RunConfig {
|
||||
}
|
||||
|
||||
pub fn rpc(&self) -> color_eyre::Result<&'static Client> {
|
||||
Ok(Box::leak(Box::new(rpc::Client::new(
|
||||
Ok(Box::leak(Box::new(Client::new(
|
||||
&format!(
|
||||
"http://{}:{}",
|
||||
self.rpcconnect().unwrap_or(&"localhost".to_string()),
|
||||
@@ -357,18 +374,10 @@ impl RunConfig {
|
||||
.map_or_else(default_brk_path, |s| Self::fix_user_path(s.as_ref()))
|
||||
}
|
||||
|
||||
fn outputsdir(&self) -> PathBuf {
|
||||
pub fn outputsdir(&self) -> PathBuf {
|
||||
self.brkdir().join("outputs")
|
||||
}
|
||||
|
||||
pub fn indexeddir(&self) -> PathBuf {
|
||||
self.outputsdir().join("indexed")
|
||||
}
|
||||
|
||||
pub fn computeddir(&self) -> PathBuf {
|
||||
self.outputsdir().join("computed")
|
||||
}
|
||||
|
||||
pub fn harsdir(&self) -> PathBuf {
|
||||
self.outputsdir().join("hars")
|
||||
}
|
||||
@@ -409,7 +418,7 @@ impl RunConfig {
|
||||
}
|
||||
|
||||
pub fn website(&self) -> Website {
|
||||
self.website.unwrap_or(Website::KiboMoney)
|
||||
self.website.unwrap_or(Website::Default)
|
||||
}
|
||||
|
||||
pub fn fetch(&self) -> bool {
|
||||
@@ -421,8 +430,12 @@ impl RunConfig {
|
||||
.then(|| Fetcher::import(Some(self.harsdir().as_path())).unwrap())
|
||||
}
|
||||
|
||||
pub fn compressed(&self) -> bool {
|
||||
self.compressed.is_none_or(|b| b)
|
||||
pub fn computation(&self) -> Computation {
|
||||
self.computation.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn format(&self) -> Format {
|
||||
self.format.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn check_collisions(&self) -> bool {
|
||||
|
||||
@@ -4,15 +4,22 @@ description = "A Bitcoin dataset computer, built on top of brk_indexer"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
bitcoin = { workspace = true }
|
||||
bitcoincore-rpc = { workspace = true }
|
||||
brk_core = { workspace = true }
|
||||
brk_exit = { workspace = true }
|
||||
brk_fetcher = { workspace = true }
|
||||
brk_indexer = { workspace = true }
|
||||
brk_logger = { workspace = true }
|
||||
brk_parser = { workspace = true }
|
||||
brk_state = { workspace = true }
|
||||
brk_vec = { workspace = true }
|
||||
color-eyre = { workspace = true }
|
||||
fjall = { workspace = true }
|
||||
jiff = { workspace = true }
|
||||
log = { workspace = true }
|
||||
rayon = { workspace = true }
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
<a href="https://github.com/bitcoinresearchkit/brk">
|
||||
<img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/bitcoinresearchkit/brk?style=social">
|
||||
</a>
|
||||
<a href="https://kibo.money">
|
||||
<img alt="kibo.money" src="https://img.shields.io/badge/showcase-kib%C5%8D.money-orange">
|
||||
</a>
|
||||
<a href="https://github.com/bitcoinresearchkit/brk/blob/main/LICENSE.md">
|
||||
<img src="https://img.shields.io/crates/l/brk" alt="License" />
|
||||
</a>
|
||||
@@ -29,7 +26,7 @@
|
||||
<a href="https://bsky.app/profile/bitcoinresearchkit.org">
|
||||
<img src="https://img.shields.io/badge/bluesky-blue?link=https%3A%2F%2Fbsky.app%2Fprofile%2Fbitcoinresearchkit.org" alt="Bluesky" />
|
||||
</a>
|
||||
<a href="https://x.com/0xbrk">
|
||||
<a href="https://x.com/brkdotorg">
|
||||
<img src="https://img.shields.io/badge/x.com-black" alt="X" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
use std::path::Path;
|
||||
use std::{path::Path, thread};
|
||||
|
||||
use brk_computer::Computer;
|
||||
use brk_core::default_bitcoin_path;
|
||||
use brk_core::{default_bitcoin_path, default_brk_path};
|
||||
use brk_exit::Exit;
|
||||
use brk_fetcher::Fetcher;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_parser::{Parser, rpc};
|
||||
use brk_parser::Parser;
|
||||
use brk_vec::{Computation, Format};
|
||||
|
||||
pub fn main() -> color_eyre::Result<()> {
|
||||
color_eyre::install()?;
|
||||
@@ -14,31 +15,40 @@ pub fn main() -> color_eyre::Result<()> {
|
||||
|
||||
let bitcoin_dir = default_bitcoin_path();
|
||||
|
||||
let rpc = Box::leak(Box::new(rpc::Client::new(
|
||||
let rpc = Box::leak(Box::new(bitcoincore_rpc::Client::new(
|
||||
"http://localhost:8332",
|
||||
rpc::Auth::CookieFile(bitcoin_dir.join(".cookie")),
|
||||
bitcoincore_rpc::Auth::CookieFile(bitcoin_dir.join(".cookie")),
|
||||
)?));
|
||||
let exit = Exit::new();
|
||||
|
||||
let parser = Parser::new(bitcoin_dir.join("blocks"), rpc);
|
||||
// Can't increase main thread's stack programatically, thus we need to use another thread
|
||||
thread::Builder::new()
|
||||
.stack_size(32 * 1024 * 1024)
|
||||
.spawn(move || -> color_eyre::Result<()> {
|
||||
let parser = Parser::new(bitcoin_dir.join("blocks"), rpc);
|
||||
|
||||
let outputs_dir = Path::new("../../_outputs");
|
||||
let _outputs_dir = default_brk_path().join("outputs");
|
||||
let outputs_dir = _outputs_dir.as_path();
|
||||
// let outputs_dir = Path::new("../../_outputs");
|
||||
|
||||
let compressed = true;
|
||||
let format = Format::Raw;
|
||||
|
||||
let mut indexer = Indexer::new(outputs_dir.join("indexed"), compressed, true)?;
|
||||
indexer.import_stores()?;
|
||||
indexer.import_vecs()?;
|
||||
let mut indexer = Indexer::new(outputs_dir, format, true)?;
|
||||
indexer.import_stores()?;
|
||||
indexer.import_vecs()?;
|
||||
|
||||
let fetcher = Fetcher::import(None)?;
|
||||
let fetcher = Fetcher::import(None)?;
|
||||
|
||||
let mut computer = Computer::new(outputs_dir.join("computed"), Some(fetcher), compressed);
|
||||
computer.import_stores()?;
|
||||
computer.import_vecs()?;
|
||||
let mut computer = Computer::new(outputs_dir, Some(fetcher), format);
|
||||
computer.import_stores(&indexer)?;
|
||||
computer.import_vecs(&indexer, Computation::Lazy)?;
|
||||
|
||||
let starting_indexes = indexer.index(&parser, rpc, &exit)?;
|
||||
let starting_indexes = indexer.index(&parser, rpc, &exit)?;
|
||||
|
||||
computer.compute(&mut indexer, starting_indexes, &exit)?;
|
||||
computer.compute(&mut indexer, starting_indexes, &exit)?;
|
||||
|
||||
Ok(())
|
||||
Ok(())
|
||||
})?
|
||||
.join()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
@@ -5,16 +5,19 @@
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use brk_core::Version;
|
||||
use brk_exit::Exit;
|
||||
use brk_fetcher::Fetcher;
|
||||
use brk_indexer::{Indexer, Indexes};
|
||||
pub use brk_parser::rpc;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, Computation, Format};
|
||||
|
||||
mod storage;
|
||||
mod stores;
|
||||
mod utils;
|
||||
mod vecs;
|
||||
|
||||
use brk_vec::Compressed;
|
||||
use log::info;
|
||||
use storage::{Stores, Vecs};
|
||||
use stores::Stores;
|
||||
use vecs::Vecs;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Computer {
|
||||
@@ -22,33 +25,48 @@ pub struct Computer {
|
||||
fetcher: Option<Fetcher>,
|
||||
vecs: Option<Vecs>,
|
||||
stores: Option<Stores>,
|
||||
compressed: Compressed,
|
||||
format: Format,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ONE;
|
||||
|
||||
impl Computer {
|
||||
pub fn new(computed_dir: PathBuf, fetcher: Option<Fetcher>, compressed: bool) -> Self {
|
||||
pub fn new(outputs_dir: &Path, fetcher: Option<Fetcher>, format: Format) -> Self {
|
||||
Self {
|
||||
path: computed_dir,
|
||||
path: outputs_dir.to_owned(),
|
||||
fetcher,
|
||||
vecs: None,
|
||||
stores: None,
|
||||
compressed: Compressed::from(compressed),
|
||||
format,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn import_vecs(&mut self) -> color_eyre::Result<()> {
|
||||
pub fn import_vecs(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
computation: Computation,
|
||||
) -> color_eyre::Result<()> {
|
||||
self.vecs = Some(Vecs::import(
|
||||
&self.path.join("vecs"),
|
||||
// TODO: Give self.path, join inside import
|
||||
&self.path.join("vecs/computed"),
|
||||
VERSION + Version::ZERO,
|
||||
indexer,
|
||||
self.fetcher.is_some(),
|
||||
self.compressed,
|
||||
computation,
|
||||
self.format,
|
||||
)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Do NOT import multiple times or things will break !!!
|
||||
/// Clone struct instead
|
||||
pub fn import_stores(&mut self) -> color_eyre::Result<()> {
|
||||
self.stores = Some(Stores::import(&self.path.join("stores"))?);
|
||||
pub fn import_stores(&mut self, indexer: &Indexer) -> color_eyre::Result<()> {
|
||||
self.stores = Some(Stores::import(
|
||||
// TODO: Give self.path, join inside import
|
||||
&self.path.join("stores"),
|
||||
VERSION + Version::ZERO,
|
||||
indexer.keyspace(),
|
||||
)?);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -57,32 +75,24 @@ impl Computer {
|
||||
pub fn compute(
|
||||
&mut self,
|
||||
indexer: &mut Indexer,
|
||||
starting_indexes: Indexes,
|
||||
starting_indexes: brk_indexer::Indexes,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
info!("Computing...");
|
||||
|
||||
self.vecs.as_mut().unwrap().compute(
|
||||
indexer,
|
||||
starting_indexes,
|
||||
self.fetcher.as_mut(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
self.vecs
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.compute(indexer, starting_indexes, self.fetcher.as_mut(), exit)
|
||||
}
|
||||
|
||||
pub fn path(&self) -> &Path {
|
||||
&self.path
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
// pub fn vecs(&self) -> &Vecs {
|
||||
self.vecs.as_ref().unwrap().vecs()
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> &Vecs {
|
||||
self.vecs.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn mut_vecs(&mut self) -> &mut Vecs {
|
||||
self.vecs.as_mut().unwrap()
|
||||
}
|
||||
// pub fn mut_vecs(&mut self) -> &mut Vecs {
|
||||
// self.vecs.as_mut().unwrap()
|
||||
// }
|
||||
|
||||
pub fn stores(&self) -> &Stores {
|
||||
self.stores.as_ref().unwrap()
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
mod stores;
|
||||
mod vecs;
|
||||
|
||||
pub use stores::*;
|
||||
pub use vecs::*;
|
||||
@@ -1,25 +0,0 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{AddressindexTxoutindex, Unit};
|
||||
use brk_indexer::Store;
|
||||
use brk_vec::Version;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Stores {
|
||||
pub address_to_utxos_received: Store<AddressindexTxoutindex, Unit>,
|
||||
pub address_to_utxos_spent: Store<AddressindexTxoutindex, Unit>,
|
||||
}
|
||||
|
||||
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::ZERO)?;
|
||||
let address_to_utxos_spent =
|
||||
Store::import(&path.join("address_to_utxos_spent"), Version::ZERO)?;
|
||||
|
||||
Ok(Self {
|
||||
address_to_utxos_received,
|
||||
address_to_utxos_spent,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,505 +0,0 @@
|
||||
use core::error;
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
fmt::Debug,
|
||||
ops::Add,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use brk_core::{Bitcoin, CheckedSub, Close, Dollars, Height, Sats, Txindex};
|
||||
use brk_exit::Exit;
|
||||
use brk_vec::{
|
||||
Compressed, DynamicVec, Error, GenericVec, Result, StoredIndex, StoredType, StoredVec, Version,
|
||||
};
|
||||
use log::info;
|
||||
|
||||
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 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 inner = StoredVec::forced_import(path, version, compressed)?;
|
||||
|
||||
Ok(Self {
|
||||
computed_version: None,
|
||||
inner,
|
||||
})
|
||||
}
|
||||
|
||||
fn safe_truncate_if_needed(&mut self, index: I, exit: &Exit) -> Result<()> {
|
||||
if exit.triggered() {
|
||||
return Ok(());
|
||||
}
|
||||
exit.block();
|
||||
self.inner.truncate_if_needed(index)?;
|
||||
exit.release();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn forced_push_at(&mut self, index: I, value: T, exit: &Exit) -> Result<()> {
|
||||
match self.len().cmp(&index.to_usize()?) {
|
||||
Ordering::Less => {
|
||||
return Err(Error::IndexTooHigh);
|
||||
}
|
||||
ord => {
|
||||
if ord == Ordering::Greater {
|
||||
self.safe_truncate_if_needed(index, exit)?;
|
||||
}
|
||||
self.inner.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
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) -> Result<()> {
|
||||
if exit.triggered() {
|
||||
return Ok(());
|
||||
}
|
||||
exit.block();
|
||||
self.inner.flush()?;
|
||||
exit.release();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn version(&self) -> Version {
|
||||
self.inner.version()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.inner.len()
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.inner.is_empty()
|
||||
}
|
||||
|
||||
fn file_name(&self) -> String {
|
||||
self.inner.file_name()
|
||||
}
|
||||
|
||||
pub fn vec(&self) -> &StoredVec<I, T> {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub fn mut_vec(&mut self) -> &mut StoredVec<I, T> {
|
||||
&mut self.inner
|
||||
}
|
||||
|
||||
pub fn any_vec(&self) -> &dyn brk_vec::AnyStoredVec {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub fn mut_any_vec(&mut self) -> &mut dyn brk_vec::AnyStoredVec {
|
||||
&mut self.inner
|
||||
}
|
||||
|
||||
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.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.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 StoredVec<A, B>,
|
||||
mut t: F,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
A: StoredIndex,
|
||||
B: StoredType,
|
||||
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(index, |(a, b, other)| {
|
||||
let (i, v) = t((a, b, self, other));
|
||||
self.forced_push_at(i, v, exit)
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
|
||||
pub fn compute_inverse_more_to_less(
|
||||
&mut self,
|
||||
max_from: T,
|
||||
other: &mut StoredVec<T, I>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
I: StoredType + StoredIndex,
|
||||
T: StoredIndex,
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + other.version(),
|
||||
)?;
|
||||
|
||||
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, ..)| {
|
||||
if self.unwrap_cached_get(i).is_none_or(|old_v| old_v > v) {
|
||||
self.forced_push_at(i, v, exit)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
|
||||
pub fn compute_inverse_less_to_more(
|
||||
&mut self,
|
||||
max_from: T,
|
||||
first_indexes: &mut StoredVec<T, I>,
|
||||
last_indexes: &mut StoredVec<T, I>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
I: StoredType,
|
||||
T: StoredIndex,
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + first_indexes.version() + last_indexes.version(),
|
||||
)?;
|
||||
|
||||
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.double_unwrap_cached_get(value)).to_usize()?;
|
||||
(first_index..last_index)
|
||||
.try_for_each(|index| self.forced_push_at(I::from(index), value, exit))
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
|
||||
pub fn compute_last_index_from_first(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
first_indexes: &mut StoredVec<I, T>,
|
||||
final_len: usize,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
T: Copy + From<usize> + CheckedSub<T> + StoredIndex,
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + first_indexes.version(),
|
||||
)?;
|
||||
|
||||
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, |(index, v, ..)| {
|
||||
if let Some(prev_index) = prev_index.take() {
|
||||
let value = v.checked_sub(one).unwrap();
|
||||
self.forced_push_at(prev_index, value, exit)?;
|
||||
}
|
||||
prev_index.replace(index);
|
||||
Ok(())
|
||||
})?;
|
||||
if let Some(prev_index) = prev_index {
|
||||
self.forced_push_at(
|
||||
prev_index,
|
||||
T::from(final_len).checked_sub(one).unwrap(),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
|
||||
pub fn compute_count_from_indexes<T2>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
first_indexes: &mut StoredVec<I, T2>,
|
||||
last_indexes: &mut StoredVec<I, T2>,
|
||||
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,
|
||||
{
|
||||
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(
|
||||
Version::ZERO + self.version() + first_indexes.version() + last_indexes.version(),
|
||||
)?;
|
||||
|
||||
let index = max_from.min(I::from(self.len()));
|
||||
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 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)
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
|
||||
pub fn compute_is_first_ordered<A>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
self_to_other: &mut StoredVec<I, A>,
|
||||
other_to_self: &mut StoredVec<A, I>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
I: StoredType,
|
||||
T: From<bool>,
|
||||
A: StoredIndex + StoredType,
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + self_to_other.version() + other_to_self.version(),
|
||||
)?;
|
||||
|
||||
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.double_unwrap_cached_get(other) == i),
|
||||
exit,
|
||||
)
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
|
||||
pub fn compute_sum_from_indexes<T2>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
first_indexes: &mut StoredVec<I, T2>,
|
||||
last_indexes: &mut StoredVec<I, T2>,
|
||||
source: &mut StoredVec<T2, T>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
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, |(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)
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
computed_version: self.computed_version,
|
||||
inner: self.inner.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use brk_core::{CheckedSub, Height, StoredU32, StoredU64, StoredUsize, Timestamp, Weight};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_parser::bitcoin;
|
||||
use brk_vec::{Compressed, Version};
|
||||
|
||||
use super::{
|
||||
Indexes,
|
||||
base::ComputedVec,
|
||||
grouped::{ComputedVecsFromHeight, StorableVecGeneatorOptions},
|
||||
indexes,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vecs {
|
||||
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 {
|
||||
pub fn forced_import(path: &Path, compressed: Compressed) -> color_eyre::Result<Self> {
|
||||
fs::create_dir_all(path)?;
|
||||
|
||||
Ok(Self {
|
||||
height_to_interval: ComputedVec::forced_import(
|
||||
&path.join("height_to_interval"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
indexes_to_block_interval: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"block_interval",
|
||||
false,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_percentiles()
|
||||
.add_minmax()
|
||||
.add_average(),
|
||||
)?,
|
||||
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,
|
||||
)?,
|
||||
indexes_to_block_vbytes: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"block_vbytes",
|
||||
false,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_sum().add_total(),
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute(
|
||||
&mut self,
|
||||
indexer: &mut Indexer,
|
||||
indexes: &mut indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
self.height_to_interval.compute_transform(
|
||||
starting_indexes.height,
|
||||
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.double_unwrap_cached_get(prev_h);
|
||||
timestamp
|
||||
.checked_sub(prev_timestamp)
|
||||
.unwrap_or(Timestamp::ZERO)
|
||||
});
|
||||
(height, interval)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.indexes_to_block_interval.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(self.height_to_interval.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 brk_vec::AnyStoredVec> {
|
||||
[
|
||||
vec![
|
||||
self.height_to_interval.any_vec(),
|
||||
self.height_to_vbytes.any_vec(),
|
||||
],
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -1,790 +0,0 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_exit::Exit;
|
||||
use brk_vec::{
|
||||
Compressed, DynamicVec, GenericVec, Result, StoredIndex, StoredType, StoredVec, Version,
|
||||
};
|
||||
use color_eyre::eyre::ContextCompat;
|
||||
|
||||
use crate::storage::vecs::base::ComputedVec;
|
||||
|
||||
use super::ComputedType;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ComputedVecBuilder<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: ComputedType,
|
||||
{
|
||||
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>>,
|
||||
}
|
||||
|
||||
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 key = I::to_string().split("::").last().unwrap().to_lowercase();
|
||||
|
||||
let only_one_active = options.is_only_one_active();
|
||||
|
||||
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 {
|
||||
default()
|
||||
} else {
|
||||
prefix(s)
|
||||
}
|
||||
};
|
||||
|
||||
let suffix = |s: &str| path.join(format!("{key}_to_{name}_{s}"));
|
||||
|
||||
let maybe_suffix = |s: &str| {
|
||||
if only_one_active {
|
||||
default()
|
||||
} else {
|
||||
suffix(s)
|
||||
}
|
||||
};
|
||||
|
||||
let version = VERSION + version;
|
||||
|
||||
let s = Self {
|
||||
first: options.first.then(|| {
|
||||
ComputedVec::forced_import(
|
||||
&maybe_prefix("first"),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
last: options.last.then(|| {
|
||||
ComputedVec::forced_import(
|
||||
&path.join(format!("{key}_to_{name}")),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
min: options.min.then(|| {
|
||||
ComputedVec::forced_import(
|
||||
&maybe_suffix("min"),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
max: options.max.then(|| {
|
||||
ComputedVec::forced_import(
|
||||
&maybe_suffix("max"),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
median: options.median.then(|| {
|
||||
ComputedVec::forced_import(
|
||||
&maybe_suffix("median"),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
average: options.average.then(|| {
|
||||
ComputedVec::forced_import(
|
||||
&maybe_suffix("average"),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
sum: options.sum.then(|| {
|
||||
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(|| {
|
||||
ComputedVec::forced_import(
|
||||
&maybe_suffix("90p"),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
_75p: options._75p.then(|| {
|
||||
ComputedVec::forced_import(
|
||||
&maybe_suffix("75p"),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
_25p: options._25p.then(|| {
|
||||
ComputedVec::forced_import(
|
||||
&maybe_suffix("25p"),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
_10p: options._10p.then(|| {
|
||||
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 StoredVec<I2, T>,
|
||||
first_indexes: &mut StoredVec<I, I2>,
|
||||
last_indexes: &mut StoredVec<I, I2>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
I2: StoredIndex + StoredType,
|
||||
T: Ord + From<f64>,
|
||||
f64: From<T>,
|
||||
{
|
||||
let index = self.starting_index(max_from);
|
||||
|
||||
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.double_unwrap_cached_get(first_index);
|
||||
first.forced_push_at(index, v, exit)?;
|
||||
}
|
||||
|
||||
if let Some(last) = self.last.as_mut() {
|
||||
let v = source.double_unwrap_cached_get(last_index);
|
||||
last.forced_push_at(index, v, exit)?;
|
||||
}
|
||||
|
||||
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()
|
||||
|| self.median.is_some()
|
||||
|| self._25p.is_some()
|
||||
|| self._10p.is_some()
|
||||
|| self.min.is_some();
|
||||
let needs_values = needs_sorted || needs_average_sum_or_total;
|
||||
|
||||
if needs_values {
|
||||
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()
|
||||
.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() {
|
||||
_90p.forced_push_at(i, Self::get_percentile(&values, 0.90), exit)?;
|
||||
}
|
||||
|
||||
if let Some(_75p) = self._75p.as_mut() {
|
||||
_75p.forced_push_at(i, Self::get_percentile(&values, 0.75), exit)?;
|
||||
}
|
||||
|
||||
if let Some(median) = self.median.as_mut() {
|
||||
median.forced_push_at(i, Self::get_percentile(&values, 0.50), exit)?;
|
||||
}
|
||||
|
||||
if let Some(_25p) = self._25p.as_mut() {
|
||||
_25p.forced_push_at(i, Self::get_percentile(&values, 0.25), exit)?;
|
||||
}
|
||||
|
||||
if let Some(_10p) = self._10p.as_mut() {
|
||||
_10p.forced_push_at(i, Self::get_percentile(&values, 0.10), exit)?;
|
||||
}
|
||||
|
||||
if let Some(min) = self.min.as_mut() {
|
||||
min.forced_push_at(i, values.first().unwrap().clone(), exit)?;
|
||||
}
|
||||
}
|
||||
|
||||
if needs_average_sum_or_total {
|
||||
let len = values.len();
|
||||
|
||||
if let Some(average) = self.average.as_mut() {
|
||||
let len = len as f64;
|
||||
let total = values
|
||||
.iter()
|
||||
.map(|v| f64::from(v.clone()))
|
||||
.fold(0.0, |a, b| a + b);
|
||||
let avg = T::from(total / len);
|
||||
average.forced_push_at(i, avg, exit)?;
|
||||
}
|
||||
|
||||
if needs_sum_or_total {
|
||||
let sum = values.into_iter().fold(T::from(0), |a, b| a + b);
|
||||
|
||||
if let Some(sum_vec) = self.sum.as_mut() {
|
||||
sum_vec.forced_push_at(i, sum.clone(), exit)?;
|
||||
}
|
||||
|
||||
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)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
pub fn from_aligned<I2>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
source: &mut ComputedVecBuilder<I2, T>,
|
||||
first_indexes: &mut StoredVec<I, I2>,
|
||||
last_indexes: &mut StoredVec<I, I2>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
I2: StoredIndex + StoredType,
|
||||
T: Ord + From<f64>,
|
||||
f64: From<T>,
|
||||
{
|
||||
if self._90p.is_some()
|
||||
|| self._75p.is_some()
|
||||
|| self.median.is_some()
|
||||
|| self._25p.is_some()
|
||||
|| self._10p.is_some()
|
||||
{
|
||||
panic!("unsupported");
|
||||
}
|
||||
|
||||
let index = self.starting_index(max_from);
|
||||
|
||||
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()
|
||||
.double_unwrap_cached_get(first_index);
|
||||
first.forced_push_at(index, v, exit)?;
|
||||
}
|
||||
|
||||
if let Some(last) = self.last.as_mut() {
|
||||
let v = source
|
||||
.last
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.double_unwrap_cached_get(last_index);
|
||||
last.forced_push_at(index, v, exit)?;
|
||||
}
|
||||
|
||||
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_average_sum_or_total;
|
||||
|
||||
if needs_values {
|
||||
if needs_sorted {
|
||||
if let Some(max) = self.max.as_mut() {
|
||||
let mut values = source
|
||||
.max
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.collect_inclusive_range(first_index, last_index)?;
|
||||
values.sort_unstable();
|
||||
max.forced_push_at(i, values.last().unwrap().clone(), exit)?;
|
||||
}
|
||||
|
||||
if let Some(min) = self.min.as_mut() {
|
||||
let mut values = source
|
||||
.min
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.collect_inclusive_range(first_index, last_index)?;
|
||||
values.sort_unstable();
|
||||
min.forced_push_at(i, values.first().unwrap().clone(), exit)?;
|
||||
}
|
||||
}
|
||||
|
||||
if needs_average_sum_or_total {
|
||||
if let Some(average) = self.average.as_mut() {
|
||||
let values = source
|
||||
.average
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.collect_inclusive_range(first_index, last_index)?;
|
||||
let len = values.len() as f64;
|
||||
let total = values
|
||||
.into_iter()
|
||||
.map(|v| f64::from(v))
|
||||
.fold(0.0, |a, b| a + b);
|
||||
// TODO: Multiply by count then divide by total
|
||||
// Right now it's not 100% accurate as there could be more or less elements in the lower timeframe (28 days vs 31 days in a month for example)
|
||||
let avg = T::from(total / len);
|
||||
average.forced_push_at(i, avg, exit)?;
|
||||
}
|
||||
|
||||
if needs_sum_or_total {
|
||||
let values = source
|
||||
.sum
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.collect_inclusive_range(first_index, last_index)?;
|
||||
let sum = values.into_iter().fold(T::from(0), |a, b| a + b);
|
||||
|
||||
if let Some(sum_vec) = self.sum.as_mut() {
|
||||
sum_vec.forced_push_at(i, sum.clone(), exit)?;
|
||||
}
|
||||
|
||||
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)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_percentile(sorted: &[T], percentile: f64) -> T {
|
||||
let len = sorted.len();
|
||||
|
||||
if len == 0 {
|
||||
panic!();
|
||||
} else if len == 1 {
|
||||
sorted[0].clone()
|
||||
} else {
|
||||
let index = (len - 1) as f64 * percentile;
|
||||
|
||||
let fract = index.fract();
|
||||
|
||||
if fract != 0.0 {
|
||||
let left = sorted.get(index as usize).unwrap().clone();
|
||||
let right = sorted.get(index.ceil() as usize).unwrap().clone();
|
||||
left / 2 + right / 2
|
||||
} else {
|
||||
sorted.get(index as usize).unwrap().clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn starting_index(&self, max_from: I) -> I {
|
||||
max_from.min(I::from(
|
||||
self.any_vecs().into_iter().map(|v| v.len()).min().unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
if let Some(last) = self.last.as_ref() {
|
||||
v.push(last.any_vec());
|
||||
}
|
||||
if let Some(min) = self.min.as_ref() {
|
||||
v.push(min.any_vec());
|
||||
}
|
||||
if let Some(max) = self.max.as_ref() {
|
||||
v.push(max.any_vec());
|
||||
}
|
||||
if let Some(median) = self.median.as_ref() {
|
||||
v.push(median.any_vec());
|
||||
}
|
||||
if let Some(average) = self.average.as_ref() {
|
||||
v.push(average.any_vec());
|
||||
}
|
||||
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());
|
||||
}
|
||||
if let Some(_75p) = self._75p.as_ref() {
|
||||
v.push(_75p.any_vec());
|
||||
}
|
||||
if let Some(_25p) = self._25p.as_ref() {
|
||||
v.push(_25p.any_vec());
|
||||
}
|
||||
if let Some(_10p) = self._10p.as_ref() {
|
||||
v.push(_10p.any_vec());
|
||||
}
|
||||
|
||||
v
|
||||
}
|
||||
|
||||
pub fn safe_flush(&mut self, exit: &Exit) -> Result<()> {
|
||||
if let Some(first) = self.first.as_mut() {
|
||||
first.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(last) = self.last.as_mut() {
|
||||
last.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(min) = self.min.as_mut() {
|
||||
min.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(max) = self.max.as_mut() {
|
||||
max.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(median) = self.median.as_mut() {
|
||||
median.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(average) = self.average.as_mut() {
|
||||
average.safe_flush(exit)?;
|
||||
}
|
||||
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)?;
|
||||
}
|
||||
if let Some(_75p) = self._75p.as_mut() {
|
||||
_75p.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(_25p) = self._25p.as_mut() {
|
||||
_25p.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(_10p) = self._10p.as_mut() {
|
||||
_10p.safe_flush(exit)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Copy)]
|
||||
pub struct StorableVecGeneatorOptions {
|
||||
average: bool,
|
||||
sum: bool,
|
||||
max: bool,
|
||||
_90p: bool,
|
||||
_75p: bool,
|
||||
median: bool,
|
||||
_25p: bool,
|
||||
_10p: bool,
|
||||
min: bool,
|
||||
first: bool,
|
||||
last: bool,
|
||||
total: bool,
|
||||
}
|
||||
|
||||
impl StorableVecGeneatorOptions {
|
||||
pub fn add_first(mut self) -> Self {
|
||||
self.first = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_last(mut self) -> Self {
|
||||
self.last = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_min(mut self) -> Self {
|
||||
self.min = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_max(mut self) -> Self {
|
||||
self.max = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_median(mut self) -> Self {
|
||||
self.median = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_average(mut self) -> Self {
|
||||
self.average = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_sum(mut self) -> Self {
|
||||
self.sum = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_90p(mut self) -> Self {
|
||||
self._90p = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_75p(mut self) -> Self {
|
||||
self._75p = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_25p(mut self) -> Self {
|
||||
self._25p = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_10p(mut self) -> Self {
|
||||
self._10p = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_total(mut self) -> Self {
|
||||
self.total = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_min(mut self) -> Self {
|
||||
self.min = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_max(mut self) -> Self {
|
||||
self.max = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_median(mut self) -> Self {
|
||||
self.median = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_average(mut self) -> Self {
|
||||
self.average = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_sum(mut self) -> Self {
|
||||
self.sum = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_90p(mut self) -> Self {
|
||||
self._90p = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_75p(mut self) -> Self {
|
||||
self._75p = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_25p(mut self) -> Self {
|
||||
self._25p = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_10p(mut self) -> Self {
|
||||
self._10p = false;
|
||||
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;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_percentiles(mut self) -> Self {
|
||||
self._90p = true;
|
||||
self._75p = true;
|
||||
self.median = true;
|
||||
self._25p = true;
|
||||
self._10p = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn remove_percentiles(mut self) -> Self {
|
||||
self._90p = false;
|
||||
self._75p = false;
|
||||
self.median = false;
|
||||
self._25p = false;
|
||||
self._10p = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_only_one_active(&self) -> bool {
|
||||
[
|
||||
self.average,
|
||||
self.sum,
|
||||
self.max,
|
||||
self._90p,
|
||||
self._75p,
|
||||
self.median,
|
||||
self._25p,
|
||||
self._10p,
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -1,206 +0,0 @@
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -1,845 +0,0 @@
|
||||
use std::{fs, ops::Deref, path::Path};
|
||||
|
||||
use brk_core::{
|
||||
Date, Dateindex, Decadeindex, Difficultyepoch, Halvingepoch, Height, Monthindex, Quarterindex,
|
||||
Timestamp, Txindex, Txinindex, Txoutindex, Weekindex, Yearindex,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{Compressed, Version};
|
||||
|
||||
use super::ComputedVec;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vecs {
|
||||
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 {
|
||||
pub fn forced_import(path: &Path, compressed: Compressed) -> color_eyre::Result<Self> {
|
||||
fs::create_dir_all(path)?;
|
||||
|
||||
Ok(Self {
|
||||
dateindex_to_date: ComputedVec::forced_import(
|
||||
&path.join("dateindex_to_date"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
dateindex_to_dateindex: ComputedVec::forced_import(
|
||||
&path.join("dateindex_to_dateindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
dateindex_to_first_height: ComputedVec::forced_import(
|
||||
&path.join("dateindex_to_first_height"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
dateindex_to_last_height: ComputedVec::forced_import(
|
||||
&path.join("dateindex_to_last_height"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_real_date: ComputedVec::forced_import(
|
||||
&path.join("height_to_real_date"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_fixed_date: ComputedVec::forced_import(
|
||||
&path.join("height_to_fixed_date"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_dateindex: ComputedVec::forced_import(
|
||||
&path.join("height_to_dateindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_height: ComputedVec::forced_import(
|
||||
&path.join("height_to_height"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_last_txindex: ComputedVec::forced_import(
|
||||
&path.join("height_to_last_txindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_last_txinindex: ComputedVec::forced_import(
|
||||
&path.join("txindex_to_last_txinindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_last_txoutindex: ComputedVec::forced_import(
|
||||
&path.join("txindex_to_last_txoutindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
difficultyepoch_to_first_height: ComputedVec::forced_import(
|
||||
&path.join("difficultyepoch_to_first_height"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
difficultyepoch_to_last_height: ComputedVec::forced_import(
|
||||
&path.join("difficultyepoch_to_last_height"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
halvingepoch_to_first_height: ComputedVec::forced_import(
|
||||
&path.join("halvingepoch_to_first_height"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
halvingepoch_to_last_height: ComputedVec::forced_import(
|
||||
&path.join("halvingepoch_to_last_height"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
weekindex_to_first_dateindex: ComputedVec::forced_import(
|
||||
&path.join("weekindex_to_first_dateindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
weekindex_to_last_dateindex: ComputedVec::forced_import(
|
||||
&path.join("weekindex_to_last_dateindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
monthindex_to_first_dateindex: ComputedVec::forced_import(
|
||||
&path.join("monthindex_to_first_dateindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
monthindex_to_last_dateindex: ComputedVec::forced_import(
|
||||
&path.join("monthindex_to_last_dateindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
yearindex_to_first_monthindex: ComputedVec::forced_import(
|
||||
&path.join("yearindex_to_first_monthindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
yearindex_to_last_monthindex: ComputedVec::forced_import(
|
||||
&path.join("yearindex_to_last_monthindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
decadeindex_to_first_yearindex: ComputedVec::forced_import(
|
||||
&path.join("decadeindex_to_first_yearindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
decadeindex_to_last_yearindex: ComputedVec::forced_import(
|
||||
&path.join("decadeindex_to_last_yearindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
dateindex_to_weekindex: ComputedVec::forced_import(
|
||||
&path.join("dateindex_to_weekindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
dateindex_to_monthindex: ComputedVec::forced_import(
|
||||
&path.join("dateindex_to_monthindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
monthindex_to_yearindex: ComputedVec::forced_import(
|
||||
&path.join("monthindex_to_yearindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
yearindex_to_decadeindex: ComputedVec::forced_import(
|
||||
&path.join("yearindex_to_decadeindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_difficultyepoch: ComputedVec::forced_import(
|
||||
&path.join("height_to_difficultyepoch"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_halvingepoch: ComputedVec::forced_import(
|
||||
&path.join("height_to_halvingepoch"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
weekindex_to_weekindex: ComputedVec::forced_import(
|
||||
&path.join("weekindex_to_weekindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
monthindex_to_monthindex: ComputedVec::forced_import(
|
||||
&path.join("monthindex_to_monthindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
yearindex_to_yearindex: ComputedVec::forced_import(
|
||||
&path.join("yearindex_to_yearindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
decadeindex_to_decadeindex: ComputedVec::forced_import(
|
||||
&path.join("decadeindex_to_decadeindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
difficultyepoch_to_difficultyepoch: ComputedVec::forced_import(
|
||||
&path.join("difficultyepoch_to_difficultyepoch"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
halvingepoch_to_halvingepoch: ComputedVec::forced_import(
|
||||
&path.join("halvingepoch_to_halvingepoch"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
dateindex_to_timestamp: ComputedVec::forced_import(
|
||||
&path.join("dateindex_to_timestamp"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
decadeindex_to_timestamp: ComputedVec::forced_import(
|
||||
&path.join("decadeindex_to_timestamp"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
difficultyepoch_to_timestamp: ComputedVec::forced_import(
|
||||
&path.join("difficultyepoch_to_timestamp"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
halvingepoch_to_timestamp: ComputedVec::forced_import(
|
||||
&path.join("halvingepoch_to_timestamp"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
monthindex_to_timestamp: ComputedVec::forced_import(
|
||||
&path.join("monthindex_to_timestamp"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
weekindex_to_timestamp: ComputedVec::forced_import(
|
||||
&path.join("weekindex_to_timestamp"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
yearindex_to_timestamp: ComputedVec::forced_import(
|
||||
&path.join("yearindex_to_timestamp"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_fixed_timestamp: ComputedVec::forced_import(
|
||||
&path.join("height_to_fixed_timestamp"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
monthindex_to_quarterindex: ComputedVec::forced_import(
|
||||
&path.join("monthindex_to_quarterindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
quarterindex_to_first_monthindex: ComputedVec::forced_import(
|
||||
&path.join("quarterindex_to_first_monthindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
quarterindex_to_last_monthindex: ComputedVec::forced_import(
|
||||
&path.join("quarterindex_to_last_monthindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
quarterindex_to_quarterindex: ComputedVec::forced_import(
|
||||
&path.join("quarterindex_to_quarterindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
quarterindex_to_timestamp: ComputedVec::forced_import(
|
||||
&path.join("quarterindex_to_timestamp"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute(
|
||||
&mut self,
|
||||
indexer: &mut Indexer,
|
||||
starting_indexes: brk_indexer::Indexes,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<Indexes> {
|
||||
let indexer_vecs = indexer.mut_vecs();
|
||||
|
||||
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();
|
||||
|
||||
self.height_to_height.compute_transform(
|
||||
starting_indexes.height,
|
||||
indexer_vecs.height_to_timestamp.mut_vec(),
|
||||
|(h, ..)| (h, h),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.height_to_real_date.compute_transform(
|
||||
starting_indexes.height,
|
||||
indexer_vecs.height_to_timestamp.mut_vec(),
|
||||
|(h, t, ..)| (h, Date::from(t)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.height_to_fixed_timestamp.compute_transform(
|
||||
starting_indexes.height,
|
||||
indexer_vecs.height_to_timestamp.mut_vec(),
|
||||
|(h, d, s, ..)| {
|
||||
let d = h
|
||||
.decremented()
|
||||
.and_then(|h| s.unwrap_cached_get(h))
|
||||
.map_or(d, |prev_d| prev_d.max(d));
|
||||
(h, d)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.height_to_fixed_date.compute_transform(
|
||||
starting_indexes.height,
|
||||
self.height_to_fixed_timestamp.mut_vec(),
|
||||
|(h, t, ..)| (h, Date::from(t)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let decremented_starting_height = starting_indexes.height.decremented().unwrap_or_default();
|
||||
|
||||
let starting_dateindex = self
|
||||
.height_to_dateindex
|
||||
.unwrap_cached_get(decremented_starting_height)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.height_to_dateindex.compute_transform(
|
||||
starting_indexes.height,
|
||||
self.height_to_fixed_date.mut_vec(),
|
||||
|(h, d, ..)| (h, Dateindex::try_from(d).unwrap()),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let starting_dateindex = if let Some(dateindex) = self
|
||||
.height_to_dateindex
|
||||
.unwrap_cached_get(decremented_starting_height)
|
||||
{
|
||||
starting_dateindex.min(dateindex)
|
||||
} else {
|
||||
starting_dateindex
|
||||
};
|
||||
|
||||
self.dateindex_to_first_height
|
||||
.compute_inverse_more_to_less(
|
||||
starting_indexes.height,
|
||||
self.height_to_dateindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let date_count = self.dateindex_to_first_height.len();
|
||||
|
||||
self.dateindex_to_last_height
|
||||
.compute_last_index_from_first(
|
||||
starting_dateindex,
|
||||
self.dateindex_to_first_height.mut_vec(),
|
||||
height_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.dateindex_to_dateindex.compute_transform(
|
||||
starting_dateindex,
|
||||
self.dateindex_to_first_height.mut_vec(),
|
||||
|(di, ..)| (di, di),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.dateindex_to_date.compute_transform(
|
||||
starting_dateindex,
|
||||
self.dateindex_to_dateindex.mut_vec(),
|
||||
|(di, ..)| (di, Date::from(di)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.dateindex_to_timestamp.compute_transform(
|
||||
starting_dateindex,
|
||||
self.dateindex_to_date.mut_vec(),
|
||||
|(di, d, ..)| (di, Timestamp::from(d)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.txindex_to_last_txinindex
|
||||
.compute_last_index_from_first(
|
||||
starting_indexes.txindex,
|
||||
indexer_vecs.txindex_to_first_txinindex.mut_vec(),
|
||||
txinindexes_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.txindex_to_last_txoutindex
|
||||
.compute_last_index_from_first(
|
||||
starting_indexes.txindex,
|
||||
indexer_vecs.txindex_to_first_txoutindex.mut_vec(),
|
||||
txoutindexes_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.height_to_last_txindex.compute_last_index_from_first(
|
||||
starting_indexes.height,
|
||||
indexer_vecs.height_to_first_txindex.mut_vec(),
|
||||
txindexes_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// ---
|
||||
|
||||
let starting_weekindex = self
|
||||
.dateindex_to_weekindex
|
||||
.unwrap_cached_get(starting_dateindex)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.dateindex_to_weekindex.compute_transform(
|
||||
starting_dateindex,
|
||||
self.dateindex_to_dateindex.mut_vec(),
|
||||
|(di, ..)| (di, Weekindex::from(di)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.weekindex_to_first_dateindex
|
||||
.compute_inverse_more_to_less(
|
||||
starting_dateindex,
|
||||
self.dateindex_to_weekindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.weekindex_to_last_dateindex
|
||||
.compute_last_index_from_first(
|
||||
starting_weekindex,
|
||||
self.weekindex_to_first_dateindex.mut_vec(),
|
||||
date_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.weekindex_to_weekindex.compute_transform(
|
||||
starting_weekindex,
|
||||
self.weekindex_to_first_dateindex.mut_vec(),
|
||||
|(wi, ..)| (wi, wi),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.weekindex_to_timestamp.compute_transform(
|
||||
starting_weekindex,
|
||||
self.weekindex_to_first_dateindex.mut_vec(),
|
||||
|(i, d, ..)| (i, self.dateindex_to_timestamp.double_unwrap_cached_get(d)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// ---
|
||||
|
||||
let starting_monthindex = self
|
||||
.dateindex_to_monthindex
|
||||
.unwrap_cached_get(starting_dateindex)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.dateindex_to_monthindex.compute_transform(
|
||||
starting_dateindex,
|
||||
self.dateindex_to_dateindex.mut_vec(),
|
||||
|(di, ..)| (di, Monthindex::from(di)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex_to_first_dateindex
|
||||
.compute_inverse_more_to_less(
|
||||
starting_dateindex,
|
||||
self.dateindex_to_monthindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let month_count = self.monthindex_to_first_dateindex.len();
|
||||
|
||||
self.monthindex_to_last_dateindex
|
||||
.compute_last_index_from_first(
|
||||
starting_monthindex,
|
||||
self.monthindex_to_first_dateindex.mut_vec(),
|
||||
date_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex_to_monthindex.compute_transform(
|
||||
starting_monthindex,
|
||||
self.monthindex_to_first_dateindex.mut_vec(),
|
||||
|(mi, ..)| (mi, mi),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex_to_timestamp.compute_transform(
|
||||
starting_monthindex,
|
||||
self.monthindex_to_first_dateindex.mut_vec(),
|
||||
|(i, d, ..)| (i, self.dateindex_to_timestamp.double_unwrap_cached_get(d)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// ---
|
||||
|
||||
let starting_quarterindex = self
|
||||
.monthindex_to_quarterindex
|
||||
.unwrap_cached_get(starting_monthindex)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.monthindex_to_quarterindex.compute_transform(
|
||||
starting_monthindex,
|
||||
self.monthindex_to_monthindex.mut_vec(),
|
||||
|(mi, ..)| (mi, Quarterindex::from(mi)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.quarterindex_to_first_monthindex
|
||||
.compute_inverse_more_to_less(
|
||||
starting_monthindex,
|
||||
self.monthindex_to_quarterindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// let quarter_count = self.quarterindex_to_first_monthindex.len();
|
||||
|
||||
self.quarterindex_to_last_monthindex
|
||||
.compute_last_index_from_first(
|
||||
starting_quarterindex,
|
||||
self.quarterindex_to_first_monthindex.mut_vec(),
|
||||
month_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.quarterindex_to_quarterindex.compute_transform(
|
||||
starting_quarterindex,
|
||||
self.quarterindex_to_first_monthindex.mut_vec(),
|
||||
|(yi, ..)| (yi, yi),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.quarterindex_to_timestamp.compute_transform(
|
||||
starting_quarterindex,
|
||||
self.quarterindex_to_first_monthindex.mut_vec(),
|
||||
|(i, m, ..)| (i, self.monthindex_to_timestamp.double_unwrap_cached_get(m)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// ---
|
||||
|
||||
let starting_yearindex = self
|
||||
.monthindex_to_yearindex
|
||||
.unwrap_cached_get(starting_monthindex)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.monthindex_to_yearindex.compute_transform(
|
||||
starting_monthindex,
|
||||
self.monthindex_to_monthindex.mut_vec(),
|
||||
|(mi, ..)| (mi, Yearindex::from(mi)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex_to_first_monthindex
|
||||
.compute_inverse_more_to_less(
|
||||
starting_monthindex,
|
||||
self.monthindex_to_yearindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let year_count = self.yearindex_to_first_monthindex.len();
|
||||
|
||||
self.yearindex_to_last_monthindex
|
||||
.compute_last_index_from_first(
|
||||
starting_yearindex,
|
||||
self.yearindex_to_first_monthindex.mut_vec(),
|
||||
month_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex_to_yearindex.compute_transform(
|
||||
starting_yearindex,
|
||||
self.yearindex_to_first_monthindex.mut_vec(),
|
||||
|(yi, ..)| (yi, yi),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex_to_timestamp.compute_transform(
|
||||
starting_yearindex,
|
||||
self.yearindex_to_first_monthindex.mut_vec(),
|
||||
|(i, m, ..)| (i, self.monthindex_to_timestamp.double_unwrap_cached_get(m)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// ---
|
||||
|
||||
let starting_decadeindex = self
|
||||
.yearindex_to_decadeindex
|
||||
.unwrap_cached_get(starting_yearindex)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.yearindex_to_decadeindex.compute_transform(
|
||||
starting_yearindex,
|
||||
self.yearindex_to_yearindex.mut_vec(),
|
||||
|(yi, ..)| (yi, Decadeindex::from(yi)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex_to_first_yearindex
|
||||
.compute_inverse_more_to_less(
|
||||
starting_yearindex,
|
||||
self.yearindex_to_decadeindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex_to_last_yearindex
|
||||
.compute_last_index_from_first(
|
||||
starting_decadeindex,
|
||||
self.decadeindex_to_first_yearindex.mut_vec(),
|
||||
year_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex_to_decadeindex.compute_transform(
|
||||
starting_decadeindex,
|
||||
self.decadeindex_to_first_yearindex.mut_vec(),
|
||||
|(di, ..)| (di, di),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex_to_timestamp.compute_transform(
|
||||
starting_decadeindex,
|
||||
self.decadeindex_to_first_yearindex.mut_vec(),
|
||||
|(i, y, ..)| (i, self.yearindex_to_timestamp.double_unwrap_cached_get(y)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// ---
|
||||
|
||||
let starting_difficultyepoch = self
|
||||
.height_to_difficultyepoch
|
||||
.unwrap_cached_get(decremented_starting_height)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.height_to_difficultyepoch.compute_transform(
|
||||
starting_indexes.height,
|
||||
self.height_to_height.mut_vec(),
|
||||
|(h, ..)| (h, Difficultyepoch::from(h)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.difficultyepoch_to_first_height
|
||||
.compute_inverse_more_to_less(
|
||||
starting_indexes.height,
|
||||
self.height_to_difficultyepoch.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.difficultyepoch_to_last_height
|
||||
.compute_last_index_from_first(
|
||||
starting_difficultyepoch,
|
||||
self.difficultyepoch_to_first_height.mut_vec(),
|
||||
height_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.difficultyepoch_to_difficultyepoch.compute_transform(
|
||||
starting_difficultyepoch,
|
||||
self.difficultyepoch_to_first_height.mut_vec(),
|
||||
|(de, ..)| (de, de),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.difficultyepoch_to_timestamp.compute_transform(
|
||||
starting_difficultyepoch,
|
||||
self.difficultyepoch_to_first_height.mut_vec(),
|
||||
|(i, h, ..)| {
|
||||
(
|
||||
i,
|
||||
indexer_vecs.height_to_timestamp.double_unwrap_cached_get(h),
|
||||
)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// ---
|
||||
|
||||
let starting_halvingepoch = self
|
||||
.height_to_halvingepoch
|
||||
.unwrap_cached_get(decremented_starting_height)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.height_to_halvingepoch.compute_transform(
|
||||
starting_indexes.height,
|
||||
self.height_to_height.mut_vec(),
|
||||
|(h, ..)| (h, Halvingepoch::from(h)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.halvingepoch_to_first_height
|
||||
.compute_inverse_more_to_less(
|
||||
starting_indexes.height,
|
||||
self.height_to_halvingepoch.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.halvingepoch_to_last_height
|
||||
.compute_last_index_from_first(
|
||||
starting_halvingepoch,
|
||||
self.halvingepoch_to_first_height.mut_vec(),
|
||||
height_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.halvingepoch_to_halvingepoch.compute_transform(
|
||||
starting_halvingepoch,
|
||||
self.halvingepoch_to_first_height.mut_vec(),
|
||||
|(he, ..)| (he, he),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// self.difficultyepoch_to_timestamp.compute_transform(
|
||||
// starting_difficultyepoch,
|
||||
// self.difficultyepoch_to_first_height.mut_vec(),
|
||||
// |(i, h, ..)| {
|
||||
// (
|
||||
// i,
|
||||
// *indexer_vecs.height_to_timestamp.unwraped_cached_get(h).unwrap().unwrap(),
|
||||
// )
|
||||
// },
|
||||
// exit,
|
||||
// )?;
|
||||
|
||||
Ok(Indexes {
|
||||
indexes: starting_indexes,
|
||||
dateindex: starting_dateindex,
|
||||
weekindex: starting_weekindex,
|
||||
monthindex: starting_monthindex,
|
||||
quarterindex: starting_quarterindex,
|
||||
yearindex: starting_yearindex,
|
||||
decadeindex: starting_decadeindex,
|
||||
difficultyepoch: starting_difficultyepoch,
|
||||
halvingepoch: starting_halvingepoch,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn brk_vec::AnyStoredVec> {
|
||||
vec![
|
||||
self.dateindex_to_date.any_vec(),
|
||||
self.dateindex_to_dateindex.any_vec(),
|
||||
self.dateindex_to_first_height.any_vec(),
|
||||
self.dateindex_to_last_height.any_vec(),
|
||||
self.height_to_dateindex.any_vec(),
|
||||
self.height_to_fixed_date.any_vec(),
|
||||
self.height_to_height.any_vec(),
|
||||
self.height_to_last_txindex.any_vec(),
|
||||
self.height_to_real_date.any_vec(),
|
||||
self.txindex_to_last_txinindex.any_vec(),
|
||||
self.txindex_to_last_txoutindex.any_vec(),
|
||||
self.difficultyepoch_to_first_height.any_vec(),
|
||||
self.difficultyepoch_to_last_height.any_vec(),
|
||||
self.halvingepoch_to_first_height.any_vec(),
|
||||
self.halvingepoch_to_last_height.any_vec(),
|
||||
self.weekindex_to_first_dateindex.any_vec(),
|
||||
self.weekindex_to_last_dateindex.any_vec(),
|
||||
self.monthindex_to_first_dateindex.any_vec(),
|
||||
self.monthindex_to_last_dateindex.any_vec(),
|
||||
self.yearindex_to_first_monthindex.any_vec(),
|
||||
self.yearindex_to_last_monthindex.any_vec(),
|
||||
self.decadeindex_to_first_yearindex.any_vec(),
|
||||
self.decadeindex_to_last_yearindex.any_vec(),
|
||||
self.dateindex_to_weekindex.any_vec(),
|
||||
self.dateindex_to_monthindex.any_vec(),
|
||||
self.monthindex_to_yearindex.any_vec(),
|
||||
self.yearindex_to_decadeindex.any_vec(),
|
||||
self.height_to_difficultyepoch.any_vec(),
|
||||
self.height_to_halvingepoch.any_vec(),
|
||||
self.weekindex_to_weekindex.any_vec(),
|
||||
self.monthindex_to_monthindex.any_vec(),
|
||||
self.yearindex_to_yearindex.any_vec(),
|
||||
self.decadeindex_to_decadeindex.any_vec(),
|
||||
self.difficultyepoch_to_difficultyepoch.any_vec(),
|
||||
self.halvingepoch_to_halvingepoch.any_vec(),
|
||||
self.dateindex_to_timestamp.any_vec(),
|
||||
self.decadeindex_to_timestamp.any_vec(),
|
||||
self.difficultyepoch_to_timestamp.any_vec(),
|
||||
self.halvingepoch_to_timestamp.any_vec(),
|
||||
self.monthindex_to_timestamp.any_vec(),
|
||||
self.weekindex_to_timestamp.any_vec(),
|
||||
self.yearindex_to_timestamp.any_vec(),
|
||||
self.height_to_fixed_timestamp.any_vec(),
|
||||
self.monthindex_to_quarterindex.any_vec(),
|
||||
self.quarterindex_to_first_monthindex.any_vec(),
|
||||
self.quarterindex_to_last_monthindex.any_vec(),
|
||||
self.quarterindex_to_quarterindex.any_vec(),
|
||||
self.quarterindex_to_timestamp.any_vec(),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Indexes {
|
||||
indexes: brk_indexer::Indexes,
|
||||
pub dateindex: Dateindex,
|
||||
pub weekindex: Weekindex,
|
||||
pub monthindex: Monthindex,
|
||||
pub quarterindex: Quarterindex,
|
||||
pub yearindex: Yearindex,
|
||||
pub decadeindex: Decadeindex,
|
||||
pub difficultyepoch: Difficultyepoch,
|
||||
pub halvingepoch: Halvingepoch,
|
||||
}
|
||||
|
||||
impl Deref for Indexes {
|
||||
type Target = brk_indexer::Indexes;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.indexes
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,82 +0,0 @@
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use brk_exit::Exit;
|
||||
use brk_fetcher::Fetcher;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyStoredVec, Compressed};
|
||||
|
||||
pub mod base;
|
||||
pub mod blocks;
|
||||
pub mod grouped;
|
||||
pub mod indexes;
|
||||
pub mod marketprice;
|
||||
pub mod transactions;
|
||||
|
||||
use base::*;
|
||||
use indexes::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vecs {
|
||||
pub blocks: blocks::Vecs,
|
||||
pub indexes: indexes::Vecs,
|
||||
pub transactions: transactions::Vecs,
|
||||
pub marketprice: Option<marketprice::Vecs>,
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
pub fn import(path: &Path, fetch: bool, compressed: Compressed) -> color_eyre::Result<Self> {
|
||||
fs::create_dir_all(path)?;
|
||||
|
||||
Ok(Self {
|
||||
blocks: blocks::Vecs::forced_import(path, compressed)?,
|
||||
indexes: indexes::Vecs::forced_import(path, compressed)?,
|
||||
transactions: transactions::Vecs::forced_import(path, compressed, fetch)?,
|
||||
marketprice: fetch.then(|| marketprice::Vecs::forced_import(path, compressed).unwrap()),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute(
|
||||
&mut self,
|
||||
indexer: &mut Indexer,
|
||||
starting_indexes: brk_indexer::Indexes,
|
||||
fetcher: Option<&mut Fetcher>,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
let starting_indexes = self.indexes.compute(indexer, starting_indexes, exit)?;
|
||||
|
||||
self.blocks
|
||||
.compute(indexer, &mut self.indexes, &starting_indexes, exit)?;
|
||||
|
||||
if let Some(marketprice) = self.marketprice.as_mut() {
|
||||
marketprice.compute(
|
||||
indexer,
|
||||
&mut self.indexes,
|
||||
&starting_indexes,
|
||||
fetcher.unwrap(),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
self.transactions.compute(
|
||||
indexer,
|
||||
&mut self.indexes,
|
||||
&starting_indexes,
|
||||
&mut self.marketprice.as_mut(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStoredVec> {
|
||||
[
|
||||
self.indexes.as_any_vecs(),
|
||||
self.blocks.as_any_vecs(),
|
||||
self.transactions.as_any_vecs(),
|
||||
self.marketprice
|
||||
.as_ref()
|
||||
.map_or(vec![], |v| v.as_any_vecs()),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
@@ -1,578 +0,0 @@
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use brk_core::{
|
||||
CheckedSub, Feerate, Sats, StoredU32, StoredU64, StoredUsize, TxVersion, Txindex, Txinindex,
|
||||
Txoutindex, Weight,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_parser::bitcoin;
|
||||
use brk_vec::{Compressed, DynamicVec, StoredIndex, Version};
|
||||
|
||||
use super::{
|
||||
ComputedVec, Indexes,
|
||||
grouped::{
|
||||
ComputedValueVecsFromHeight, ComputedValueVecsFromTxindex, ComputedVecsFromHeight,
|
||||
ComputedVecsFromTxindex, StorableVecGeneatorOptions,
|
||||
},
|
||||
indexes, marketprice,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vecs {
|
||||
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,
|
||||
compute_dollars: bool,
|
||||
) -> color_eyre::Result<Self> {
|
||||
fs::create_dir_all(path)?;
|
||||
|
||||
Ok(Self {
|
||||
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::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
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,
|
||||
)?,
|
||||
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_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,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute(
|
||||
&mut self,
|
||||
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_is_coinbase.compute_is_first_ordered(
|
||||
starting_indexes.txindex,
|
||||
indexer_vecs.txindex_to_height.mut_vec(),
|
||||
indexer_vecs.height_to_first_txindex.mut_vec(),
|
||||
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);
|
||||
|
||||
// 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));
|
||||
|
||||
(txindex, weight)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
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,
|
||||
)?;
|
||||
|
||||
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,
|
||||
)?;
|
||||
|
||||
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 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()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::Version;
|
||||
use fjall::TransactionalKeyspace;
|
||||
|
||||
const _VERSION: Version = Version::ZERO;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Stores {
|
||||
// pub address_to_utxos_received: Store<AddressIndexOutputIndex, Unit>,
|
||||
// pub address_to_utxos_spent: Store<AddressIndexOutputIndex, Unit>,
|
||||
}
|
||||
|
||||
impl Stores {
|
||||
pub fn import(_: &Path, _: Version, _: &TransactionalKeyspace) -> color_eyre::Result<Self> {
|
||||
// let address_to_utxos_received = Store::import(
|
||||
// keyspace.clone(),
|
||||
// path,
|
||||
// "address_to_utxos_received",
|
||||
// version + VERSION + Version::ZERO,
|
||||
// )?;
|
||||
// let address_to_utxos_spent = Store::import(
|
||||
// keyspace.clone(),
|
||||
// path,
|
||||
// "address_to_utxos_spent",
|
||||
// version + VERSION + Version::ZERO,
|
||||
// )?;
|
||||
|
||||
Ok(Self {
|
||||
// address_to_utxos_received,
|
||||
// address_to_utxos_spent,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
use std::ops::{Add, Div};
|
||||
|
||||
pub fn get_percentile<T>(sorted: &[T], percentile: f64) -> T
|
||||
where
|
||||
T: Clone + Div<usize, Output = T> + Add<T, Output = T>,
|
||||
{
|
||||
let len = sorted.len();
|
||||
|
||||
if len == 0 {
|
||||
panic!();
|
||||
} else if len == 1 {
|
||||
sorted[0].clone()
|
||||
} else {
|
||||
let index = (len - 1) as f64 * percentile;
|
||||
|
||||
let fract = index.fract();
|
||||
|
||||
if fract != 0.0 {
|
||||
let left = sorted.get(index as usize).unwrap().clone();
|
||||
let right = sorted.get(index.ceil() as usize).unwrap().clone();
|
||||
left / 2 + right / 2
|
||||
} else {
|
||||
// dbg!(sorted.len(), index);
|
||||
sorted.get(index as usize).unwrap().clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use brk_core::{
|
||||
CheckedSub, DifficultyEpoch, HalvingEpoch, Height, StoredU32, StoredU64, StoredUsize,
|
||||
Timestamp, Version, Weight,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, AnyIterableVec, Computation, EagerVec, Format};
|
||||
|
||||
use super::{
|
||||
Indexes,
|
||||
grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, StorableVecGeneatorOptions},
|
||||
indexes,
|
||||
};
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vecs {
|
||||
pub height_to_interval: EagerVec<Height, Timestamp>,
|
||||
pub height_to_vbytes: EagerVec<Height, StoredU64>,
|
||||
pub difficultyepoch_to_timestamp: EagerVec<DifficultyEpoch, Timestamp>,
|
||||
pub halvingepoch_to_timestamp: EagerVec<HalvingEpoch, Timestamp>,
|
||||
pub timeindexes_to_timestamp: ComputedVecsFromDateIndex<Timestamp>,
|
||||
pub indexes_to_block_count: ComputedVecsFromHeight<StoredU32>,
|
||||
pub indexes_to_block_interval: ComputedVecsFromHeight<Timestamp>,
|
||||
pub indexes_to_block_size: ComputedVecsFromHeight<StoredUsize>,
|
||||
pub indexes_to_block_vbytes: ComputedVecsFromHeight<StoredU64>,
|
||||
pub indexes_to_block_weight: ComputedVecsFromHeight<Weight>,
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
version: Version,
|
||||
_computation: Computation,
|
||||
format: Format,
|
||||
) -> color_eyre::Result<Self> {
|
||||
fs::create_dir_all(path)?;
|
||||
|
||||
Ok(Self {
|
||||
height_to_interval: EagerVec::forced_import(
|
||||
path,
|
||||
"interval",
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)?,
|
||||
timeindexes_to_timestamp: ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
"timestamp",
|
||||
true,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_first(),
|
||||
)?,
|
||||
indexes_to_block_interval: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"block_interval",
|
||||
false,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_percentiles()
|
||||
.add_minmax()
|
||||
.add_average(),
|
||||
)?,
|
||||
indexes_to_block_count: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"block_count",
|
||||
true,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_sum()
|
||||
.add_cumulative(),
|
||||
)?,
|
||||
indexes_to_block_weight: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"block_weight",
|
||||
false,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_sum()
|
||||
.add_cumulative(),
|
||||
)?,
|
||||
indexes_to_block_size: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"block_size",
|
||||
false,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_sum()
|
||||
.add_cumulative(),
|
||||
)?,
|
||||
height_to_vbytes: EagerVec::forced_import(
|
||||
path,
|
||||
"vbytes",
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)?,
|
||||
indexes_to_block_vbytes: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"block_vbytes",
|
||||
false,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_sum()
|
||||
.add_cumulative(),
|
||||
)?,
|
||||
difficultyepoch_to_timestamp: EagerVec::forced_import(
|
||||
path,
|
||||
"timestamp",
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)?,
|
||||
halvingepoch_to_timestamp: EagerVec::forced_import(
|
||||
path,
|
||||
"timestamp",
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
self.timeindexes_to_timestamp.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|vec, _, indexes, starting_indexes, exit| {
|
||||
vec.compute_transform(
|
||||
starting_indexes.dateindex,
|
||||
&indexes.dateindex_to_date,
|
||||
|(di, d, ..)| (di, Timestamp::from(d)),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
self.indexes_to_block_count.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, indexer, _, starting_indexes, exit| {
|
||||
let indexer_vecs = indexer.vecs();
|
||||
|
||||
v.compute_range(
|
||||
starting_indexes.height,
|
||||
&indexer_vecs.height_to_weight,
|
||||
|h| (h, StoredU32::from(1_u32)),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
let indexer_vecs = indexer.vecs();
|
||||
|
||||
let mut height_to_timestamp_iter = indexer_vecs.height_to_timestamp.iter();
|
||||
self.height_to_interval.compute_transform(
|
||||
starting_indexes.height,
|
||||
&indexer_vecs.height_to_timestamp,
|
||||
|(height, timestamp, ..)| {
|
||||
let interval = height.decremented().map_or(Timestamp::ZERO, |prev_h| {
|
||||
let prev_timestamp = height_to_timestamp_iter.unwrap_get_inner(prev_h);
|
||||
timestamp
|
||||
.checked_sub(prev_timestamp)
|
||||
.unwrap_or(Timestamp::ZERO)
|
||||
});
|
||||
(height, interval)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.indexes_to_block_interval.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(&self.height_to_interval),
|
||||
)?;
|
||||
|
||||
self.indexes_to_block_weight.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(&indexer_vecs.height_to_weight),
|
||||
)?;
|
||||
|
||||
self.indexes_to_block_size.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(&indexer_vecs.height_to_total_size),
|
||||
)?;
|
||||
|
||||
self.height_to_vbytes.compute_transform(
|
||||
starting_indexes.height,
|
||||
&indexer_vecs.height_to_weight,
|
||||
|(h, w, ..)| {
|
||||
(
|
||||
h,
|
||||
StoredU64::from(bitcoin::Weight::from(w).to_vbytes_floor()),
|
||||
)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.indexes_to_block_vbytes.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(&self.height_to_vbytes),
|
||||
)?;
|
||||
|
||||
let mut height_to_timestamp_iter = indexer_vecs.height_to_timestamp.iter();
|
||||
|
||||
self.difficultyepoch_to_timestamp.compute_transform(
|
||||
starting_indexes.difficultyepoch,
|
||||
&indexes.difficultyepoch_to_first_height,
|
||||
|(i, h, ..)| (i, height_to_timestamp_iter.unwrap_get_inner(h)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.halvingepoch_to_timestamp.compute_transform(
|
||||
starting_indexes.halvingepoch,
|
||||
&indexes.halvingepoch_to_first_height,
|
||||
|(i, h, ..)| (i, height_to_timestamp_iter.unwrap_get_inner(h)),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
[
|
||||
vec![
|
||||
&self.height_to_interval as &dyn AnyCollectableVec,
|
||||
&self.height_to_vbytes,
|
||||
&self.difficultyepoch_to_timestamp,
|
||||
&self.halvingepoch_to_timestamp,
|
||||
],
|
||||
self.timeindexes_to_timestamp.vecs(),
|
||||
self.indexes_to_block_count.vecs(),
|
||||
self.indexes_to_block_interval.vecs(),
|
||||
self.indexes_to_block_size.vecs(),
|
||||
self.indexes_to_block_vbytes.vecs(),
|
||||
self.indexes_to_block_weight.vecs(),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use brk_core::{StoredU8, Version};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, AnyVec, Computation, Format};
|
||||
|
||||
use super::{
|
||||
Indexes,
|
||||
grouped::{ComputedVecsFromHeight, StorableVecGeneatorOptions},
|
||||
indexes,
|
||||
};
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vecs {
|
||||
pub _0: ComputedVecsFromHeight<StoredU8>,
|
||||
pub _1: ComputedVecsFromHeight<StoredU8>,
|
||||
pub _50: ComputedVecsFromHeight<StoredU8>,
|
||||
pub _100: ComputedVecsFromHeight<StoredU8>,
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
version: Version,
|
||||
_computation: Computation,
|
||||
format: Format,
|
||||
) -> color_eyre::Result<Self> {
|
||||
fs::create_dir_all(path)?;
|
||||
|
||||
Ok(Self {
|
||||
_0: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"0",
|
||||
true,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
)?,
|
||||
_1: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"1",
|
||||
true,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
)?,
|
||||
_50: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"50",
|
||||
true,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
)?,
|
||||
_100: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"100",
|
||||
true,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
self._0.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|vec, _, indexes, starting_indexes, exit| {
|
||||
vec.compute_to(
|
||||
starting_indexes.height,
|
||||
indexes.height_to_date.len(),
|
||||
indexes.height_to_date.version(),
|
||||
|i| (i, StoredU8::new(0)),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
self._1.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|vec, _, indexes, starting_indexes, exit| {
|
||||
vec.compute_to(
|
||||
starting_indexes.height,
|
||||
indexes.height_to_date.len(),
|
||||
indexes.height_to_date.version(),
|
||||
|i| (i, StoredU8::new(1)),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
self._50.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|vec, _, indexes, starting_indexes, exit| {
|
||||
vec.compute_to(
|
||||
starting_indexes.height,
|
||||
indexes.height_to_date.len(),
|
||||
indexes.height_to_date.version(),
|
||||
|i| (i, StoredU8::new(50)),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
self._100.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|vec, _, indexes, starting_indexes, exit| {
|
||||
vec.compute_to(
|
||||
starting_indexes.height,
|
||||
indexes.height_to_date.len(),
|
||||
indexes.height_to_date.version(),
|
||||
|i| (i, StoredU8::new(100)),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
[
|
||||
self._0.vecs(),
|
||||
self._1.vecs(),
|
||||
self._50.vecs(),
|
||||
self._100.vecs(),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,907 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{CheckedSub, Result, StoredUsize, Version};
|
||||
use brk_exit::Exit;
|
||||
use brk_vec::{AnyCollectableVec, AnyIterableVec, EagerVec, Format, StoredIndex, StoredType};
|
||||
use color_eyre::eyre::ContextCompat;
|
||||
|
||||
use crate::utils::get_percentile;
|
||||
|
||||
use super::ComputedType;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ComputedVecBuilder<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: ComputedType,
|
||||
{
|
||||
pub first: Option<Box<EagerVec<I, T>>>,
|
||||
pub average: Option<Box<EagerVec<I, T>>>,
|
||||
pub sum: Option<Box<EagerVec<I, T>>>,
|
||||
pub max: Option<Box<EagerVec<I, T>>>,
|
||||
pub _90p: Option<Box<EagerVec<I, T>>>,
|
||||
pub _75p: Option<Box<EagerVec<I, T>>>,
|
||||
pub median: Option<Box<EagerVec<I, T>>>,
|
||||
pub _25p: Option<Box<EagerVec<I, T>>>,
|
||||
pub _10p: Option<Box<EagerVec<I, T>>>,
|
||||
pub min: Option<Box<EagerVec<I, T>>>,
|
||||
pub last: Option<Box<EagerVec<I, T>>>,
|
||||
pub cumulative: Option<Box<EagerVec<I, T>>>,
|
||||
}
|
||||
|
||||
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,
|
||||
format: Format,
|
||||
options: StorableVecGeneatorOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let only_one_active = options.is_only_one_active();
|
||||
|
||||
let prefix = |s: &str| format!("{s}_{name}");
|
||||
|
||||
let maybe_prefix = |s: &str| {
|
||||
if only_one_active {
|
||||
name.to_string()
|
||||
} else {
|
||||
prefix(s)
|
||||
}
|
||||
};
|
||||
|
||||
let suffix = |s: &str| format!("{name}_{s}");
|
||||
|
||||
let maybe_suffix = |s: &str| {
|
||||
if only_one_active {
|
||||
name.to_string()
|
||||
} else {
|
||||
suffix(s)
|
||||
}
|
||||
};
|
||||
|
||||
let s = Self {
|
||||
first: options.first.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&maybe_prefix("first"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
last: options.last.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(path, name, version + Version::ZERO, format).unwrap(),
|
||||
)
|
||||
}),
|
||||
min: options.min.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&maybe_suffix("min"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
max: options.max.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&maybe_suffix("max"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
median: options.median.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&maybe_suffix("median"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
average: options.average.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&maybe_suffix("average"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
sum: options.sum.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&maybe_suffix("sum"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
cumulative: options.cumulative.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&prefix("cumulative"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
_90p: options._90p.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&maybe_suffix("90p"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
_75p: options._75p.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&maybe_suffix("75p"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
_25p: options._25p.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&maybe_suffix("25p"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
_10p: options._10p.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&maybe_suffix("10p"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}),
|
||||
};
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
pub fn extend(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
source: &impl AnyIterableVec<I, T>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
if self.cumulative.is_none() {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
self.validate_computed_version_or_reset_file(source.version())?;
|
||||
|
||||
let index = self.starting_index(max_from);
|
||||
|
||||
let cumulative_vec = self.cumulative.as_mut().unwrap();
|
||||
|
||||
let mut cumulative = index.decremented().map_or(T::from(0_usize), |index| {
|
||||
cumulative_vec.iter().unwrap_get_inner(index)
|
||||
});
|
||||
source.iter_at(index).try_for_each(|(i, v)| -> Result<()> {
|
||||
cumulative = cumulative.clone() + v.into_inner();
|
||||
cumulative_vec.forced_push_at(i, cumulative.clone(), exit)
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute<I2>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
source: &impl AnyIterableVec<I2, T>,
|
||||
first_indexes: &impl AnyIterableVec<I, I2>,
|
||||
count_indexes: &impl AnyIterableVec<I, StoredUsize>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
I2: StoredIndex + StoredType + CheckedSub<I2>,
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
source.version() + first_indexes.version() + count_indexes.version(),
|
||||
)?;
|
||||
|
||||
let index = self.starting_index(max_from);
|
||||
|
||||
let mut count_indexes_iter = count_indexes.iter();
|
||||
let mut source_iter = source.iter();
|
||||
|
||||
let cumulative_vec = self.cumulative.as_mut();
|
||||
|
||||
let mut cumulative = cumulative_vec.map(|cumulative_vec| {
|
||||
index.decremented().map_or(T::from(0_usize), |index| {
|
||||
cumulative_vec.iter().unwrap_get_inner(index)
|
||||
})
|
||||
});
|
||||
|
||||
first_indexes
|
||||
.iter_at(index)
|
||||
.try_for_each(|(i, first_index)| -> Result<()> {
|
||||
let first_index = first_index.into_inner();
|
||||
|
||||
let count_index = count_indexes_iter.unwrap_get_inner(i);
|
||||
|
||||
if let Some(first) = self.first.as_mut() {
|
||||
let f = source_iter
|
||||
.get_inner(first_index)
|
||||
.unwrap_or_else(|| T::from(0_usize));
|
||||
first.forced_push_at(index, f, exit)?;
|
||||
}
|
||||
|
||||
if let Some(last) = self.last.as_mut() {
|
||||
let count_index = *count_index;
|
||||
if count_index == 0 {
|
||||
panic!("should compute last if count can be 0")
|
||||
}
|
||||
let last_index = first_index + (count_index - 1);
|
||||
let v = source_iter.unwrap_get_inner(last_index);
|
||||
// .context("to work")
|
||||
// .inspect_err(|_| {
|
||||
// dbg!(first_index, count_index, last_index);
|
||||
// })
|
||||
// .unwrap()
|
||||
// .into_inner();
|
||||
last.forced_push_at(index, v, exit)?;
|
||||
}
|
||||
|
||||
let needs_sum_or_cumulative = self.sum.is_some() || self.cumulative.is_some();
|
||||
let needs_average_sum_or_cumulative =
|
||||
needs_sum_or_cumulative || self.average.is_some();
|
||||
let needs_sorted = self.max.is_some()
|
||||
|| self._90p.is_some()
|
||||
|| self._75p.is_some()
|
||||
|| self.median.is_some()
|
||||
|| self._25p.is_some()
|
||||
|| self._10p.is_some()
|
||||
|| self.min.is_some();
|
||||
let needs_values = needs_sorted || needs_average_sum_or_cumulative;
|
||||
|
||||
if needs_values {
|
||||
source_iter.set(first_index);
|
||||
let mut values = (&mut source_iter)
|
||||
.take(*count_index)
|
||||
.map(|(_, v)| v.into_inner())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if needs_sorted {
|
||||
values.sort_unstable();
|
||||
|
||||
if let Some(max) = self.max.as_mut() {
|
||||
max.forced_push_at(
|
||||
i,
|
||||
values
|
||||
.last()
|
||||
.context("expect some")
|
||||
.inspect_err(|_| {
|
||||
dbg!(
|
||||
&values,
|
||||
max.path(),
|
||||
first_indexes.name(),
|
||||
first_index,
|
||||
count_indexes.name(),
|
||||
count_index,
|
||||
source.len(),
|
||||
source.name()
|
||||
);
|
||||
})
|
||||
.unwrap()
|
||||
.clone(),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(_90p) = self._90p.as_mut() {
|
||||
_90p.forced_push_at(i, get_percentile(&values, 0.90), exit)?;
|
||||
}
|
||||
|
||||
if let Some(_75p) = self._75p.as_mut() {
|
||||
_75p.forced_push_at(i, get_percentile(&values, 0.75), exit)?;
|
||||
}
|
||||
|
||||
if let Some(median) = self.median.as_mut() {
|
||||
median.forced_push_at(i, get_percentile(&values, 0.50), exit)?;
|
||||
}
|
||||
|
||||
if let Some(_25p) = self._25p.as_mut() {
|
||||
_25p.forced_push_at(i, get_percentile(&values, 0.25), exit)?;
|
||||
}
|
||||
|
||||
if let Some(_10p) = self._10p.as_mut() {
|
||||
_10p.forced_push_at(i, get_percentile(&values, 0.10), exit)?;
|
||||
}
|
||||
|
||||
if let Some(min) = self.min.as_mut() {
|
||||
min.forced_push_at(i, values.first().unwrap().clone(), exit)?;
|
||||
}
|
||||
}
|
||||
|
||||
if needs_average_sum_or_cumulative {
|
||||
let len = values.len();
|
||||
let sum = values.into_iter().fold(T::from(0), |a, b| a + b);
|
||||
|
||||
if let Some(average) = self.average.as_mut() {
|
||||
let avg = sum.clone() / len;
|
||||
average.forced_push_at(i, avg, exit)?;
|
||||
}
|
||||
|
||||
if needs_sum_or_cumulative {
|
||||
if let Some(sum_vec) = self.sum.as_mut() {
|
||||
sum_vec.forced_push_at(i, sum.clone(), exit)?;
|
||||
}
|
||||
|
||||
if let Some(cumulative_vec) = self.cumulative.as_mut() {
|
||||
let t = cumulative.as_ref().unwrap().clone() + sum;
|
||||
cumulative.replace(t.clone());
|
||||
cumulative_vec.forced_push_at(i, t, exit)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
pub fn from_aligned<I2>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
source: &ComputedVecBuilder<I2, T>,
|
||||
first_indexes: &impl AnyIterableVec<I, I2>,
|
||||
count_indexes: &impl AnyIterableVec<I, StoredUsize>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
I2: StoredIndex + StoredType + CheckedSub<I2>,
|
||||
{
|
||||
if self._90p.is_some()
|
||||
|| self._75p.is_some()
|
||||
|| self.median.is_some()
|
||||
|| self._25p.is_some()
|
||||
|| self._10p.is_some()
|
||||
{
|
||||
panic!("unsupported");
|
||||
}
|
||||
|
||||
self.validate_computed_version_or_reset_file(
|
||||
VERSION + first_indexes.version() + count_indexes.version(),
|
||||
)?;
|
||||
|
||||
let index = self.starting_index(max_from);
|
||||
|
||||
let mut count_indexes_iter = count_indexes.iter();
|
||||
|
||||
let mut source_first_iter = source.first.as_ref().map(|f| f.iter());
|
||||
let mut source_last_iter = source.last.as_ref().map(|f| f.iter());
|
||||
let mut source_max_iter = source.max.as_ref().map(|f| f.iter());
|
||||
let mut source_min_iter = source.min.as_ref().map(|f| f.iter());
|
||||
let mut source_average_iter = source.average.as_ref().map(|f| f.iter());
|
||||
let mut source_sum_iter = source.sum.as_ref().map(|f| f.iter());
|
||||
|
||||
let mut cumulative = self.cumulative.as_mut().map(|cumulative_vec| {
|
||||
index.decremented().map_or(T::from(0_usize), |index| {
|
||||
cumulative_vec.iter().unwrap_get_inner(index)
|
||||
})
|
||||
});
|
||||
|
||||
first_indexes
|
||||
.iter_at(index)
|
||||
.try_for_each(|(i, first_index, ..)| -> Result<()> {
|
||||
let first_index = first_index.into_inner();
|
||||
|
||||
let count_index = count_indexes_iter.unwrap_get_inner(i);
|
||||
|
||||
if let Some(first) = self.first.as_mut() {
|
||||
let v = source_first_iter
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.unwrap_get_inner(first_index);
|
||||
first.forced_push_at(index, v, exit)?;
|
||||
}
|
||||
|
||||
if let Some(last) = self.last.as_mut() {
|
||||
let count_index = *count_index;
|
||||
if count_index == 0 {
|
||||
panic!("should compute last if count can be 0")
|
||||
}
|
||||
let last_index = first_index + (count_index - 1);
|
||||
let v = source_last_iter
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.unwrap_get_inner(last_index);
|
||||
last.forced_push_at(index, v, exit)?;
|
||||
}
|
||||
|
||||
let needs_sum_or_cumulative = self.sum.is_some() || self.cumulative.is_some();
|
||||
let needs_average_sum_or_cumulative =
|
||||
needs_sum_or_cumulative || self.average.is_some();
|
||||
let needs_sorted = self.max.is_some() || self.min.is_some();
|
||||
let needs_values = needs_sorted || needs_average_sum_or_cumulative;
|
||||
|
||||
if needs_values {
|
||||
if needs_sorted {
|
||||
if let Some(max) = self.max.as_mut() {
|
||||
let source_max_iter = source_max_iter.as_mut().unwrap();
|
||||
source_max_iter.set(first_index);
|
||||
let mut values = source_max_iter
|
||||
.take(*count_index)
|
||||
.map(|(_, v)| v.into_inner())
|
||||
.collect::<Vec<_>>();
|
||||
values.sort_unstable();
|
||||
max.forced_push_at(i, values.last().unwrap().clone(), exit)?;
|
||||
}
|
||||
|
||||
if let Some(min) = self.min.as_mut() {
|
||||
let source_min_iter = source_min_iter.as_mut().unwrap();
|
||||
source_min_iter.set(first_index);
|
||||
let mut values = source_min_iter
|
||||
.take(*count_index)
|
||||
.map(|(_, v)| v.into_inner())
|
||||
.collect::<Vec<_>>();
|
||||
values.sort_unstable();
|
||||
min.forced_push_at(i, values.first().unwrap().clone(), exit)?;
|
||||
}
|
||||
}
|
||||
|
||||
if needs_average_sum_or_cumulative {
|
||||
if let Some(average) = self.average.as_mut() {
|
||||
let source_average_iter = source_average_iter.as_mut().unwrap();
|
||||
source_average_iter.set(first_index);
|
||||
let values = source_average_iter
|
||||
.take(*count_index)
|
||||
.map(|(_, v)| v.into_inner())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let len = values.len();
|
||||
let cumulative = values.into_iter().fold(T::from(0), |a, b| a + b);
|
||||
// TODO: Multiply by count then divide by cumulative
|
||||
// Right now it's not 100% accurate as there could be more or less elements in the lower timeframe (28 days vs 31 days in a month for example)
|
||||
let avg = cumulative / len;
|
||||
average.forced_push_at(i, avg, exit)?;
|
||||
}
|
||||
|
||||
if needs_sum_or_cumulative {
|
||||
let source_sum_iter = source_sum_iter.as_mut().unwrap();
|
||||
source_sum_iter.set(first_index);
|
||||
let values = source_sum_iter
|
||||
.take(*count_index)
|
||||
.map(|(_, v)| v.into_inner())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let sum = values.into_iter().fold(T::from(0), |a, b| a + b);
|
||||
|
||||
if let Some(sum_vec) = self.sum.as_mut() {
|
||||
sum_vec.forced_push_at(i, sum.clone(), exit)?;
|
||||
}
|
||||
|
||||
if let Some(cumulative_vec) = self.cumulative.as_mut() {
|
||||
let t = cumulative.as_ref().unwrap().clone() + sum;
|
||||
cumulative.replace(t.clone());
|
||||
cumulative_vec.forced_push_at(i, t, exit)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn starting_index(&self, max_from: I) -> I {
|
||||
max_from.min(I::from(
|
||||
self.vecs().into_iter().map(|v| v.len()).min().unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn unwrap_first(&self) -> &EagerVec<I, T> {
|
||||
self.first.as_ref().unwrap()
|
||||
}
|
||||
#[allow(unused)]
|
||||
pub fn unwrap_average(&self) -> &EagerVec<I, T> {
|
||||
self.average.as_ref().unwrap()
|
||||
}
|
||||
pub fn unwrap_sum(&self) -> &EagerVec<I, T> {
|
||||
self.sum.as_ref().unwrap()
|
||||
}
|
||||
pub fn unwrap_max(&self) -> &EagerVec<I, T> {
|
||||
self.max.as_ref().unwrap()
|
||||
}
|
||||
#[allow(unused)]
|
||||
pub fn unwrap_90p(&self) -> &EagerVec<I, T> {
|
||||
self._90p.as_ref().unwrap()
|
||||
}
|
||||
#[allow(unused)]
|
||||
pub fn unwrap_75p(&self) -> &EagerVec<I, T> {
|
||||
self._75p.as_ref().unwrap()
|
||||
}
|
||||
#[allow(unused)]
|
||||
pub fn unwrap_median(&self) -> &EagerVec<I, T> {
|
||||
self.median.as_ref().unwrap()
|
||||
}
|
||||
#[allow(unused)]
|
||||
pub fn unwrap_25p(&self) -> &EagerVec<I, T> {
|
||||
self._25p.as_ref().unwrap()
|
||||
}
|
||||
#[allow(unused)]
|
||||
pub fn unwrap_10p(&self) -> &EagerVec<I, T> {
|
||||
self._10p.as_ref().unwrap()
|
||||
}
|
||||
pub fn unwrap_min(&self) -> &EagerVec<I, T> {
|
||||
self.min.as_ref().unwrap()
|
||||
}
|
||||
pub fn unwrap_last(&self) -> &EagerVec<I, T> {
|
||||
self.last.as_ref().unwrap()
|
||||
}
|
||||
#[allow(unused)]
|
||||
pub fn unwrap_cumulative(&self) -> &EagerVec<I, T> {
|
||||
self.cumulative.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
let mut v: Vec<&dyn AnyCollectableVec> = vec![];
|
||||
|
||||
if let Some(first) = self.first.as_ref() {
|
||||
v.push(first.as_ref());
|
||||
}
|
||||
if let Some(last) = self.last.as_ref() {
|
||||
v.push(last.as_ref());
|
||||
}
|
||||
if let Some(min) = self.min.as_ref() {
|
||||
v.push(min.as_ref());
|
||||
}
|
||||
if let Some(max) = self.max.as_ref() {
|
||||
v.push(max.as_ref());
|
||||
}
|
||||
if let Some(median) = self.median.as_ref() {
|
||||
v.push(median.as_ref());
|
||||
}
|
||||
if let Some(average) = self.average.as_ref() {
|
||||
v.push(average.as_ref());
|
||||
}
|
||||
if let Some(sum) = self.sum.as_ref() {
|
||||
v.push(sum.as_ref());
|
||||
}
|
||||
if let Some(cumulative) = self.cumulative.as_ref() {
|
||||
v.push(cumulative.as_ref());
|
||||
}
|
||||
if let Some(_90p) = self._90p.as_ref() {
|
||||
v.push(_90p.as_ref());
|
||||
}
|
||||
if let Some(_75p) = self._75p.as_ref() {
|
||||
v.push(_75p.as_ref());
|
||||
}
|
||||
if let Some(_25p) = self._25p.as_ref() {
|
||||
v.push(_25p.as_ref());
|
||||
}
|
||||
if let Some(_10p) = self._10p.as_ref() {
|
||||
v.push(_10p.as_ref());
|
||||
}
|
||||
|
||||
v
|
||||
}
|
||||
|
||||
pub fn safe_flush(&mut self, exit: &Exit) -> Result<()> {
|
||||
if let Some(first) = self.first.as_mut() {
|
||||
first.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(last) = self.last.as_mut() {
|
||||
last.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(min) = self.min.as_mut() {
|
||||
min.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(max) = self.max.as_mut() {
|
||||
max.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(median) = self.median.as_mut() {
|
||||
median.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(average) = self.average.as_mut() {
|
||||
average.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(sum) = self.sum.as_mut() {
|
||||
sum.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(cumulative) = self.cumulative.as_mut() {
|
||||
cumulative.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(_90p) = self._90p.as_mut() {
|
||||
_90p.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(_75p) = self._75p.as_mut() {
|
||||
_75p.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(_25p) = self._25p.as_mut() {
|
||||
_25p.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(_10p) = self._10p.as_mut() {
|
||||
_10p.safe_flush(exit)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_computed_version_or_reset_file(&mut self, version: Version) -> Result<()> {
|
||||
if let Some(first) = self.first.as_mut() {
|
||||
first.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
if let Some(last) = self.last.as_mut() {
|
||||
last.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
if let Some(min) = self.min.as_mut() {
|
||||
min.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
if let Some(max) = self.max.as_mut() {
|
||||
max.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
if let Some(median) = self.median.as_mut() {
|
||||
median.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
if let Some(average) = self.average.as_mut() {
|
||||
average.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
if let Some(sum) = self.sum.as_mut() {
|
||||
sum.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
if let Some(cumulative) = self.cumulative.as_mut() {
|
||||
cumulative.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
if let Some(_90p) = self._90p.as_mut() {
|
||||
_90p.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
if let Some(_75p) = self._75p.as_mut() {
|
||||
_75p.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
if let Some(_25p) = self._25p.as_mut() {
|
||||
_25p.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
if let Some(_10p) = self._10p.as_mut() {
|
||||
_10p.validate_computed_version_or_reset_file(Version::ZERO + version)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Copy)]
|
||||
pub struct StorableVecGeneatorOptions {
|
||||
average: bool,
|
||||
sum: bool,
|
||||
max: bool,
|
||||
_90p: bool,
|
||||
_75p: bool,
|
||||
median: bool,
|
||||
_25p: bool,
|
||||
_10p: bool,
|
||||
min: bool,
|
||||
first: bool,
|
||||
last: bool,
|
||||
cumulative: bool,
|
||||
}
|
||||
|
||||
impl StorableVecGeneatorOptions {
|
||||
pub fn add_first(mut self) -> Self {
|
||||
self.first = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_last(mut self) -> Self {
|
||||
self.last = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_min(mut self) -> Self {
|
||||
self.min = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_max(mut self) -> Self {
|
||||
self.max = true;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn add_median(mut self) -> Self {
|
||||
self.median = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_average(mut self) -> Self {
|
||||
self.average = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_sum(mut self) -> Self {
|
||||
self.sum = true;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn add_90p(mut self) -> Self {
|
||||
self._90p = true;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn add_75p(mut self) -> Self {
|
||||
self._75p = true;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn add_25p(mut self) -> Self {
|
||||
self._25p = true;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn add_10p(mut self) -> Self {
|
||||
self._10p = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_cumulative(mut self) -> Self {
|
||||
self.cumulative = true;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_min(mut self) -> Self {
|
||||
self.min = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_max(mut self) -> Self {
|
||||
self.max = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_median(mut self) -> Self {
|
||||
self.median = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_average(mut self) -> Self {
|
||||
self.average = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_sum(mut self) -> Self {
|
||||
self.sum = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_90p(mut self) -> Self {
|
||||
self._90p = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_75p(mut self) -> Self {
|
||||
self._75p = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_25p(mut self) -> Self {
|
||||
self._25p = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_10p(mut self) -> Self {
|
||||
self._10p = false;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rm_cumulative(mut self) -> Self {
|
||||
self.cumulative = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_minmax(mut self) -> Self {
|
||||
self.min = true;
|
||||
self.max = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_percentiles(mut self) -> Self {
|
||||
self._90p = true;
|
||||
self._75p = true;
|
||||
self.median = true;
|
||||
self._25p = true;
|
||||
self._10p = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn remove_percentiles(mut self) -> Self {
|
||||
self._90p = false;
|
||||
self._75p = false;
|
||||
self.median = false;
|
||||
self._25p = false;
|
||||
self._10p = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_only_one_active(&self) -> bool {
|
||||
[
|
||||
self.average,
|
||||
self.sum,
|
||||
self.max,
|
||||
self._90p,
|
||||
self._75p,
|
||||
self.median,
|
||||
self._25p,
|
||||
self._10p,
|
||||
self.min,
|
||||
self.first,
|
||||
self.last,
|
||||
self.cumulative,
|
||||
]
|
||||
.iter()
|
||||
.filter(|b| **b)
|
||||
.count()
|
||||
== 1
|
||||
}
|
||||
|
||||
pub fn copy_self_extra(&self) -> Self {
|
||||
Self {
|
||||
cumulative: self.cumulative,
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{
|
||||
DateIndex, DecadeIndex, MonthIndex, QuarterIndex, Result, Version, WeekIndex, YearIndex,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, AnyIterableVec, EagerVec, Format};
|
||||
|
||||
use crate::vecs::{Indexes, indexes};
|
||||
|
||||
use super::{ComputedType, ComputedVecBuilder, StorableVecGeneatorOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedVecsFromDateIndex<T>
|
||||
where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub dateindex: Option<EagerVec<DateIndex, T>>,
|
||||
pub dateindex_extra: ComputedVecBuilder<DateIndex, T>,
|
||||
pub weekindex: ComputedVecBuilder<WeekIndex, T>,
|
||||
pub monthindex: ComputedVecBuilder<MonthIndex, T>,
|
||||
pub quarterindex: ComputedVecBuilder<QuarterIndex, T>,
|
||||
pub yearindex: ComputedVecBuilder<YearIndex, T>,
|
||||
pub decadeindex: ComputedVecBuilder<DecadeIndex, T>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<T> ComputedVecsFromDateIndex<T>
|
||||
where
|
||||
T: ComputedType,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
compute_source: bool,
|
||||
version: Version,
|
||||
format: Format,
|
||||
options: StorableVecGeneatorOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let dateindex = compute_source.then(|| {
|
||||
EagerVec::forced_import(path, name, version + VERSION + Version::ZERO, format).unwrap()
|
||||
});
|
||||
|
||||
let dateindex_extra = ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options.copy_self_extra(),
|
||||
)?;
|
||||
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
Ok(Self {
|
||||
dateindex,
|
||||
dateindex_extra,
|
||||
weekindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
monthindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
quarterindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
yearindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
decadeindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute_all<F>(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(
|
||||
&mut EagerVec<DateIndex, T>,
|
||||
&Indexer,
|
||||
&indexes::Vecs,
|
||||
&Indexes,
|
||||
&Exit,
|
||||
) -> Result<()>,
|
||||
{
|
||||
compute(
|
||||
self.dateindex.as_mut().unwrap(),
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let dateindex: Option<&EagerVec<DateIndex, T>> = None;
|
||||
self.compute_rest(indexes, starting_indexes, exit, dateindex)
|
||||
}
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
dateindex: Option<&impl AnyIterableVec<DateIndex, T>>,
|
||||
) -> color_eyre::Result<()> {
|
||||
if let Some(dateindex) = dateindex {
|
||||
self.dateindex_extra
|
||||
.extend(starting_indexes.dateindex, dateindex, exit)?;
|
||||
|
||||
self.weekindex.compute(
|
||||
starting_indexes.weekindex,
|
||||
dateindex,
|
||||
&indexes.weekindex_to_first_dateindex,
|
||||
&indexes.weekindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex.compute(
|
||||
starting_indexes.monthindex,
|
||||
dateindex,
|
||||
&indexes.monthindex_to_first_dateindex,
|
||||
&indexes.monthindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
} else {
|
||||
let dateindex = self.dateindex.as_ref().unwrap();
|
||||
|
||||
self.dateindex_extra
|
||||
.extend(starting_indexes.dateindex, dateindex, exit)?;
|
||||
|
||||
self.weekindex.compute(
|
||||
starting_indexes.weekindex,
|
||||
dateindex,
|
||||
&indexes.weekindex_to_first_dateindex,
|
||||
&indexes.weekindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex.compute(
|
||||
starting_indexes.monthindex,
|
||||
dateindex,
|
||||
&indexes.monthindex_to_first_dateindex,
|
||||
&indexes.monthindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
self.quarterindex.from_aligned(
|
||||
starting_indexes.quarterindex,
|
||||
&self.monthindex,
|
||||
&indexes.quarterindex_to_first_monthindex,
|
||||
&indexes.quarterindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex.from_aligned(
|
||||
starting_indexes.yearindex,
|
||||
&self.monthindex,
|
||||
&indexes.yearindex_to_first_monthindex,
|
||||
&indexes.yearindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex.from_aligned(
|
||||
starting_indexes.decadeindex,
|
||||
&self.yearindex,
|
||||
&indexes.decadeindex_to_first_yearindex,
|
||||
&indexes.decadeindex_to_yearindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
[
|
||||
self.dateindex
|
||||
.as_ref()
|
||||
.map_or(vec![], |v| vec![v as &dyn AnyCollectableVec]),
|
||||
self.dateindex_extra.vecs(),
|
||||
self.weekindex.vecs(),
|
||||
self.monthindex.vecs(),
|
||||
self.quarterindex.vecs(),
|
||||
self.yearindex.vecs(),
|
||||
self.decadeindex.vecs(),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{
|
||||
DateIndex, DecadeIndex, DifficultyEpoch, Height, MonthIndex, QuarterIndex, Result, Version,
|
||||
WeekIndex, YearIndex,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, AnyIterableVec, EagerVec, Format};
|
||||
|
||||
use crate::vecs::{Indexes, indexes};
|
||||
|
||||
use super::{ComputedType, ComputedVecBuilder, StorableVecGeneatorOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedVecsFromHeight<T>
|
||||
where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub height: Option<EagerVec<Height, T>>,
|
||||
pub height_extra: ComputedVecBuilder<Height, T>,
|
||||
pub dateindex: ComputedVecBuilder<DateIndex, T>,
|
||||
pub weekindex: ComputedVecBuilder<WeekIndex, T>,
|
||||
pub difficultyepoch: ComputedVecBuilder<DifficultyEpoch, T>,
|
||||
pub monthindex: ComputedVecBuilder<MonthIndex, T>,
|
||||
pub quarterindex: ComputedVecBuilder<QuarterIndex, T>,
|
||||
pub yearindex: ComputedVecBuilder<YearIndex, T>,
|
||||
// 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,
|
||||
format: Format,
|
||||
options: StorableVecGeneatorOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let height = compute_source.then(|| {
|
||||
EagerVec::forced_import(path, name, version + VERSION + Version::ZERO, format).unwrap()
|
||||
});
|
||||
|
||||
let height_extra = ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options.copy_self_extra(),
|
||||
)?;
|
||||
|
||||
let dateindex = ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?;
|
||||
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
Ok(Self {
|
||||
height,
|
||||
height_extra,
|
||||
dateindex,
|
||||
weekindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
difficultyepoch: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
monthindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
quarterindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
yearindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
// halvingepoch: StorableVecGeneator::forced_import(path, name, version + VERSION + Version::ZERO, format, options)?,
|
||||
decadeindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute_all<F>(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(&mut EagerVec<Height, T>, &Indexer, &indexes::Vecs, &Indexes, &Exit) -> Result<()>,
|
||||
{
|
||||
compute(
|
||||
self.height.as_mut().unwrap(),
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let height: Option<&EagerVec<Height, T>> = None;
|
||||
self.compute_rest(indexes, starting_indexes, exit, height)
|
||||
}
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
height: Option<&impl AnyIterableVec<Height, T>>,
|
||||
) -> color_eyre::Result<()> {
|
||||
if let Some(height) = height {
|
||||
self.height_extra
|
||||
.extend(starting_indexes.height, height, exit)?;
|
||||
|
||||
self.dateindex.compute(
|
||||
starting_indexes.dateindex,
|
||||
height,
|
||||
&indexes.dateindex_to_first_height,
|
||||
&indexes.dateindex_to_height_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.difficultyepoch.compute(
|
||||
starting_indexes.difficultyepoch,
|
||||
height,
|
||||
&indexes.difficultyepoch_to_first_height,
|
||||
&indexes.difficultyepoch_to_height_count,
|
||||
exit,
|
||||
)?;
|
||||
} else {
|
||||
let height = self.height.as_ref().unwrap();
|
||||
|
||||
self.height_extra
|
||||
.extend(starting_indexes.height, height, exit)?;
|
||||
|
||||
self.dateindex.compute(
|
||||
starting_indexes.dateindex,
|
||||
height,
|
||||
&indexes.dateindex_to_first_height,
|
||||
&indexes.dateindex_to_height_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.difficultyepoch.compute(
|
||||
starting_indexes.difficultyepoch,
|
||||
height,
|
||||
&indexes.difficultyepoch_to_first_height,
|
||||
&indexes.difficultyepoch_to_height_count,
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
self.weekindex.from_aligned(
|
||||
starting_indexes.weekindex,
|
||||
&self.dateindex,
|
||||
&indexes.weekindex_to_first_dateindex,
|
||||
&indexes.weekindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex.from_aligned(
|
||||
starting_indexes.monthindex,
|
||||
&self.dateindex,
|
||||
&indexes.monthindex_to_first_dateindex,
|
||||
&indexes.monthindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.quarterindex.from_aligned(
|
||||
starting_indexes.quarterindex,
|
||||
&self.monthindex,
|
||||
&indexes.quarterindex_to_first_monthindex,
|
||||
&indexes.quarterindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex.from_aligned(
|
||||
starting_indexes.yearindex,
|
||||
&self.monthindex,
|
||||
&indexes.yearindex_to_first_monthindex,
|
||||
&indexes.yearindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex.from_aligned(
|
||||
starting_indexes.decadeindex,
|
||||
&self.yearindex,
|
||||
&indexes.decadeindex_to_first_yearindex,
|
||||
&indexes.decadeindex_to_yearindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
[
|
||||
self.height
|
||||
.as_ref()
|
||||
.map_or(vec![], |v| vec![v as &dyn AnyCollectableVec]),
|
||||
self.height_extra.vecs(),
|
||||
self.dateindex.vecs(),
|
||||
self.weekindex.vecs(),
|
||||
self.difficultyepoch.vecs(),
|
||||
self.monthindex.vecs(),
|
||||
self.quarterindex.vecs(),
|
||||
self.yearindex.vecs(),
|
||||
// self.halvingepoch.vecs(),
|
||||
self.decadeindex.vecs(),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
+31
-36
@@ -1,11 +1,11 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{Difficultyepoch, Height};
|
||||
use brk_core::{DifficultyEpoch, Height, Result, Version};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyStoredVec, Compressed, Result, Version};
|
||||
use brk_vec::{AnyCollectableVec, EagerVec, Format};
|
||||
|
||||
use crate::storage::vecs::{Indexes, base::ComputedVec, indexes};
|
||||
use crate::vecs::{Indexes, indexes};
|
||||
|
||||
use super::{ComputedType, ComputedVecBuilder, StorableVecGeneatorOptions};
|
||||
|
||||
@@ -14,9 +14,9 @@ pub struct ComputedVecsFromHeightStrict<T>
|
||||
where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub height: ComputedVec<Height, T>,
|
||||
pub height: EagerVec<Height, T>,
|
||||
pub height_extra: ComputedVecBuilder<Height, T>,
|
||||
pub difficultyepoch: ComputedVecBuilder<Difficultyepoch, T>,
|
||||
pub difficultyepoch: ComputedVecBuilder<DifficultyEpoch, T>,
|
||||
// TODO: pub halvingepoch: StorableVecGeneator<Halvingepoch, T>,
|
||||
}
|
||||
|
||||
@@ -31,22 +31,17 @@ where
|
||||
path: &Path,
|
||||
name: &str,
|
||||
version: Version,
|
||||
compressed: Compressed,
|
||||
format: Format,
|
||||
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 =
|
||||
EagerVec::forced_import(path, name, version + VERSION + Version::ZERO, format)?;
|
||||
|
||||
let height_extra = ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version,
|
||||
compressed,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options.copy_self_extra(),
|
||||
)?;
|
||||
|
||||
@@ -56,52 +51,52 @@ where
|
||||
height,
|
||||
height_extra,
|
||||
difficultyepoch: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
// halvingepoch: StorableVecGeneator::forced_import(path, name, version, compressed, options)?,
|
||||
// halvingepoch: StorableVecGeneator::forced_import(path, name, version + VERSION + Version::ZERO, format, options)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute<F>(
|
||||
&mut self,
|
||||
indexer: &mut Indexer,
|
||||
indexes: &mut indexes::Vecs,
|
||||
indexer: &Indexer,
|
||||
indexes: &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<()>,
|
||||
F: FnMut(&mut EagerVec<Height, T>, &Indexer, &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)?;
|
||||
.extend(starting_indexes.height, &self.height, 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(),
|
||||
&self.height,
|
||||
&indexes.difficultyepoch_to_first_height,
|
||||
&indexes.difficultyepoch_to_height_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn any_vecs(&self) -> Vec<&dyn AnyStoredVec> {
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
[
|
||||
vec![self.height.any_vec()],
|
||||
self.height_extra.any_vecs(),
|
||||
self.difficultyepoch.any_vecs(),
|
||||
// self.halvingepoch.as_any_vecs(),
|
||||
vec![&self.height as &dyn AnyCollectableVec],
|
||||
self.height_extra.vecs(),
|
||||
self.difficultyepoch.vecs(),
|
||||
// self.halvingepoch.vecs(),
|
||||
]
|
||||
.concat()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,629 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{
|
||||
Bitcoin, DateIndex, DecadeIndex, DifficultyEpoch, Dollars, Height, MonthIndex, QuarterIndex,
|
||||
Result, Sats, TxIndex, Version, WeekIndex, YearIndex,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{
|
||||
AnyCollectableVec, AnyVec, CollectableVec, EagerVec, Format, StoredIndex, VecIterator,
|
||||
};
|
||||
|
||||
use crate::vecs::{Indexes, fetched, indexes};
|
||||
|
||||
use super::{ComputedType, ComputedVecBuilder, StorableVecGeneatorOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedVecsFromTxindex<T>
|
||||
where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub txindex: Option<Box<EagerVec<TxIndex, T>>>,
|
||||
pub height: ComputedVecBuilder<Height, T>,
|
||||
pub dateindex: ComputedVecBuilder<DateIndex, T>,
|
||||
pub weekindex: ComputedVecBuilder<WeekIndex, T>,
|
||||
pub difficultyepoch: ComputedVecBuilder<DifficultyEpoch, T>,
|
||||
pub monthindex: ComputedVecBuilder<MonthIndex, T>,
|
||||
pub quarterindex: ComputedVecBuilder<QuarterIndex, T>,
|
||||
pub yearindex: ComputedVecBuilder<YearIndex, T>,
|
||||
// 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,
|
||||
format: Format,
|
||||
options: StorableVecGeneatorOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let txindex = compute_source.then(|| {
|
||||
Box::new(
|
||||
EagerVec::forced_import(path, name, version + VERSION + Version::ZERO, format)
|
||||
.unwrap(),
|
||||
)
|
||||
});
|
||||
|
||||
let height = ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?;
|
||||
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
Ok(Self {
|
||||
txindex,
|
||||
height,
|
||||
dateindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
weekindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
difficultyepoch: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
monthindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
quarterindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
yearindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
// halvingepoch: StorableVecGeneator::forced_import(path, name, version + VERSION + Version::ZERO, format, options)?,
|
||||
decadeindex: ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
// #[allow(unused)]
|
||||
// pub fn compute_all<F>(
|
||||
// &mut self,
|
||||
// indexer: &Indexer,
|
||||
// indexes: &indexes::Vecs,
|
||||
// starting_indexes: &Indexes,
|
||||
// exit: &Exit,
|
||||
// mut compute: F,
|
||||
// ) -> color_eyre::Result<()>
|
||||
// where
|
||||
// F: FnMut(
|
||||
// &mut EagerVec<TxIndex, T>,
|
||||
// &Indexer,
|
||||
// &indexes::Vecs,
|
||||
// &Indexes,
|
||||
// &Exit,
|
||||
// ) -> Result<()>,
|
||||
// {
|
||||
// compute(
|
||||
// self.txindex.as_mut().unwrap(),
|
||||
// indexer,
|
||||
// indexes,
|
||||
// starting_indexes,
|
||||
// exit,
|
||||
// )?;
|
||||
|
||||
// let txindex: Option<&StoredVec<TxIndex, T>> = None;
|
||||
// self.compute_rest(indexer, indexes, starting_indexes, exit, txindex)?;
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
txindex: Option<&impl CollectableVec<TxIndex, T>>,
|
||||
) -> Result<()> {
|
||||
if let Some(txindex) = txindex {
|
||||
self.height.compute(
|
||||
starting_indexes.height,
|
||||
txindex,
|
||||
&indexer.vecs().height_to_first_txindex,
|
||||
&indexes.height_to_txindex_count,
|
||||
exit,
|
||||
)?;
|
||||
} else {
|
||||
let txindex = self.txindex.as_ref().unwrap().as_ref();
|
||||
|
||||
self.height.compute(
|
||||
starting_indexes.height,
|
||||
txindex,
|
||||
&indexer.vecs().height_to_first_txindex,
|
||||
&indexes.height_to_txindex_count,
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
self.compute_after_height(indexes, starting_indexes, exit)
|
||||
}
|
||||
|
||||
fn compute_after_height(
|
||||
&mut self,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.dateindex.from_aligned(
|
||||
starting_indexes.dateindex,
|
||||
&self.height,
|
||||
&indexes.dateindex_to_first_height,
|
||||
&indexes.dateindex_to_height_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.weekindex.from_aligned(
|
||||
starting_indexes.weekindex,
|
||||
&self.dateindex,
|
||||
&indexes.weekindex_to_first_dateindex,
|
||||
&indexes.weekindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex.from_aligned(
|
||||
starting_indexes.monthindex,
|
||||
&self.dateindex,
|
||||
&indexes.monthindex_to_first_dateindex,
|
||||
&indexes.monthindex_to_dateindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.quarterindex.from_aligned(
|
||||
starting_indexes.quarterindex,
|
||||
&self.monthindex,
|
||||
&indexes.quarterindex_to_first_monthindex,
|
||||
&indexes.quarterindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex.from_aligned(
|
||||
starting_indexes.yearindex,
|
||||
&self.monthindex,
|
||||
&indexes.yearindex_to_first_monthindex,
|
||||
&indexes.yearindex_to_monthindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex.from_aligned(
|
||||
starting_indexes.decadeindex,
|
||||
&self.yearindex,
|
||||
&indexes.decadeindex_to_first_yearindex,
|
||||
&indexes.decadeindex_to_yearindex_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.difficultyepoch.from_aligned(
|
||||
starting_indexes.difficultyepoch,
|
||||
&self.height,
|
||||
&indexes.difficultyepoch_to_first_height,
|
||||
&indexes.difficultyepoch_to_height_count,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
[
|
||||
self.txindex
|
||||
.as_ref()
|
||||
.map_or(vec![], |v| vec![v.as_ref() as &dyn AnyCollectableVec]),
|
||||
self.height.vecs(),
|
||||
self.dateindex.vecs(),
|
||||
self.weekindex.vecs(),
|
||||
self.difficultyepoch.vecs(),
|
||||
self.monthindex.vecs(),
|
||||
self.quarterindex.vecs(),
|
||||
self.yearindex.vecs(),
|
||||
// self.halvingepoch.vecs(),
|
||||
self.decadeindex.vecs(),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
|
||||
impl ComputedVecsFromTxindex<Bitcoin> {
|
||||
pub fn compute_rest_from_sats(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
sats: &ComputedVecsFromTxindex<Sats>,
|
||||
txindex: Option<&impl CollectableVec<TxIndex, Bitcoin>>,
|
||||
) -> Result<()> {
|
||||
let txindex_version = if let Some(txindex) = txindex {
|
||||
txindex.version()
|
||||
} else {
|
||||
self.txindex.as_ref().unwrap().as_ref().version()
|
||||
};
|
||||
|
||||
self.height
|
||||
.validate_computed_version_or_reset_file(txindex_version)?;
|
||||
|
||||
let starting_index = self.height.starting_index(starting_indexes.height);
|
||||
|
||||
(starting_index.unwrap_to_usize()..indexer.vecs().height_to_weight.len())
|
||||
.map(Height::from)
|
||||
.try_for_each(|height| -> Result<()> {
|
||||
if let Some(first) = self.height.first.as_mut() {
|
||||
first.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_first()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(average) = self.height.average.as_mut() {
|
||||
average.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_average()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(sum) = self.height.sum.as_mut() {
|
||||
sum.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_sum()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(max) = self.height.max.as_mut() {
|
||||
max.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_max()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(_90p) = self.height._90p.as_mut() {
|
||||
_90p.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_90p()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(_75p) = self.height._75p.as_mut() {
|
||||
_75p.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_75p()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(median) = self.height.median.as_mut() {
|
||||
median.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_median()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(_25p) = self.height._25p.as_mut() {
|
||||
_25p.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_25p()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(_10p) = self.height._10p.as_mut() {
|
||||
_10p.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_10p()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(min) = self.height.min.as_mut() {
|
||||
min.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_min()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(last) = self.height.last.as_mut() {
|
||||
last.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_last()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(cumulative) = self.height.cumulative.as_mut() {
|
||||
cumulative.forced_push_at(
|
||||
height,
|
||||
Bitcoin::from(
|
||||
sats.height
|
||||
.unwrap_cumulative()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.height.safe_flush(exit)?;
|
||||
|
||||
self.compute_after_height(indexes, starting_indexes, exit)
|
||||
}
|
||||
}
|
||||
|
||||
impl ComputedVecsFromTxindex<Dollars> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn compute_rest_from_bitcoin(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
bitcoin: &ComputedVecsFromTxindex<Bitcoin>,
|
||||
txindex: Option<&impl CollectableVec<TxIndex, Dollars>>,
|
||||
fetched: &fetched::Vecs,
|
||||
) -> Result<()> {
|
||||
let txindex_version = if let Some(txindex) = txindex {
|
||||
txindex.version()
|
||||
} else {
|
||||
self.txindex.as_ref().unwrap().as_ref().version()
|
||||
};
|
||||
|
||||
self.height
|
||||
.validate_computed_version_or_reset_file(txindex_version)?;
|
||||
|
||||
let starting_index = self.height.starting_index(starting_indexes.height);
|
||||
|
||||
let mut close_iter = fetched.chainindexes_to_close.height.into_iter();
|
||||
|
||||
(starting_index.unwrap_to_usize()..indexer.vecs().height_to_weight.len())
|
||||
.map(Height::from)
|
||||
.try_for_each(|height| -> Result<()> {
|
||||
let price = *close_iter.unwrap_get_inner(height);
|
||||
|
||||
if let Some(first) = self.height.first.as_mut() {
|
||||
first.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_first()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(average) = self.height.average.as_mut() {
|
||||
average.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_average()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(sum) = self.height.sum.as_mut() {
|
||||
sum.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_sum()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(max) = self.height.max.as_mut() {
|
||||
max.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_max()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(_90p) = self.height._90p.as_mut() {
|
||||
_90p.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_90p()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(_75p) = self.height._75p.as_mut() {
|
||||
_75p.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_75p()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(median) = self.height.median.as_mut() {
|
||||
median.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_median()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(_25p) = self.height._25p.as_mut() {
|
||||
_25p.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_25p()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(_10p) = self.height._10p.as_mut() {
|
||||
_10p.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_10p()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(min) = self.height.min.as_mut() {
|
||||
min.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_min()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(last) = self.height.last.as_mut() {
|
||||
last.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_last()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
if let Some(cumulative) = self.height.cumulative.as_mut() {
|
||||
cumulative.forced_push_at(
|
||||
height,
|
||||
price
|
||||
* bitcoin
|
||||
.height
|
||||
.unwrap_cumulative()
|
||||
.into_iter()
|
||||
.unwrap_get_inner(height),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.height.safe_flush(exit)?;
|
||||
|
||||
self.compute_after_height(indexes, starting_indexes, exit)
|
||||
}
|
||||
}
|
||||
+8
-2
@@ -3,15 +3,21 @@ mod from_dateindex;
|
||||
mod from_height;
|
||||
mod from_height_strict;
|
||||
mod from_txindex;
|
||||
mod stored_type;
|
||||
mod ratio_from_dateindex;
|
||||
mod r#type;
|
||||
mod value_from_dateindex;
|
||||
mod value_from_height;
|
||||
mod value_from_txindex;
|
||||
mod value_height;
|
||||
|
||||
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 ratio_from_dateindex::*;
|
||||
use r#type::*;
|
||||
pub use value_from_dateindex::*;
|
||||
pub use value_from_height::*;
|
||||
pub use value_from_txindex::*;
|
||||
pub use value_height::*;
|
||||
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -4,10 +4,10 @@ use brk_vec::StoredType;
|
||||
|
||||
pub trait ComputedType
|
||||
where
|
||||
Self: StoredType + From<usize> + Div<usize, Output = Self> + Add<Output = Self>,
|
||||
Self: StoredType + From<usize> + Div<usize, Output = Self> + Add<Output = Self> + Ord,
|
||||
{
|
||||
}
|
||||
impl<T> ComputedType for T where
|
||||
T: StoredType + From<usize> + Div<usize, Output = Self> + Add<Output = Self>
|
||||
T: StoredType + From<usize> + Div<usize, Output = Self> + Add<Output = Self> + Ord
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{Bitcoin, DateIndex, Dollars, Result, Sats, Version};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, CollectableVec, EagerVec, Format, StoredVec};
|
||||
|
||||
use crate::vecs::{Indexes, fetched, grouped::ComputedVecsFromDateIndex, indexes};
|
||||
|
||||
use super::StorableVecGeneatorOptions;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedValueVecsFromDateIndex {
|
||||
pub sats: ComputedVecsFromDateIndex<Sats>,
|
||||
pub bitcoin: ComputedVecsFromDateIndex<Bitcoin>,
|
||||
pub dollars: Option<ComputedVecsFromDateIndex<Dollars>>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl ComputedValueVecsFromDateIndex {
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
compute_source: bool,
|
||||
version: Version,
|
||||
format: Format,
|
||||
options: StorableVecGeneatorOptions,
|
||||
compute_dollars: bool,
|
||||
) -> color_eyre::Result<Self> {
|
||||
Ok(Self {
|
||||
sats: ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
name,
|
||||
compute_source,
|
||||
version + VERSION,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
bitcoin: ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
&format!("{name}_in_btc"),
|
||||
true,
|
||||
version + VERSION,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
dollars: compute_dollars.then(|| {
|
||||
ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
&format!("{name}_in_usd"),
|
||||
true,
|
||||
version + VERSION,
|
||||
format,
|
||||
options,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute_all<F>(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(
|
||||
&mut EagerVec<DateIndex, Sats>,
|
||||
&Indexer,
|
||||
&indexes::Vecs,
|
||||
&Indexes,
|
||||
&Exit,
|
||||
) -> Result<()>,
|
||||
{
|
||||
compute(
|
||||
self.sats.dateindex.as_mut().unwrap(),
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let dateindex: Option<&StoredVec<DateIndex, Sats>> = None;
|
||||
self.compute_rest(indexer, indexes, fetched, starting_indexes, exit, dateindex)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
dateindex: Option<&impl CollectableVec<DateIndex, Sats>>,
|
||||
) -> color_eyre::Result<()> {
|
||||
if let Some(dateindex) = dateindex {
|
||||
self.sats
|
||||
.compute_rest(indexes, starting_indexes, exit, Some(dateindex))?;
|
||||
|
||||
self.bitcoin.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, _, _, starting_indexes, exit| {
|
||||
v.compute_from_sats(starting_indexes.dateindex, dateindex, exit)
|
||||
},
|
||||
)?;
|
||||
} else {
|
||||
let dateindex: Option<&StoredVec<DateIndex, Sats>> = None;
|
||||
|
||||
self.sats
|
||||
.compute_rest(indexes, starting_indexes, exit, dateindex)?;
|
||||
|
||||
self.bitcoin.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, _, _, starting_indexes, exit| {
|
||||
v.compute_from_sats(
|
||||
starting_indexes.dateindex,
|
||||
self.sats.dateindex.as_ref().unwrap(),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
let dateindex_to_bitcoin = self.bitcoin.dateindex.as_ref().unwrap();
|
||||
let dateindex_to_close = fetched
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.timeindexes_to_close
|
||||
.dateindex
|
||||
.as_ref()
|
||||
.unwrap();
|
||||
|
||||
if let Some(dollars) = self.dollars.as_mut() {
|
||||
dollars.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, _, _, starting_indexes, exit| {
|
||||
v.compute_from_bitcoin(
|
||||
starting_indexes.dateindex,
|
||||
dateindex_to_bitcoin,
|
||||
dateindex_to_close,
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
[
|
||||
self.sats.vecs(),
|
||||
self.bitcoin.vecs(),
|
||||
self.dollars.as_ref().map_or(vec![], |v| v.vecs()),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{Bitcoin, Dollars, Height, Result, Sats, Version};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, CollectableVec, EagerVec, Format, StoredVec};
|
||||
|
||||
use crate::vecs::{Indexes, fetched, 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::ZERO;
|
||||
|
||||
impl ComputedValueVecsFromHeight {
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
compute_source: bool,
|
||||
version: Version,
|
||||
format: Format,
|
||||
options: StorableVecGeneatorOptions,
|
||||
compute_dollars: bool,
|
||||
) -> color_eyre::Result<Self> {
|
||||
Ok(Self {
|
||||
sats: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
name,
|
||||
compute_source,
|
||||
version + VERSION,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
bitcoin: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
&format!("{name}_in_btc"),
|
||||
true,
|
||||
version + VERSION,
|
||||
format,
|
||||
options,
|
||||
)?,
|
||||
dollars: compute_dollars.then(|| {
|
||||
ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
&format!("{name}_in_usd"),
|
||||
true,
|
||||
version + VERSION,
|
||||
format,
|
||||
options,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute_all<F>(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(
|
||||
&mut EagerVec<Height, Sats>,
|
||||
&Indexer,
|
||||
&indexes::Vecs,
|
||||
&Indexes,
|
||||
&Exit,
|
||||
) -> Result<()>,
|
||||
{
|
||||
compute(
|
||||
self.sats.height.as_mut().unwrap(),
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let height: Option<&StoredVec<Height, Sats>> = None;
|
||||
self.compute_rest(indexer, indexes, fetched, starting_indexes, exit, height)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
height: Option<&impl CollectableVec<Height, Sats>>,
|
||||
) -> color_eyre::Result<()> {
|
||||
if let Some(height) = height {
|
||||
self.sats
|
||||
.compute_rest(indexes, starting_indexes, exit, Some(height))?;
|
||||
|
||||
self.bitcoin.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, _, _, starting_indexes, exit| {
|
||||
v.compute_from_sats(starting_indexes.height, height, exit)
|
||||
},
|
||||
)?;
|
||||
} else {
|
||||
let height: Option<&StoredVec<Height, Sats>> = None;
|
||||
|
||||
self.sats
|
||||
.compute_rest(indexes, starting_indexes, exit, height)?;
|
||||
|
||||
self.bitcoin.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, _, _, starting_indexes, exit| {
|
||||
v.compute_from_sats(
|
||||
starting_indexes.height,
|
||||
self.sats.height.as_ref().unwrap(),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
let height_to_bitcoin = self.bitcoin.height.as_ref().unwrap();
|
||||
let height_to_close = &fetched.as_ref().unwrap().chainindexes_to_close.height;
|
||||
|
||||
if let Some(dollars) = self.dollars.as_mut() {
|
||||
dollars.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, _, _, starting_indexes, exit| {
|
||||
v.compute_from_bitcoin(
|
||||
starting_indexes.height,
|
||||
height_to_bitcoin,
|
||||
height_to_close,
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
[
|
||||
self.sats.vecs(),
|
||||
self.bitcoin.vecs(),
|
||||
self.dollars.as_ref().map_or(vec![], |v| v.vecs()),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{Bitcoin, Close, Dollars, Height, Sats, TxIndex, Version};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{
|
||||
AnyCollectableVec, BoxedAnyIterableVec, CloneableAnyIterableVec, CollectableVec, Computation,
|
||||
ComputedVecFrom3, Format, LazyVecFrom1, StoredIndex, StoredVec,
|
||||
};
|
||||
|
||||
use crate::vecs::{Indexes, fetched, indexes};
|
||||
|
||||
use super::{ComputedVecsFromTxindex, StorableVecGeneatorOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedValueVecsFromTxindex {
|
||||
pub sats: ComputedVecsFromTxindex<Sats>,
|
||||
pub bitcoin_txindex: LazyVecFrom1<TxIndex, Bitcoin, TxIndex, Sats>,
|
||||
pub bitcoin: ComputedVecsFromTxindex<Bitcoin>,
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub dollars_txindex: Option<
|
||||
ComputedVecFrom3<
|
||||
TxIndex,
|
||||
Dollars,
|
||||
TxIndex,
|
||||
Bitcoin,
|
||||
TxIndex,
|
||||
Height,
|
||||
Height,
|
||||
Close<Dollars>,
|
||||
>,
|
||||
>,
|
||||
pub dollars: Option<ComputedVecsFromTxindex<Dollars>>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl ComputedValueVecsFromTxindex {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
indexes: &indexes::Vecs,
|
||||
source: Option<BoxedAnyIterableVec<TxIndex, Sats>>,
|
||||
version: Version,
|
||||
computation: Computation,
|
||||
format: Format,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
options: StorableVecGeneatorOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let compute_source = source.is_none();
|
||||
let compute_dollars = fetched.is_some();
|
||||
|
||||
let name_in_btc = format!("{name}_in_btc");
|
||||
let name_in_usd = format!("{name}_in_usd");
|
||||
|
||||
let sats = ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
name,
|
||||
compute_source,
|
||||
version + VERSION,
|
||||
format,
|
||||
options,
|
||||
)?;
|
||||
|
||||
let bitcoin_txindex = LazyVecFrom1::init(
|
||||
&name_in_btc,
|
||||
version + VERSION,
|
||||
source.map_or_else(|| sats.txindex.as_ref().unwrap().boxed_clone(), |s| s),
|
||||
|txindex: TxIndex, iter| {
|
||||
iter.next_at(txindex.unwrap_to_usize()).map(|(_, value)| {
|
||||
let sats = value.into_inner();
|
||||
Bitcoin::from(sats)
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
let bitcoin = ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
&name_in_btc,
|
||||
false,
|
||||
version + VERSION,
|
||||
format,
|
||||
options,
|
||||
)?;
|
||||
|
||||
let dollars_txindex = fetched.map(|fetched| {
|
||||
ComputedVecFrom3::forced_import_or_init_from_3(
|
||||
computation,
|
||||
path,
|
||||
&name_in_usd,
|
||||
version + VERSION,
|
||||
format,
|
||||
bitcoin_txindex.boxed_clone(),
|
||||
indexes.txindex_to_height.boxed_clone(),
|
||||
fetched.chainindexes_to_close.height.boxed_clone(),
|
||||
|txindex: TxIndex,
|
||||
txindex_to_btc_iter,
|
||||
txindex_to_height_iter,
|
||||
height_to_close_iter| {
|
||||
let txindex = txindex.unwrap_to_usize();
|
||||
txindex_to_btc_iter.next_at(txindex).and_then(|(_, value)| {
|
||||
let btc = value.into_inner();
|
||||
txindex_to_height_iter
|
||||
.next_at(txindex)
|
||||
.and_then(|(_, value)| {
|
||||
let height = value.into_inner();
|
||||
height_to_close_iter
|
||||
.next_at(height.unwrap_to_usize())
|
||||
.map(|(_, close)| *close.into_inner() * btc)
|
||||
})
|
||||
})
|
||||
},
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
Ok(Self {
|
||||
sats,
|
||||
bitcoin_txindex,
|
||||
bitcoin,
|
||||
dollars_txindex,
|
||||
dollars: compute_dollars.then(|| {
|
||||
ComputedVecsFromTxindex::forced_import(
|
||||
path,
|
||||
&name_in_usd,
|
||||
false,
|
||||
version + VERSION,
|
||||
format,
|
||||
options,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
// pub fn compute_all<F>(
|
||||
// &mut self,
|
||||
// indexer: &Indexer,
|
||||
// indexes: &indexes::Vecs,
|
||||
// fetched: Option<&marketprice::Vecs>,
|
||||
// starting_indexes: &Indexes,
|
||||
// exit: &Exit,
|
||||
// mut compute: F,
|
||||
// ) -> color_eyre::Result<()>
|
||||
// where
|
||||
// F: FnMut(
|
||||
// &mut EagerVec<TxIndex, Sats>,
|
||||
// &Indexer,
|
||||
// &indexes::Vecs,
|
||||
// &Indexes,
|
||||
// &Exit,
|
||||
// ) -> Result<()>,
|
||||
// {
|
||||
// compute(
|
||||
// self.sats.txindex.as_mut().unwrap(),
|
||||
// indexer,
|
||||
// indexes,
|
||||
// starting_indexes,
|
||||
// exit,
|
||||
// )?;
|
||||
|
||||
// let txindex: Option<&StoredVec<TxIndex, Sats>> = None;
|
||||
// self.compute_rest(
|
||||
// indexer,
|
||||
// indexes,
|
||||
// fetched,
|
||||
// starting_indexes,
|
||||
// exit,
|
||||
// txindex,
|
||||
// )?;
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
txindex: Option<&impl CollectableVec<TxIndex, Sats>>,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
) -> color_eyre::Result<()> {
|
||||
if let Some(txindex) = txindex {
|
||||
self.sats
|
||||
.compute_rest(indexer, indexes, starting_indexes, exit, Some(txindex))?;
|
||||
} else {
|
||||
let txindex: Option<&StoredVec<TxIndex, Sats>> = None;
|
||||
self.sats
|
||||
.compute_rest(indexer, indexes, starting_indexes, exit, txindex)?;
|
||||
}
|
||||
|
||||
self.bitcoin.compute_rest_from_sats(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
&self.sats,
|
||||
Some(&self.bitcoin_txindex),
|
||||
)?;
|
||||
|
||||
if let Some(dollars) = self.dollars.as_mut() {
|
||||
let dollars_txindex = self.dollars_txindex.as_mut().unwrap();
|
||||
|
||||
dollars_txindex.compute_if_necessary(
|
||||
starting_indexes.txindex,
|
||||
&indexer.vecs().txindex_to_txid,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
dollars.compute_rest_from_bitcoin(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
&self.bitcoin,
|
||||
Some(dollars_txindex),
|
||||
fetched.as_ref().unwrap(),
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
[
|
||||
self.sats.vecs(),
|
||||
self.bitcoin.vecs(),
|
||||
self.dollars.as_ref().map_or(vec![], |v| v.vecs()),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{Bitcoin, Dollars, Height, Result, Sats, Version};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, CollectableVec, EagerVec, Format, StoredVec};
|
||||
|
||||
use crate::vecs::{Indexes, fetched, indexes};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedHeightValueVecs {
|
||||
pub sats: Option<EagerVec<Height, Sats>>,
|
||||
pub bitcoin: EagerVec<Height, Bitcoin>,
|
||||
pub dollars: Option<EagerVec<Height, Dollars>>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl ComputedHeightValueVecs {
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
compute_source: bool,
|
||||
version: Version,
|
||||
format: Format,
|
||||
compute_dollars: bool,
|
||||
) -> color_eyre::Result<Self> {
|
||||
Ok(Self {
|
||||
sats: compute_source.then(|| {
|
||||
EagerVec::forced_import(path, name, version + VERSION + Version::ZERO, format)
|
||||
.unwrap()
|
||||
}),
|
||||
bitcoin: EagerVec::forced_import(
|
||||
path,
|
||||
&format!("{name}_in_btc"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)?,
|
||||
dollars: compute_dollars.then(|| {
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&format!("{name}_in_usd"),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute_all<F>(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(
|
||||
&mut EagerVec<Height, Sats>,
|
||||
&Indexer,
|
||||
&indexes::Vecs,
|
||||
&Indexes,
|
||||
&Exit,
|
||||
) -> Result<()>,
|
||||
{
|
||||
compute(
|
||||
self.sats.as_mut().unwrap(),
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let height: Option<&StoredVec<Height, Sats>> = None;
|
||||
self.compute_rest(fetched, starting_indexes, exit, height)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
fetched: Option<&fetched::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
height: Option<&impl CollectableVec<Height, Sats>>,
|
||||
) -> color_eyre::Result<()> {
|
||||
if let Some(height) = height {
|
||||
self.bitcoin
|
||||
.compute_from_sats(starting_indexes.height, height, exit)?;
|
||||
} else {
|
||||
self.bitcoin.compute_from_sats(
|
||||
starting_indexes.height,
|
||||
self.sats.as_ref().unwrap(),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
let height_to_bitcoin = &self.bitcoin;
|
||||
let height_to_close = &fetched.as_ref().unwrap().chainindexes_to_close.height;
|
||||
|
||||
if let Some(dollars) = self.dollars.as_mut() {
|
||||
dollars.compute_from_bitcoin(
|
||||
starting_indexes.height,
|
||||
height_to_bitcoin,
|
||||
height_to_close,
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
[
|
||||
vec![&self.bitcoin as &dyn AnyCollectableVec],
|
||||
self.sats.as_ref().map_or(vec![], |v| vec![v]),
|
||||
self.dollars.as_ref().map_or(vec![], |v| vec![v]),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,135 @@
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use brk_core::{DifficultyEpoch, HalvingEpoch, StoredF64, Version};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, Computation, Format, VecIterator};
|
||||
|
||||
use super::{
|
||||
Indexes,
|
||||
grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, StorableVecGeneatorOptions},
|
||||
indexes,
|
||||
};
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vecs {
|
||||
pub indexes_to_difficulty: ComputedVecsFromHeight<StoredF64>,
|
||||
pub indexes_to_difficultyepoch: ComputedVecsFromDateIndex<DifficultyEpoch>,
|
||||
pub indexes_to_halvingepoch: ComputedVecsFromDateIndex<HalvingEpoch>,
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
version: Version,
|
||||
_computation: Computation,
|
||||
format: Format,
|
||||
) -> color_eyre::Result<Self> {
|
||||
fs::create_dir_all(path)?;
|
||||
|
||||
Ok(Self {
|
||||
indexes_to_difficulty: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"difficulty",
|
||||
false,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
)?,
|
||||
indexes_to_difficultyepoch: ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
"difficultyepoch",
|
||||
true,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
)?,
|
||||
indexes_to_halvingepoch: ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
"halvingepoch",
|
||||
true,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
let mut height_to_difficultyepoch_iter = indexes.height_to_difficultyepoch.into_iter();
|
||||
self.indexes_to_difficultyepoch.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|vec, _, indexes, starting_indexes, exit| {
|
||||
let mut height_count_iter = indexes.dateindex_to_height_count.into_iter();
|
||||
vec.compute_transform(
|
||||
starting_indexes.dateindex,
|
||||
&indexes.dateindex_to_first_height,
|
||||
|(di, height, ..)| {
|
||||
(
|
||||
di,
|
||||
height_to_difficultyepoch_iter.unwrap_get_inner(
|
||||
height + (*height_count_iter.unwrap_get_inner(di) - 1),
|
||||
),
|
||||
)
|
||||
},
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
let mut height_to_halvingepoch_iter = indexes.height_to_halvingepoch.into_iter();
|
||||
self.indexes_to_halvingepoch.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|vec, _, indexes, starting_indexes, exit| {
|
||||
let mut height_count_iter = indexes.dateindex_to_height_count.into_iter();
|
||||
vec.compute_transform(
|
||||
starting_indexes.dateindex,
|
||||
&indexes.dateindex_to_first_height,
|
||||
|(di, height, ..)| {
|
||||
(
|
||||
di,
|
||||
height_to_halvingepoch_iter.unwrap_get_inner(
|
||||
height + (*height_count_iter.unwrap_get_inner(di) - 1),
|
||||
),
|
||||
)
|
||||
},
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
self.indexes_to_difficulty.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(&indexer.vecs().height_to_difficulty),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
[
|
||||
self.indexes_to_difficulty.vecs(),
|
||||
self.indexes_to_difficultyepoch.vecs(),
|
||||
self.indexes_to_halvingepoch.vecs(),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use brk_core::Version;
|
||||
use brk_exit::Exit;
|
||||
use brk_fetcher::Fetcher;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyCollectableVec, Computation, Format};
|
||||
|
||||
pub mod blocks;
|
||||
pub mod constants;
|
||||
pub mod fetched;
|
||||
pub mod grouped;
|
||||
pub mod indexes;
|
||||
pub mod market;
|
||||
pub mod mining;
|
||||
pub mod stateful;
|
||||
pub mod transactions;
|
||||
|
||||
pub use indexes::Indexes;
|
||||
use log::info;
|
||||
|
||||
const VERSION: Version = Version::ONE;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vecs {
|
||||
pub indexes: indexes::Vecs,
|
||||
pub constants: constants::Vecs,
|
||||
pub blocks: blocks::Vecs,
|
||||
pub mining: mining::Vecs,
|
||||
pub market: market::Vecs,
|
||||
pub transactions: transactions::Vecs,
|
||||
pub stateful: stateful::Vecs,
|
||||
pub fetched: Option<fetched::Vecs>,
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
pub fn import(
|
||||
path: &Path,
|
||||
version: Version,
|
||||
indexer: &Indexer,
|
||||
fetch: bool,
|
||||
computation: Computation,
|
||||
format: Format,
|
||||
) -> color_eyre::Result<Self> {
|
||||
fs::create_dir_all(path)?;
|
||||
|
||||
let indexes = indexes::Vecs::forced_import(
|
||||
path,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexer,
|
||||
computation,
|
||||
format,
|
||||
)?;
|
||||
|
||||
let fetched = fetch.then(|| {
|
||||
fetched::Vecs::forced_import(
|
||||
path,
|
||||
version + VERSION + Version::ZERO,
|
||||
computation,
|
||||
format,
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
Ok(Self {
|
||||
blocks: blocks::Vecs::forced_import(
|
||||
path,
|
||||
version + VERSION + Version::ZERO,
|
||||
computation,
|
||||
format,
|
||||
)?,
|
||||
mining: mining::Vecs::forced_import(
|
||||
path,
|
||||
version + VERSION + Version::ZERO,
|
||||
computation,
|
||||
format,
|
||||
)?,
|
||||
constants: constants::Vecs::forced_import(
|
||||
path,
|
||||
version + VERSION + Version::ZERO,
|
||||
computation,
|
||||
format,
|
||||
)?,
|
||||
market: market::Vecs::forced_import(
|
||||
path,
|
||||
version + VERSION + Version::ZERO,
|
||||
computation,
|
||||
format,
|
||||
)?,
|
||||
stateful: stateful::Vecs::forced_import(
|
||||
path,
|
||||
version + VERSION + Version::ZERO,
|
||||
computation,
|
||||
format,
|
||||
fetched.as_ref(),
|
||||
)?,
|
||||
transactions: transactions::Vecs::forced_import(
|
||||
path,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexer,
|
||||
&indexes,
|
||||
computation,
|
||||
format,
|
||||
fetched.as_ref(),
|
||||
)?,
|
||||
indexes,
|
||||
fetched,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
starting_indexes: brk_indexer::Indexes,
|
||||
fetcher: Option<&mut Fetcher>,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
let starting_indexes = self.indexes.compute(indexer, starting_indexes, exit)?;
|
||||
|
||||
info!("Computing constants...");
|
||||
self.constants
|
||||
.compute(indexer, &self.indexes, &starting_indexes, exit)?;
|
||||
|
||||
info!("Computing blocks...");
|
||||
self.blocks
|
||||
.compute(indexer, &self.indexes, &starting_indexes, exit)?;
|
||||
|
||||
info!("Computing mining...");
|
||||
self.mining
|
||||
.compute(indexer, &self.indexes, &starting_indexes, exit)?;
|
||||
|
||||
if let Some(fetched) = self.fetched.as_mut() {
|
||||
info!("Computing fetched...");
|
||||
fetched.compute(
|
||||
indexer,
|
||||
&self.indexes,
|
||||
&starting_indexes,
|
||||
fetcher.unwrap(),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
info!("Computing transactions...");
|
||||
self.transactions.compute(
|
||||
indexer,
|
||||
&self.indexes,
|
||||
&starting_indexes,
|
||||
self.fetched.as_ref(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
if let Some(fetched) = self.fetched.as_ref() {
|
||||
info!("Computing market...");
|
||||
self.market.compute(
|
||||
indexer,
|
||||
&self.indexes,
|
||||
fetched,
|
||||
&mut self.transactions,
|
||||
&starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
info!("Computing stateful...");
|
||||
self.stateful.compute(
|
||||
indexer,
|
||||
&self.indexes,
|
||||
&self.transactions,
|
||||
self.fetched.as_ref(),
|
||||
&self.market,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
|
||||
[
|
||||
self.constants.vecs(),
|
||||
self.indexes.vecs(),
|
||||
self.blocks.vecs(),
|
||||
self.mining.vecs(),
|
||||
self.market.vecs(),
|
||||
self.transactions.vecs(),
|
||||
self.stateful.vecs(),
|
||||
self.fetched.as_ref().map_or(vec![], |v| v.vecs()),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,258 @@
|
||||
use std::{collections::BTreeMap, ops::ControlFlow};
|
||||
|
||||
use brk_core::{CheckedSub, Dollars, HalvingEpoch, Height, Result, Timestamp};
|
||||
use brk_exit::Exit;
|
||||
use brk_state::{BlockState, OutputFilter, Outputs, Transacted};
|
||||
use brk_vec::StoredIndex;
|
||||
use rayon::prelude::*;
|
||||
|
||||
use crate::vecs::Indexes;
|
||||
|
||||
use super::cohort;
|
||||
|
||||
pub trait OutputCohorts {
|
||||
fn tick_tock_next_block(&mut self, chain_state: &[BlockState], timestamp: Timestamp);
|
||||
fn send(&mut self, height_to_sent: BTreeMap<Height, Transacted>, chain_state: &[BlockState]);
|
||||
fn receive(&mut self, received: Transacted, height: Height, price: Option<Dollars>);
|
||||
fn compute_overlaping_vecs(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()>;
|
||||
}
|
||||
|
||||
impl OutputCohorts for Outputs<(OutputFilter, cohort::Vecs)> {
|
||||
fn tick_tock_next_block(&mut self, chain_state: &[BlockState], timestamp: Timestamp) {
|
||||
if chain_state.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let prev_timestamp = chain_state.last().unwrap().timestamp;
|
||||
|
||||
self.by_date_range
|
||||
.as_mut_vec()
|
||||
.into_par_iter()
|
||||
.for_each(|(filter, v)| {
|
||||
let state = &mut v.state;
|
||||
|
||||
let _ = chain_state
|
||||
.iter()
|
||||
.try_for_each(|block_state| -> ControlFlow<()> {
|
||||
let prev_days_old = block_state
|
||||
.timestamp
|
||||
.difference_in_days_between(prev_timestamp);
|
||||
let days_old = block_state.timestamp.difference_in_days_between(timestamp);
|
||||
|
||||
if prev_days_old == days_old {
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
let is = filter.contains(days_old);
|
||||
let was = filter.contains(prev_days_old);
|
||||
|
||||
if is && !was {
|
||||
state.increment(&block_state.supply, block_state.price);
|
||||
} else if was && !is {
|
||||
state.decrement(&block_state.supply, block_state.price);
|
||||
}
|
||||
|
||||
ControlFlow::Continue(())
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn send(&mut self, height_to_sent: BTreeMap<Height, Transacted>, chain_state: &[BlockState]) {
|
||||
let mut time_based_vecs = self
|
||||
.by_date_range
|
||||
.as_mut_vec()
|
||||
.into_iter()
|
||||
.chain(self.by_epoch.as_mut_vec())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let last_timestamp = chain_state.last().unwrap().timestamp;
|
||||
let current_price = chain_state.last().unwrap().price;
|
||||
|
||||
// dbg!(&height_to_sent);
|
||||
|
||||
height_to_sent.into_iter().for_each(|(height, sent)| {
|
||||
let block_state = chain_state.get(height.unwrap_to_usize()).unwrap();
|
||||
let prev_price = block_state.price;
|
||||
|
||||
let blocks_old = chain_state.len() - 1 - height.unwrap_to_usize();
|
||||
|
||||
let days_old = block_state
|
||||
.timestamp
|
||||
.difference_in_days_between(last_timestamp);
|
||||
|
||||
let days_old_foat = block_state
|
||||
.timestamp
|
||||
.difference_in_days_between_float(last_timestamp);
|
||||
|
||||
let older_than_hour =
|
||||
jiff::Timestamp::from(last_timestamp.checked_sub(block_state.timestamp).unwrap())
|
||||
.as_second()
|
||||
>= 60 * 60;
|
||||
|
||||
time_based_vecs
|
||||
.iter_mut()
|
||||
.filter(|(filter, _)| match filter {
|
||||
OutputFilter::From(from) => *from <= days_old,
|
||||
OutputFilter::To(to) => *to > days_old,
|
||||
OutputFilter::Range(range) => range.contains(&days_old),
|
||||
OutputFilter::Epoch(epoch) => *epoch == HalvingEpoch::from(height),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.for_each(|(_, vecs)| {
|
||||
vecs.state.send(
|
||||
&sent.spendable_supply,
|
||||
current_price,
|
||||
prev_price,
|
||||
blocks_old,
|
||||
days_old_foat,
|
||||
older_than_hour,
|
||||
);
|
||||
});
|
||||
|
||||
sent.by_type.spendable.as_typed_vec().into_iter().for_each(
|
||||
|(output_type, supply_state)| {
|
||||
self.by_type.get_mut(output_type).1.state.send(
|
||||
supply_state,
|
||||
current_price,
|
||||
prev_price,
|
||||
blocks_old,
|
||||
days_old_foat,
|
||||
older_than_hour,
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
sent.by_size_group
|
||||
.into_iter()
|
||||
.for_each(|(group, supply_state)| {
|
||||
self.by_size_range.get_mut(group).1.state.send(
|
||||
&supply_state,
|
||||
current_price,
|
||||
prev_price,
|
||||
blocks_old,
|
||||
days_old_foat,
|
||||
older_than_hour,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn receive(&mut self, received: Transacted, height: Height, price: Option<Dollars>) {
|
||||
let supply_state = received.spendable_supply;
|
||||
|
||||
[
|
||||
&mut self.by_date_range.start_to_1d.1,
|
||||
&mut self.by_epoch.mut_vec_from_height(height).1,
|
||||
]
|
||||
.into_iter()
|
||||
.for_each(|v| {
|
||||
v.state.receive(&supply_state, price);
|
||||
});
|
||||
|
||||
self.by_type
|
||||
.as_mut_vec()
|
||||
.into_iter()
|
||||
.for_each(|(filter, vecs)| {
|
||||
let output_type = match filter {
|
||||
OutputFilter::Type(output_type) => *output_type,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
vecs.state.receive(received.by_type.get(output_type), price)
|
||||
});
|
||||
|
||||
received
|
||||
.by_size_group
|
||||
.into_iter()
|
||||
.for_each(|(group, supply_state)| {
|
||||
self.by_size_range
|
||||
.get_mut(group)
|
||||
.1
|
||||
.state
|
||||
.receive(&supply_state, price);
|
||||
});
|
||||
}
|
||||
|
||||
fn compute_overlaping_vecs(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()> {
|
||||
let by_date_range = self.by_date_range.as_vec();
|
||||
let by_size_range = self.by_size_range.as_vec();
|
||||
|
||||
[
|
||||
vec![(&mut self.all.1, self.by_epoch.vecs().to_vec())],
|
||||
self.by_from_date
|
||||
.as_mut_vec()
|
||||
.into_iter()
|
||||
.map(|(filter, vecs)| {
|
||||
(
|
||||
vecs,
|
||||
by_date_range
|
||||
.into_iter()
|
||||
.filter(|(other, _)| filter.includes(other))
|
||||
.map(|(_, v)| v)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
self.by_up_to_date
|
||||
.as_mut_vec()
|
||||
.into_iter()
|
||||
.map(|(filter, vecs)| {
|
||||
(
|
||||
vecs,
|
||||
by_date_range
|
||||
.into_iter()
|
||||
.filter(|(other, _)| filter.includes(other))
|
||||
.map(|(_, v)| v)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
self.by_term
|
||||
.as_mut_vec()
|
||||
.into_iter()
|
||||
.map(|(filter, vecs)| {
|
||||
(
|
||||
vecs,
|
||||
by_date_range
|
||||
.into_iter()
|
||||
.filter(|(other, _)| filter.includes(other))
|
||||
.map(|(_, v)| v)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
self.by_from_size
|
||||
.as_mut_vec()
|
||||
.into_iter()
|
||||
.map(|(filter, vecs)| {
|
||||
(
|
||||
vecs,
|
||||
by_size_range
|
||||
.into_iter()
|
||||
.filter(|(other, _)| filter.includes(other))
|
||||
.map(|(_, v)| v)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
self.by_up_to_size
|
||||
.as_mut_vec()
|
||||
.into_iter()
|
||||
.map(|(filter, vecs)| {
|
||||
(
|
||||
vecs,
|
||||
by_size_range
|
||||
.into_iter()
|
||||
.filter(|(other, _)| filter.includes(other))
|
||||
.map(|(_, v)| v)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
]
|
||||
.into_par_iter()
|
||||
.flatten()
|
||||
.try_for_each(|(vecs, stateful)| {
|
||||
vecs.compute_from_stateful(starting_indexes, &stateful, exit)
|
||||
})
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,20 +4,25 @@ description = "The Core (Structs and Errors) of the Bitcoin Research Kit"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
bincode = { workspace = true }
|
||||
bitcoin = { workspace = true }
|
||||
bitcoincore-rpc = { workspace = true }
|
||||
byteview = { workspace = true }
|
||||
derive_deref = { workspace = true }
|
||||
fjall = { workspace = true }
|
||||
jiff = { workspace = true }
|
||||
log = { workspace = true }
|
||||
rapidhash = "1.4.0"
|
||||
rlimit = "0.10.2"
|
||||
serde = { workspace = true }
|
||||
serde_bytes = "0.11.17"
|
||||
serde_bytes = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
zerocopy = { workspace = true }
|
||||
zerocopy-derive = { workspace = true }
|
||||
|
||||
[package.metadata.cargo-machete]
|
||||
ignored = ["serde_bytes"]
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
<a href="https://github.com/bitcoinresearchkit/brk">
|
||||
<img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/bitcoinresearchkit/brk?style=social">
|
||||
</a>
|
||||
<a href="https://kibo.money">
|
||||
<img alt="kibo.money" src="https://img.shields.io/badge/showcase-kib%C5%8D.money-orange">
|
||||
</a>
|
||||
<a href="https://github.com/bitcoinresearchkit/brk/blob/main/LICENSE.md">
|
||||
<img src="https://img.shields.io/crates/l/brk" alt="License" />
|
||||
</a>
|
||||
@@ -29,7 +26,7 @@
|
||||
<a href="https://bsky.app/profile/bitcoinresearchkit.org">
|
||||
<img src="https://img.shields.io/badge/bluesky-blue?link=https%3A%2F%2Fbsky.app%2Fprofile%2Fbitcoinresearchkit.org" alt="Bluesky" />
|
||||
</a>
|
||||
<a href="https://x.com/0xbrk">
|
||||
<a href="https://x.com/brkdotorg">
|
||||
<img src="https://img.shields.io/badge/x.com-black" alt="X" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -1,19 +1,26 @@
|
||||
use std::{
|
||||
fmt::{self, Debug},
|
||||
io,
|
||||
io, result, time,
|
||||
};
|
||||
|
||||
use crate::Version;
|
||||
|
||||
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
||||
pub type Result<T, E = Error> = result::Result<T, E>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
IO(io::Error),
|
||||
SerdeJson(serde_json::Error),
|
||||
Jiff(jiff::Error),
|
||||
Fjall(fjall::Error),
|
||||
SystemTimeError(time::SystemTimeError),
|
||||
ZeroCopyError,
|
||||
BincodeEncodeError(bincode::error::EncodeError),
|
||||
BincodeDecodeError(bincode::error::DecodeError),
|
||||
|
||||
WrongEndian,
|
||||
DifferentVersion { found: Version, expected: Version },
|
||||
MmapsVecIsTooSmall,
|
||||
IO(io::Error),
|
||||
ZeroCopyError,
|
||||
IndexTooHigh,
|
||||
EmptyVec,
|
||||
IndexTooLow,
|
||||
@@ -23,7 +30,17 @@ pub enum Error {
|
||||
UnsupportedUnflushedState,
|
||||
RangeFromAfterTo(usize, usize),
|
||||
DifferentCompressionMode,
|
||||
ToSerdeJsonValueError(serde_json::Error),
|
||||
WrongLength,
|
||||
WrongAddressType,
|
||||
UnindexableDate,
|
||||
|
||||
String(&'static str),
|
||||
}
|
||||
|
||||
impl From<time::SystemTimeError> for Error {
|
||||
fn from(value: time::SystemTimeError) -> Self {
|
||||
Self::SystemTimeError(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
@@ -32,6 +49,18 @@ impl From<io::Error> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<jiff::Error> for Error {
|
||||
fn from(value: jiff::Error) -> Self {
|
||||
Self::Jiff(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<fjall::Error> for Error {
|
||||
fn from(value: fjall::Error) -> Self {
|
||||
Self::Fjall(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, C> From<zerocopy::error::ConvertError<A, B, C>> for Error {
|
||||
fn from(_: zerocopy::error::ConvertError<A, B, C>) -> Self {
|
||||
Self::ZeroCopyError
|
||||
@@ -46,13 +75,34 @@ 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)
|
||||
Self::SerdeJson(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bincode::error::DecodeError> for Error {
|
||||
fn from(error: bincode::error::DecodeError) -> Self {
|
||||
Self::BincodeDecodeError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bincode::error::EncodeError> for Error {
|
||||
fn from(error: bincode::error::EncodeError) -> Self {
|
||||
Self::BincodeEncodeError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Error::IO(error) => Debug::fmt(&error, f),
|
||||
Error::SystemTimeError(error) => Debug::fmt(&error, f),
|
||||
Error::SerdeJson(error) => Debug::fmt(&error, f),
|
||||
Error::Jiff(error) => Debug::fmt(&error, f),
|
||||
Error::Fjall(error) => Debug::fmt(&error, f),
|
||||
Error::BincodeDecodeError(error) => Debug::fmt(&error, f),
|
||||
Error::BincodeEncodeError(error) => Debug::fmt(&error, f),
|
||||
Error::ZeroCopyError => write!(f, "ZeroCopy error"),
|
||||
|
||||
Error::WrongEndian => write!(f, "Wrong endian"),
|
||||
Error::DifferentVersion { found, expected } => {
|
||||
write!(
|
||||
@@ -61,7 +111,6 @@ impl fmt::Display for Error {
|
||||
)
|
||||
}
|
||||
Error::MmapsVecIsTooSmall => write!(f, "Mmaps vec is too small"),
|
||||
Error::IO(error) => Debug::fmt(&error, f),
|
||||
Error::IndexTooHigh => write!(f, "Index too high"),
|
||||
Error::IndexTooLow => write!(f, "Index too low"),
|
||||
Error::ExpectFileToHaveIndex => write!(f, "Expect file to have index"),
|
||||
@@ -73,11 +122,17 @@ impl fmt::Display for Error {
|
||||
"Unsupported unflush state, please flush before using this function"
|
||||
)
|
||||
}
|
||||
Error::ZeroCopyError => write!(f, "Zero copy convert error"),
|
||||
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),
|
||||
Error::WrongLength => write!(f, "Wrong length"),
|
||||
Error::WrongAddressType => write!(f, "Wrong address type"),
|
||||
Error::UnindexableDate => write!(
|
||||
f,
|
||||
"Date cannot be indexed, must be 2009-01-03, 2009-01-09 or greater"
|
||||
),
|
||||
|
||||
Error::String(s) => write!(f, "{s}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
use std::{
|
||||
fmt::{self, Debug},
|
||||
io,
|
||||
};
|
||||
|
||||
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
IO(io::Error),
|
||||
Jiff(jiff::Error),
|
||||
ZeroCopyError,
|
||||
WrongLength,
|
||||
WrongAddressType,
|
||||
UnindexableDate,
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(value: io::Error) -> Self {
|
||||
Self::IO(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<jiff::Error> for Error {
|
||||
fn from(value: jiff::Error) -> Self {
|
||||
Self::Jiff(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B> From<zerocopy::error::SizeError<A, B>> for Error {
|
||||
fn from(_: zerocopy::error::SizeError<A, B>) -> Self {
|
||||
Self::ZeroCopyError
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Error::IO(error) => Debug::fmt(&error, f),
|
||||
Error::Jiff(error) => Debug::fmt(&error, f),
|
||||
Error::ZeroCopyError => write!(f, "Zero copy convert error"),
|
||||
Error::WrongLength => write!(f, "Wrong length"),
|
||||
Error::WrongAddressType => write!(f, "Wrong address type"),
|
||||
Error::UnindexableDate => write!(f, "Date cannot be indexed, must be 2009-01-03, 2009-01-09 or greater"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {}
|
||||
@@ -1,9 +1,9 @@
|
||||
#![doc = include_str!("../README.md")]
|
||||
|
||||
mod error;
|
||||
mod enums;
|
||||
mod structs;
|
||||
mod utils;
|
||||
|
||||
pub use error::*;
|
||||
pub use enums::*;
|
||||
pub use structs::*;
|
||||
pub use utils::*;
|
||||
|
||||
+17
-18
@@ -2,7 +2,7 @@ use std::ops::Add;
|
||||
|
||||
use byteview::ByteView;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::Error;
|
||||
|
||||
@@ -21,9 +21,9 @@ use crate::Error;
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Addressindex(u32);
|
||||
pub struct AddressIndex(u32);
|
||||
|
||||
impl Addressindex {
|
||||
impl AddressIndex {
|
||||
pub const BYTES: usize = size_of::<Self>();
|
||||
|
||||
pub fn increment(&mut self) {
|
||||
@@ -35,56 +35,55 @@ impl Addressindex {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for Addressindex {
|
||||
impl From<u32> for AddressIndex {
|
||||
fn from(value: u32) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Addressindex {
|
||||
impl From<u64> for AddressIndex {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(value as u32)
|
||||
}
|
||||
}
|
||||
impl From<Addressindex> for u64 {
|
||||
fn from(value: Addressindex) -> Self {
|
||||
impl From<AddressIndex> for u64 {
|
||||
fn from(value: AddressIndex) -> Self {
|
||||
value.0 as u64
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Addressindex {
|
||||
impl From<usize> for AddressIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u32)
|
||||
}
|
||||
}
|
||||
impl From<Addressindex> for usize {
|
||||
fn from(value: Addressindex) -> Self {
|
||||
impl From<AddressIndex> for usize {
|
||||
fn from(value: AddressIndex) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ByteView> for Addressindex {
|
||||
type Error = Error;
|
||||
fn try_from(value: ByteView) -> Result<Self, Self::Error> {
|
||||
impl From<ByteView> for AddressIndex {
|
||||
fn from(value: ByteView) -> Self {
|
||||
Ok(Self::read_from_bytes(&value)?)
|
||||
}
|
||||
}
|
||||
impl From<Addressindex> for ByteView {
|
||||
fn from(value: Addressindex) -> Self {
|
||||
impl From<AddressIndex> for ByteView {
|
||||
fn from(value: AddressIndex) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Addressindex {
|
||||
impl Add<usize> for AddressIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 + rhs as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Addressindex> for Addressindex {
|
||||
impl Add<AddressIndex> for AddressIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Addressindex) -> Self::Output {
|
||||
fn add(self, rhs: AddressIndex) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
use byteview::ByteView;
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::Error;
|
||||
|
||||
use super::{AddressIndex, Outputindex};
|
||||
|
||||
#[derive(
|
||||
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Immutable, IntoBytes, KnownLayout, FromBytes,
|
||||
)]
|
||||
#[repr(C)]
|
||||
pub struct AddressIndexOutputIndex {
|
||||
addressindex: AddressIndex,
|
||||
_padding: u32,
|
||||
outputindex: Outputindex,
|
||||
}
|
||||
|
||||
impl From<ByteView> for AddressIndexOutputIndex {
|
||||
fn from(value: ByteView) -> Self {
|
||||
Ok(Self::read_from_bytes(&value)?)
|
||||
}
|
||||
}
|
||||
impl From<AddressIndexOutputIndex> for ByteView {
|
||||
fn from(value: AddressIndexOutputIndex) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
use serde::Serialize;
|
||||
use zerocopy_derive::{Immutable, IntoBytes, KnownLayout, TryFromBytes};
|
||||
|
||||
use super::OutputType;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
TryFromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
#[repr(u8)]
|
||||
pub enum AddressType {
|
||||
P2PK65,
|
||||
P2PK33,
|
||||
P2PKH,
|
||||
P2SH,
|
||||
P2WPKH,
|
||||
P2WSH,
|
||||
P2TR,
|
||||
P2A,
|
||||
}
|
||||
|
||||
impl From<OutputType> for AddressType {
|
||||
fn from(value: OutputType) -> Self {
|
||||
match value {
|
||||
OutputType::P2A => Self::P2A,
|
||||
OutputType::P2PK33 => Self::P2PK33,
|
||||
OutputType::P2PK65 => Self::P2PK65,
|
||||
OutputType::P2PKH => Self::P2PKH,
|
||||
OutputType::P2SH => Self::P2SH,
|
||||
OutputType::P2TR => Self::P2TR,
|
||||
OutputType::P2WPKH => Self::P2WPKH,
|
||||
OutputType::P2WSH => Self::P2WSH,
|
||||
OutputType::Empty | OutputType::OpReturn | OutputType::P2MS | OutputType::Unknown => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,44 +8,46 @@ use bitcoin::{
|
||||
};
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use serde::{Serialize, Serializer};
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::Error;
|
||||
|
||||
use super::Addresstype;
|
||||
use super::OutputType;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Addressbytes {
|
||||
P2PK65(P2PK65AddressBytes),
|
||||
P2PK33(P2PK33AddressBytes),
|
||||
P2PKH(P2PKHAddressBytes),
|
||||
P2SH(P2SHAddressBytes),
|
||||
P2WPKH(P2WPKHAddressBytes),
|
||||
P2WSH(P2WSHAddressBytes),
|
||||
P2TR(P2TRAddressBytes),
|
||||
pub enum AddressBytes {
|
||||
P2PK65(P2PK65Bytes),
|
||||
P2PK33(P2PK33Bytes),
|
||||
P2PKH(P2PKHBytes),
|
||||
P2SH(P2SHBytes),
|
||||
P2WPKH(P2WPKHBytes),
|
||||
P2WSH(P2WSHBytes),
|
||||
P2TR(P2TRBytes),
|
||||
P2A(P2ABytes),
|
||||
}
|
||||
|
||||
impl Addressbytes {
|
||||
impl AddressBytes {
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
match self {
|
||||
Addressbytes::P2PK65(bytes) => &bytes[..],
|
||||
Addressbytes::P2PK33(bytes) => &bytes[..],
|
||||
Addressbytes::P2PKH(bytes) => &bytes[..],
|
||||
Addressbytes::P2SH(bytes) => &bytes[..],
|
||||
Addressbytes::P2WPKH(bytes) => &bytes[..],
|
||||
Addressbytes::P2WSH(bytes) => &bytes[..],
|
||||
Addressbytes::P2TR(bytes) => &bytes[..],
|
||||
AddressBytes::P2PK65(bytes) => &bytes[..],
|
||||
AddressBytes::P2PK33(bytes) => &bytes[..],
|
||||
AddressBytes::P2PKH(bytes) => &bytes[..],
|
||||
AddressBytes::P2SH(bytes) => &bytes[..],
|
||||
AddressBytes::P2WPKH(bytes) => &bytes[..],
|
||||
AddressBytes::P2WSH(bytes) => &bytes[..],
|
||||
AddressBytes::P2TR(bytes) => &bytes[..],
|
||||
AddressBytes::P2A(bytes) => &bytes[..],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<(&ScriptBuf, Addresstype)> for Addressbytes {
|
||||
impl TryFrom<(&ScriptBuf, OutputType)> for AddressBytes {
|
||||
type Error = Error;
|
||||
fn try_from(tuple: (&ScriptBuf, Addresstype)) -> Result<Self, Self::Error> {
|
||||
let (script, addresstype) = tuple;
|
||||
fn try_from(tuple: (&ScriptBuf, OutputType)) -> Result<Self, Self::Error> {
|
||||
let (script, outputtype) = tuple;
|
||||
|
||||
match addresstype {
|
||||
Addresstype::P2PK65 => {
|
||||
match outputtype {
|
||||
OutputType::P2PK65 => {
|
||||
let bytes = script.as_bytes();
|
||||
let bytes = match bytes.len() {
|
||||
67 => &bytes[1..66],
|
||||
@@ -54,9 +56,9 @@ impl TryFrom<(&ScriptBuf, Addresstype)> for Addressbytes {
|
||||
return Err(Error::WrongLength);
|
||||
}
|
||||
};
|
||||
Ok(Self::P2PK65(P2PK65AddressBytes(U8x65::from(bytes))))
|
||||
Ok(Self::P2PK65(P2PK65Bytes(U8x65::from(bytes))))
|
||||
}
|
||||
Addresstype::P2PK33 => {
|
||||
OutputType::P2PK33 => {
|
||||
let bytes = script.as_bytes();
|
||||
let bytes = match bytes.len() {
|
||||
35 => &bytes[1..34],
|
||||
@@ -65,47 +67,50 @@ impl TryFrom<(&ScriptBuf, Addresstype)> for Addressbytes {
|
||||
return Err(Error::WrongLength);
|
||||
}
|
||||
};
|
||||
Ok(Self::P2PK33(P2PK33AddressBytes(U8x33::from(bytes))))
|
||||
Ok(Self::P2PK33(P2PK33Bytes(U8x33::from(bytes))))
|
||||
}
|
||||
Addresstype::P2PKH => {
|
||||
OutputType::P2PKH => {
|
||||
let bytes = &script.as_bytes()[3..23];
|
||||
Ok(Self::P2PKH(P2PKHAddressBytes(U8x20::from(bytes))))
|
||||
Ok(Self::P2PKH(P2PKHBytes(U8x20::from(bytes))))
|
||||
}
|
||||
Addresstype::P2SH => {
|
||||
OutputType::P2SH => {
|
||||
let bytes = &script.as_bytes()[2..22];
|
||||
Ok(Self::P2SH(P2SHAddressBytes(U8x20::from(bytes))))
|
||||
Ok(Self::P2SH(P2SHBytes(U8x20::from(bytes))))
|
||||
}
|
||||
Addresstype::P2WPKH => {
|
||||
OutputType::P2WPKH => {
|
||||
let bytes = &script.as_bytes()[2..];
|
||||
Ok(Self::P2WPKH(P2WPKHAddressBytes(U8x20::from(bytes))))
|
||||
Ok(Self::P2WPKH(P2WPKHBytes(U8x20::from(bytes))))
|
||||
}
|
||||
Addresstype::P2WSH => {
|
||||
OutputType::P2WSH => {
|
||||
let bytes = &script.as_bytes()[2..];
|
||||
Ok(Self::P2WSH(P2WSHAddressBytes(U8x32::from(bytes))))
|
||||
Ok(Self::P2WSH(P2WSHBytes(U8x32::from(bytes))))
|
||||
}
|
||||
Addresstype::P2TR => {
|
||||
OutputType::P2TR => {
|
||||
let bytes = &script.as_bytes()[2..];
|
||||
Ok(Self::P2TR(P2TRAddressBytes(U8x32::from(bytes))))
|
||||
Ok(Self::P2TR(P2TRBytes(U8x32::from(bytes))))
|
||||
}
|
||||
Addresstype::Multisig => Err(Error::WrongAddressType),
|
||||
Addresstype::PushOnly => Err(Error::WrongAddressType),
|
||||
Addresstype::Unknown => Err(Error::WrongAddressType),
|
||||
Addresstype::Empty => Err(Error::WrongAddressType),
|
||||
Addresstype::OpReturn => Err(Error::WrongAddressType),
|
||||
OutputType::P2A => {
|
||||
let bytes = &script.as_bytes()[2..];
|
||||
Ok(Self::P2A(P2ABytes(U8x2::from(bytes))))
|
||||
}
|
||||
OutputType::P2MS => Err(Error::WrongAddressType),
|
||||
OutputType::Unknown => Err(Error::WrongAddressType),
|
||||
OutputType::Empty => Err(Error::WrongAddressType),
|
||||
OutputType::OpReturn => Err(Error::WrongAddressType),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2PK65AddressBytes(U8x65);
|
||||
pub struct P2PK65Bytes(U8x65);
|
||||
|
||||
impl fmt::Display for P2PK65AddressBytes {
|
||||
impl fmt::Display for P2PK65Bytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.to_hex_string(Case::Lower))
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2PK65AddressBytes {
|
||||
impl Serialize for P2PK65Bytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
@@ -114,22 +119,22 @@ impl Serialize for P2PK65AddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2PK65AddressBytes> for Addressbytes {
|
||||
fn from(value: P2PK65AddressBytes) -> Self {
|
||||
impl From<P2PK65Bytes> for AddressBytes {
|
||||
fn from(value: P2PK65Bytes) -> Self {
|
||||
Self::P2PK65(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2PK33AddressBytes(U8x33);
|
||||
pub struct P2PK33Bytes(U8x33);
|
||||
|
||||
impl fmt::Display for P2PK33AddressBytes {
|
||||
impl fmt::Display for P2PK33Bytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.to_hex_string(Case::Lower))
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2PK33AddressBytes {
|
||||
impl Serialize for P2PK33Bytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
@@ -138,16 +143,16 @@ impl Serialize for P2PK33AddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2PK33AddressBytes> for Addressbytes {
|
||||
fn from(value: P2PK33AddressBytes) -> Self {
|
||||
impl From<P2PK33Bytes> for AddressBytes {
|
||||
fn from(value: P2PK33Bytes) -> Self {
|
||||
Self::P2PK33(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2PKHAddressBytes(U8x20);
|
||||
pub struct P2PKHBytes(U8x20);
|
||||
|
||||
impl fmt::Display for P2PKHAddressBytes {
|
||||
impl fmt::Display for P2PKHBytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let script = Builder::new()
|
||||
.push_opcode(opcodes::all::OP_DUP)
|
||||
@@ -161,7 +166,7 @@ impl fmt::Display for P2PKHAddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2PKHAddressBytes {
|
||||
impl Serialize for P2PKHBytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
@@ -170,16 +175,16 @@ impl Serialize for P2PKHAddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2PKHAddressBytes> for Addressbytes {
|
||||
fn from(value: P2PKHAddressBytes) -> Self {
|
||||
impl From<P2PKHBytes> for AddressBytes {
|
||||
fn from(value: P2PKHBytes) -> Self {
|
||||
Self::P2PKH(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2SHAddressBytes(U8x20);
|
||||
pub struct P2SHBytes(U8x20);
|
||||
|
||||
impl fmt::Display for P2SHAddressBytes {
|
||||
impl fmt::Display for P2SHBytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let script = Builder::new()
|
||||
.push_opcode(opcodes::all::OP_HASH160)
|
||||
@@ -191,7 +196,7 @@ impl fmt::Display for P2SHAddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2SHAddressBytes {
|
||||
impl Serialize for P2SHBytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
@@ -200,16 +205,16 @@ impl Serialize for P2SHAddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2SHAddressBytes> for Addressbytes {
|
||||
fn from(value: P2SHAddressBytes) -> Self {
|
||||
impl From<P2SHBytes> for AddressBytes {
|
||||
fn from(value: P2SHBytes) -> Self {
|
||||
Self::P2SH(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2WPKHAddressBytes(U8x20);
|
||||
pub struct P2WPKHBytes(U8x20);
|
||||
|
||||
impl fmt::Display for P2WPKHAddressBytes {
|
||||
impl fmt::Display for P2WPKHBytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let script = Builder::new().push_int(0).push_slice(*self.0).into_script();
|
||||
let address = Address::from_script(&script, Network::Bitcoin).unwrap();
|
||||
@@ -217,7 +222,7 @@ impl fmt::Display for P2WPKHAddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2WPKHAddressBytes {
|
||||
impl Serialize for P2WPKHBytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
@@ -226,16 +231,16 @@ impl Serialize for P2WPKHAddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2WPKHAddressBytes> for Addressbytes {
|
||||
fn from(value: P2WPKHAddressBytes) -> Self {
|
||||
impl From<P2WPKHBytes> for AddressBytes {
|
||||
fn from(value: P2WPKHBytes) -> Self {
|
||||
Self::P2WPKH(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2WSHAddressBytes(U8x32);
|
||||
pub struct P2WSHBytes(U8x32);
|
||||
|
||||
impl fmt::Display for P2WSHAddressBytes {
|
||||
impl fmt::Display for P2WSHBytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let script = Builder::new().push_int(0).push_slice(*self.0).into_script();
|
||||
let address = Address::from_script(&script, Network::Bitcoin).unwrap();
|
||||
@@ -243,7 +248,7 @@ impl fmt::Display for P2WSHAddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2WSHAddressBytes {
|
||||
impl Serialize for P2WSHBytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
@@ -252,16 +257,16 @@ impl Serialize for P2WSHAddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2WSHAddressBytes> for Addressbytes {
|
||||
fn from(value: P2WSHAddressBytes) -> Self {
|
||||
impl From<P2WSHBytes> for AddressBytes {
|
||||
fn from(value: P2WSHBytes) -> Self {
|
||||
Self::P2WSH(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2TRAddressBytes(U8x32);
|
||||
pub struct P2TRBytes(U8x32);
|
||||
|
||||
impl fmt::Display for P2TRAddressBytes {
|
||||
impl fmt::Display for P2TRBytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let script = Builder::new().push_int(1).push_slice(*self.0).into_script();
|
||||
let address = Address::from_script(&script, Network::Bitcoin).unwrap();
|
||||
@@ -269,7 +274,7 @@ impl fmt::Display for P2TRAddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2TRAddressBytes {
|
||||
impl Serialize for P2TRBytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
@@ -278,12 +283,60 @@ impl Serialize for P2TRAddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2TRAddressBytes> for Addressbytes {
|
||||
fn from(value: P2TRAddressBytes) -> Self {
|
||||
impl From<P2TRBytes> for AddressBytes {
|
||||
fn from(value: P2TRBytes) -> Self {
|
||||
Self::P2TR(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2ABytes(U8x2);
|
||||
|
||||
impl fmt::Display for P2ABytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let script = Builder::new().push_int(1).push_slice(*self.0).into_script();
|
||||
let address = Address::from_script(&script, Network::Bitcoin).unwrap();
|
||||
write!(f, "{}", address)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2ABytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.collect_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2ABytes> for AddressBytes {
|
||||
fn from(value: P2ABytes) -> Self {
|
||||
Self::P2A(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Deref,
|
||||
DerefMut,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
FromBytes,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct U8x2([u8; 2]);
|
||||
impl From<&[u8]> for U8x2 {
|
||||
fn from(slice: &[u8]) -> Self {
|
||||
let mut arr = [0; 2];
|
||||
arr.copy_from_slice(slice);
|
||||
Self(arr)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
use std::hash::Hasher;
|
||||
|
||||
use byteview::ByteView;
|
||||
use derive_deref::Deref;
|
||||
use zerocopy::{FromBytes, IntoBytes};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use super::{AddressBytes, OutputType};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct AddressBytesHash([u8; 8]);
|
||||
|
||||
impl From<(&AddressBytes, OutputType)> for AddressBytesHash {
|
||||
fn from((address_bytes, outputtype): (&AddressBytes, OutputType)) -> Self {
|
||||
let mut hasher = rapidhash::RapidHasher::default();
|
||||
hasher.write(address_bytes.as_slice());
|
||||
let mut slice = hasher.finish().to_le_bytes();
|
||||
slice[0] = slice[0].wrapping_add(outputtype as u8);
|
||||
Self(slice)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; 8]> for AddressBytesHash {
|
||||
fn from(value: [u8; 8]) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ByteView> for AddressBytesHash {
|
||||
fn from(value: ByteView) -> Self {
|
||||
Self::read_from_bytes(&value).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&AddressBytesHash> for ByteView {
|
||||
fn from(value: &AddressBytesHash) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AddressBytesHash> for ByteView {
|
||||
fn from(value: AddressBytesHash) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
use byteview::ByteView;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::Error;
|
||||
|
||||
use super::{Addressindex, Txoutindex};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
#[repr(C)]
|
||||
pub struct AddressindexTxoutindex {
|
||||
addressindex: Addressindex,
|
||||
_padding: u32,
|
||||
txoutindex: Txoutindex,
|
||||
}
|
||||
|
||||
impl TryFrom<ByteView> for AddressindexTxoutindex {
|
||||
type Error = Error;
|
||||
fn try_from(value: ByteView) -> Result<Self, Self::Error> {
|
||||
Ok(Self::read_from_bytes(&value)?)
|
||||
}
|
||||
}
|
||||
impl From<AddressindexTxoutindex> for ByteView {
|
||||
fn from(value: AddressindexTxoutindex) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
use bitcoin::ScriptBuf;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{Immutable, IntoBytes, KnownLayout, TryFromBytes};
|
||||
|
||||
#[derive(
|
||||
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, TryFromBytes, Immutable, IntoBytes, KnownLayout, Serialize,
|
||||
)]
|
||||
#[repr(u8)]
|
||||
pub enum Addresstype {
|
||||
P2PK65,
|
||||
P2PK33,
|
||||
P2PKH,
|
||||
P2SH,
|
||||
P2WPKH,
|
||||
P2WSH,
|
||||
P2TR,
|
||||
Multisig = 251,
|
||||
PushOnly = 252,
|
||||
OpReturn = 253,
|
||||
Empty = 254,
|
||||
Unknown = 255,
|
||||
}
|
||||
|
||||
impl From<&ScriptBuf> for Addresstype {
|
||||
fn from(script: &ScriptBuf) -> Self {
|
||||
if script.is_p2pk() {
|
||||
let bytes = script.as_bytes();
|
||||
|
||||
match bytes.len() {
|
||||
67 => Self::P2PK65,
|
||||
35 => Self::P2PK33,
|
||||
_ => {
|
||||
dbg!(bytes);
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
} else if script.is_p2pkh() {
|
||||
Self::P2PKH
|
||||
} else if script.is_p2sh() {
|
||||
Self::P2SH
|
||||
} else if script.is_p2wpkh() {
|
||||
Self::P2WPKH
|
||||
} else if script.is_p2wsh() {
|
||||
Self::P2WSH
|
||||
} else if script.is_p2tr() {
|
||||
Self::P2TR
|
||||
} else if script.is_empty() {
|
||||
Self::Empty
|
||||
} else if script.is_op_return() {
|
||||
Self::OpReturn
|
||||
} else if script.is_push_only() {
|
||||
Self::PushOnly
|
||||
} else if script.is_multisig() {
|
||||
Self::Multisig
|
||||
} else {
|
||||
Self::Unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,560 +0,0 @@
|
||||
use std::ops::Add;
|
||||
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Addresstypeindex(u32);
|
||||
|
||||
impl Addresstypeindex {
|
||||
pub fn increment(&mut self) {
|
||||
self.0 += 1;
|
||||
}
|
||||
|
||||
pub fn incremented(self) -> Self {
|
||||
Self(self.0 + 1)
|
||||
}
|
||||
|
||||
pub fn copy_then_increment(&mut self) -> Self {
|
||||
let i = *self;
|
||||
self.increment();
|
||||
i
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for Addresstypeindex {
|
||||
fn from(value: u32) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Addresstypeindex {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(value as u32)
|
||||
}
|
||||
}
|
||||
impl From<Addresstypeindex> for u64 {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
value.0 as u64
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Addresstypeindex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u32)
|
||||
}
|
||||
}
|
||||
impl From<Addresstypeindex> for usize {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Addresstypeindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 + rhs as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Addresstypeindex> for Addresstypeindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Addresstypeindex) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Emptyindex(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for Emptyindex {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<Emptyindex> for usize {
|
||||
fn from(value: Emptyindex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for Emptyindex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for Emptyindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Multisigindex(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for Multisigindex {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<Multisigindex> for usize {
|
||||
fn from(value: Multisigindex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for Multisigindex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for Multisigindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Opreturnindex(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for Opreturnindex {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<Opreturnindex> for usize {
|
||||
fn from(value: Opreturnindex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for Opreturnindex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for Opreturnindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Pushonlyindex(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for Pushonlyindex {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<Pushonlyindex> for usize {
|
||||
fn from(value: Pushonlyindex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for Pushonlyindex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for Pushonlyindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Unknownindex(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for Unknownindex {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<Unknownindex> for usize {
|
||||
fn from(value: Unknownindex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for Unknownindex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for Unknownindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2PK33index(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for P2PK33index {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2PK33index> for usize {
|
||||
fn from(value: P2PK33index) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2PK33index {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2PK33index {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2PK65index(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for P2PK65index {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2PK65index> for usize {
|
||||
fn from(value: P2PK65index) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2PK65index {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2PK65index {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2PKHindex(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for P2PKHindex {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2PKHindex> for usize {
|
||||
fn from(value: P2PKHindex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2PKHindex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2PKHindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2SHindex(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for P2SHindex {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2SHindex> for usize {
|
||||
fn from(value: P2SHindex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2SHindex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2SHindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2TRindex(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for P2TRindex {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2TRindex> for usize {
|
||||
fn from(value: P2TRindex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2TRindex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2TRindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2WPKHindex(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for P2WPKHindex {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2WPKHindex> for usize {
|
||||
fn from(value: P2WPKHindex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2WPKHindex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2WPKHindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2WSHindex(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for P2WSHindex {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2WSHindex> for usize {
|
||||
fn from(value: P2WSHindex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2WSHindex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2WSHindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
@@ -1,49 +1,57 @@
|
||||
use std::ops::{Add, Div, Mul};
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
ops::{Add, Div, Mul},
|
||||
};
|
||||
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use super::Sats;
|
||||
use crate::CheckedSub;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Default,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
use super::{Sats, StoredF64};
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, 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)
|
||||
Self::from(Sats::from(self) + Sats::from(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul for Bitcoin {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 * rhs.0)
|
||||
Self::from(Sats::from(self) * Sats::from(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<usize> for Bitcoin {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: usize) -> Self::Output {
|
||||
Self::from(Sats::from(self) * rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<Bitcoin> for Bitcoin {
|
||||
type Output = StoredF64;
|
||||
fn div(self, rhs: Bitcoin) -> Self::Output {
|
||||
StoredF64::from(self.0 / rhs.0)
|
||||
// Self::from(Sats::from(self) / Sats::from(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for Bitcoin {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 / rhs as f64)
|
||||
Self::from(Sats::from(self) / rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Sats> for Bitcoin {
|
||||
fn from(value: Sats) -> Self {
|
||||
Self(u64::from(value) as f64 / (u64::from(Sats::ONE_BTC) as f64))
|
||||
Self(f64::from(value) / (f64::from(Sats::ONE_BTC)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +61,12 @@ impl From<f64> for Bitcoin {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StoredF64> for Bitcoin {
|
||||
fn from(value: StoredF64) -> Self {
|
||||
Self(*value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Bitcoin> for f64 {
|
||||
fn from(value: Bitcoin) -> Self {
|
||||
value.0
|
||||
@@ -65,11 +79,40 @@ impl From<usize> for Bitcoin {
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Bitcoin {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self.0.is_nan(), other.0.is_nan()) {
|
||||
(true, true) => true,
|
||||
(true, false) => false,
|
||||
(false, true) => false,
|
||||
(false, false) => self.0 == other.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
impl PartialOrd for Bitcoin {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::derive_ord_xor_partial_ord)]
|
||||
impl Ord for Bitcoin {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
match (self.0.is_nan(), other.0.is_nan()) {
|
||||
(true, true) => Ordering::Equal,
|
||||
(true, false) => Ordering::Less,
|
||||
(false, true) => Ordering::Greater,
|
||||
(false, false) => self.0.partial_cmp(&other.0).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub<usize> for Bitcoin {
|
||||
fn checked_sub(self, rhs: usize) -> Option<Self> {
|
||||
Some(Self(self.0 - rhs as f64))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use bitcoin::hashes::Hash;
|
||||
use bitcoincore_rpc::{Client, RpcApi};
|
||||
use derive_deref::Deref;
|
||||
use serde::{Serialize, Serializer};
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use super::Height;
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
use byteview::ByteView;
|
||||
use derive_deref::Deref;
|
||||
use zerocopy::{FromBytes, IntoBytes};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::copy_first_8bytes;
|
||||
|
||||
use super::BlockHash;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct BlockHashPrefix([u8; 8]);
|
||||
|
||||
impl From<BlockHash> for BlockHashPrefix {
|
||||
fn from(value: BlockHash) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&BlockHash> for BlockHashPrefix {
|
||||
fn from(value: &BlockHash) -> Self {
|
||||
Self(copy_first_8bytes(&value[..]).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ByteView> for BlockHashPrefix {
|
||||
fn from(value: ByteView) -> Self {
|
||||
Self::read_from_bytes(&value).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&BlockHashPrefix> for ByteView {
|
||||
fn from(value: &BlockHashPrefix) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BlockHashPrefix> for ByteView {
|
||||
fn from(value: BlockHashPrefix) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
use std::ops::{Add, Div, Mul};
|
||||
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
use super::Dollars;
|
||||
|
||||
@@ -18,11 +22,17 @@ use super::Dollars;
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Cents(u64);
|
||||
pub struct Cents(i64);
|
||||
|
||||
impl Cents {
|
||||
pub const fn mint(value: i64) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Dollars> for Cents {
|
||||
fn from(value: Dollars) -> Self {
|
||||
Self((*value * 100.0).round() as u64)
|
||||
Self((*value * 100.0).round() as i64)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,14 +42,110 @@ impl From<Cents> for f64 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i64> for Cents {
|
||||
fn from(value: i64) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Cents {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(value)
|
||||
Self(value as i64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Cents> for usize {
|
||||
fn from(value: Cents) -> Self {
|
||||
if value.0 < 0 {
|
||||
panic!()
|
||||
}
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Cents {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as i64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Cents> for i64 {
|
||||
fn from(value: Cents) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Cents> for u64 {
|
||||
fn from(value: Cents) -> Self {
|
||||
value.0
|
||||
if value.0 < 0 {
|
||||
panic!("Shouldn't convert neg cents to u64")
|
||||
}
|
||||
value.0 as u64
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Cents {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<Cents> for Cents {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 / rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for Cents {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 / rhs as i64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u128> for Cents {
|
||||
fn from(value: u128) -> Self {
|
||||
if value > i64::MAX as u128 {
|
||||
panic!("u128 bigger than i64")
|
||||
}
|
||||
Self(value as i64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Cents> for u128 {
|
||||
fn from(value: Cents) -> Self {
|
||||
if value.0 < 0 {
|
||||
panic!("Shouldn't convert neg cents to u128")
|
||||
}
|
||||
value.0 as u128
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Cents> for Cents {
|
||||
type Output = Cents;
|
||||
fn mul(self, rhs: Cents) -> Self::Output {
|
||||
Self(self.0.checked_mul(rhs.0).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<i64> for Cents {
|
||||
type Output = Cents;
|
||||
fn mul(self, rhs: i64) -> Self::Output {
|
||||
Self(self.0 * rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<usize> for Cents {
|
||||
type Output = Cents;
|
||||
fn mul(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 * rhs as i64)
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for Cents {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Cents::from)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
use std::hash::Hasher;
|
||||
|
||||
use byteview::ByteView;
|
||||
use derive_deref::Deref;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::Error;
|
||||
|
||||
use super::{Addressbytes, Addresstype, BlockHash, Txid};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct AddressHash([u8; 8]);
|
||||
impl From<(&Addressbytes, Addresstype)> for AddressHash {
|
||||
fn from((addressbytes, addresstype): (&Addressbytes, Addresstype)) -> Self {
|
||||
let mut hasher = rapidhash::RapidHasher::default();
|
||||
hasher.write(addressbytes.as_slice());
|
||||
let mut slice = hasher.finish().to_le_bytes();
|
||||
slice[0] = slice[0].wrapping_add(addresstype as u8);
|
||||
Self(slice)
|
||||
}
|
||||
}
|
||||
impl From<[u8; 8]> for AddressHash {
|
||||
fn from(value: [u8; 8]) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl TryFrom<ByteView> for AddressHash {
|
||||
type Error = Error;
|
||||
fn try_from(value: ByteView) -> Result<Self, Self::Error> {
|
||||
Ok(Self::read_from_bytes(&value)?)
|
||||
}
|
||||
}
|
||||
impl From<&AddressHash> for ByteView {
|
||||
fn from(value: &AddressHash) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
impl From<AddressHash> for ByteView {
|
||||
fn from(value: AddressHash) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct BlockHashPrefix([u8; 8]);
|
||||
impl From<BlockHash> for BlockHashPrefix {
|
||||
fn from(value: BlockHash) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
impl From<&BlockHash> for BlockHashPrefix {
|
||||
fn from(value: &BlockHash) -> Self {
|
||||
Self(copy_first_8bytes(&value[..]).unwrap())
|
||||
}
|
||||
}
|
||||
impl TryFrom<ByteView> for BlockHashPrefix {
|
||||
type Error = Error;
|
||||
fn try_from(value: ByteView) -> Result<Self, Self::Error> {
|
||||
Ok(Self::read_from_bytes(&value)?)
|
||||
}
|
||||
}
|
||||
impl From<&BlockHashPrefix> for ByteView {
|
||||
fn from(value: &BlockHashPrefix) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
impl From<BlockHashPrefix> for ByteView {
|
||||
fn from(value: BlockHashPrefix) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct TxidPrefix([u8; 8]);
|
||||
impl From<Txid> for TxidPrefix {
|
||||
fn from(value: Txid) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
impl From<&Txid> for TxidPrefix {
|
||||
fn from(value: &Txid) -> Self {
|
||||
Self(copy_first_8bytes(&value[..]).unwrap())
|
||||
}
|
||||
}
|
||||
impl TryFrom<ByteView> for TxidPrefix {
|
||||
type Error = Error;
|
||||
fn try_from(value: ByteView) -> Result<Self, Self::Error> {
|
||||
Ok(Self::read_from_bytes(&value)?)
|
||||
}
|
||||
}
|
||||
impl From<&TxidPrefix> for ByteView {
|
||||
fn from(value: &TxidPrefix) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
impl From<TxidPrefix> for ByteView {
|
||||
fn from(value: TxidPrefix) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
impl From<[u8; 8]> for TxidPrefix {
|
||||
fn from(value: [u8; 8]) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
fn copy_first_8bytes(slice: &[u8]) -> Result<[u8; 8], ()> {
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
let buf_len = buf.len();
|
||||
if slice.len() < buf_len {
|
||||
return Err(());
|
||||
}
|
||||
slice.iter().take(buf_len).enumerate().for_each(|(i, r)| {
|
||||
buf[i] = *r;
|
||||
});
|
||||
Ok(buf)
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
use jiff::{Span, civil::Date as Date_, tz::TimeZone};
|
||||
use serde::{Serialize, Serializer};
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use super::{Dateindex, Timestamp};
|
||||
use super::{DateIndex, Timestamp};
|
||||
|
||||
#[derive(
|
||||
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, FromBytes, Immutable, IntoBytes, KnownLayout,
|
||||
@@ -14,6 +14,7 @@ impl Date {
|
||||
pub const INDEX_ZERO_: Date_ = Date_::constant(2009, 1, 3);
|
||||
pub const INDEX_ONE: Self = Self(20090109);
|
||||
pub const INDEX_ONE_: Date_ = Date_::constant(2009, 1, 9);
|
||||
pub const MIN_RATIO: Self = Self(20120101);
|
||||
|
||||
pub fn new(year: u16, month: u8, day: u8) -> Self {
|
||||
Self(year as u32 * 1_00_00 + month as u32 * 1_00 + day as u32)
|
||||
@@ -58,9 +59,9 @@ impl From<Timestamp> for Date {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Dateindex> for Date {
|
||||
fn from(value: Dateindex) -> Self {
|
||||
if value == Dateindex::default() {
|
||||
impl From<DateIndex> for Date {
|
||||
fn from(value: DateIndex) -> Self {
|
||||
if value == DateIndex::default() {
|
||||
Date::INDEX_ZERO
|
||||
} else {
|
||||
Self::from(
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
use std::ops::Add;
|
||||
use std::{
|
||||
fmt,
|
||||
ops::{Add, Rem},
|
||||
};
|
||||
|
||||
use serde::Serialize;
|
||||
// use color_eyre::eyre::eyre;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::{CheckedSub, Error};
|
||||
|
||||
@@ -23,38 +26,38 @@ use super::Date;
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Dateindex(u16);
|
||||
pub struct DateIndex(u16);
|
||||
|
||||
impl Dateindex {
|
||||
impl DateIndex {
|
||||
pub const BYTES: usize = size_of::<Self>();
|
||||
}
|
||||
|
||||
impl From<Dateindex> for usize {
|
||||
fn from(value: Dateindex) -> Self {
|
||||
impl From<DateIndex> for usize {
|
||||
fn from(value: DateIndex) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Dateindex {
|
||||
impl From<usize> for DateIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u16)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Dateindex> for i64 {
|
||||
fn from(value: Dateindex) -> Self {
|
||||
impl From<DateIndex> for i64 {
|
||||
fn from(value: DateIndex) -> Self {
|
||||
value.0 as i64
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Dateindex {
|
||||
impl Add<usize> for DateIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 + rhs as u16)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Date> for Dateindex {
|
||||
impl TryFrom<Date> for DateIndex {
|
||||
type Error = Error;
|
||||
fn try_from(value: Date) -> Result<Self, Self::Error> {
|
||||
let value_ = jiff::civil::Date::from(value);
|
||||
@@ -72,8 +75,21 @@ impl TryFrom<Date> for Dateindex {
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for Dateindex {
|
||||
impl CheckedSub for DateIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Rem<usize> for DateIndex {
|
||||
type Output = Self;
|
||||
fn rem(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 % rhs as u16)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DateIndex {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use std::{fmt::Debug, ops::Add};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
use super::{Date, Dateindex, Yearindex};
|
||||
use super::{Date, DateIndex, YearIndex};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
@@ -23,27 +23,27 @@ use super::{Date, Dateindex, Yearindex};
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct Decadeindex(u8);
|
||||
pub struct DecadeIndex(u8);
|
||||
|
||||
impl From<u8> for Decadeindex {
|
||||
impl From<u8> for DecadeIndex {
|
||||
fn from(value: u8) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Decadeindex {
|
||||
impl From<usize> for DecadeIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u8)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Decadeindex> for usize {
|
||||
fn from(value: Decadeindex) -> Self {
|
||||
impl From<DecadeIndex> for usize {
|
||||
fn from(value: DecadeIndex) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Decadeindex {
|
||||
impl Add<usize> for DecadeIndex {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
@@ -51,13 +51,13 @@ impl Add<usize> for Decadeindex {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Dateindex> for Decadeindex {
|
||||
fn from(value: Dateindex) -> Self {
|
||||
impl From<DateIndex> for DecadeIndex {
|
||||
fn from(value: DateIndex) -> Self {
|
||||
Self::from(Date::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Date> for Decadeindex {
|
||||
impl From<Date> for DecadeIndex {
|
||||
fn from(value: Date) -> Self {
|
||||
let year = value.year();
|
||||
if year < 2000 {
|
||||
@@ -67,14 +67,14 @@ impl From<Date> for Decadeindex {
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for Decadeindex {
|
||||
impl CheckedSub for DecadeIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Yearindex> for Decadeindex {
|
||||
fn from(value: Yearindex) -> Self {
|
||||
impl From<YearIndex> for DecadeIndex {
|
||||
fn from(value: YearIndex) -> Self {
|
||||
let v = usize::from(value);
|
||||
if v == 0 {
|
||||
Self(0)
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use std::{fmt::Debug, ops::Add};
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
ops::{Add, Div},
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
@@ -23,27 +26,35 @@ use super::Height;
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct Difficultyepoch(u16);
|
||||
pub struct DifficultyEpoch(u16);
|
||||
|
||||
impl From<u16> for Difficultyepoch {
|
||||
impl From<u16> for DifficultyEpoch {
|
||||
fn from(value: u16) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Difficultyepoch {
|
||||
impl From<usize> for DifficultyEpoch {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u16)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Difficultyepoch> for usize {
|
||||
fn from(value: Difficultyepoch) -> Self {
|
||||
impl From<DifficultyEpoch> for usize {
|
||||
fn from(value: DifficultyEpoch) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Difficultyepoch {
|
||||
impl Add for DifficultyEpoch {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self::from(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for DifficultyEpoch {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
@@ -51,13 +62,20 @@ impl Add<usize> for Difficultyepoch {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Height> for Difficultyepoch {
|
||||
impl Div<usize> for DifficultyEpoch {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self::from(self.0 as usize / rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Height> for DifficultyEpoch {
|
||||
fn from(value: Height) -> Self {
|
||||
Self((u32::from(value) / 2016) as u16)
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for Difficultyepoch {
|
||||
impl CheckedSub for DifficultyEpoch {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
|
||||
@@ -1,27 +1,51 @@
|
||||
use std::ops::{Add, Div, Mul};
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
f64,
|
||||
ops::{Add, AddAssign, Div, Mul},
|
||||
};
|
||||
|
||||
use bincode::{Decode, Encode};
|
||||
use byteview::ByteView;
|
||||
use derive_deref::Deref;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use super::{Bitcoin, Cents, Sats};
|
||||
use crate::{CheckedSub, copy_first_8bytes};
|
||||
|
||||
use super::{Bitcoin, Cents, Close, High, Sats, StoredF32, StoredF64};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Default,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Deref,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
)]
|
||||
pub struct Dollars(f64);
|
||||
|
||||
impl Dollars {
|
||||
pub const ZERO: Self = Self(0.0);
|
||||
pub const NAN: Self = Self(f64::NAN);
|
||||
|
||||
pub const fn mint(dollars: f64) -> Self {
|
||||
Self(dollars)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f32> for Dollars {
|
||||
fn from(value: f32) -> Self {
|
||||
Self(value as f64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for Dollars {
|
||||
fn from(value: f64) -> Self {
|
||||
Self(value)
|
||||
@@ -34,12 +58,30 @@ impl From<Cents> for Dollars {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Dollars> for f32 {
|
||||
fn from(value: Dollars) -> Self {
|
||||
value.0 as f32
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Dollars> for f64 {
|
||||
fn from(value: Dollars) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Close<Dollars>> for Dollars {
|
||||
fn from(value: Close<Dollars>) -> Self {
|
||||
Self(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<High<Dollars>> for Dollars {
|
||||
fn from(value: High<Dollars>) -> Self {
|
||||
Self(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Dollars {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as f64)
|
||||
@@ -49,31 +91,246 @@ impl From<usize> for Dollars {
|
||||
impl Add for Dollars {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
Self::from(Cents::from(self) + Cents::from(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<Dollars> for Dollars {
|
||||
type Output = StoredF64;
|
||||
fn div(self, rhs: Dollars) -> Self::Output {
|
||||
if self.is_nan() || rhs == Dollars::ZERO {
|
||||
StoredF64::NAN
|
||||
} else {
|
||||
StoredF64::from(f64::from(self) / f64::from(rhs))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<Close<Dollars>> for Dollars {
|
||||
type Output = StoredF64;
|
||||
fn div(self, rhs: Close<Dollars>) -> Self::Output {
|
||||
if self.is_nan() || *rhs == Dollars::ZERO {
|
||||
StoredF64::NAN
|
||||
} else {
|
||||
StoredF64::from(f64::from(self) / f64::from(*rhs))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<Dollars> for Close<Dollars> {
|
||||
type Output = StoredF64;
|
||||
fn div(self, rhs: Dollars) -> Self::Output {
|
||||
if self.is_nan() || rhs == Dollars::ZERO {
|
||||
StoredF64::NAN
|
||||
} else {
|
||||
StoredF64::from(f64::from(*self) / f64::from(rhs))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for Dollars {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 / rhs as f64)
|
||||
if self.is_nan() || rhs == 0 {
|
||||
Dollars::NAN
|
||||
} else {
|
||||
Self::from(Cents::from(self) / rhs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<Bitcoin> for Dollars {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: Bitcoin) -> Self::Output {
|
||||
if self.is_nan() {
|
||||
self
|
||||
} else {
|
||||
Self(f64::from(self) / f64::from(rhs))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Dollars> for Dollars {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: Dollars) -> Self::Output {
|
||||
Self::from(Cents::from(self) * Cents::from(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Close<Dollars>> for Dollars {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: Close<Dollars>) -> Self::Output {
|
||||
Self::from(Cents::from(self) * Cents::from(*rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Dollars> for Close<Dollars> {
|
||||
type Output = Dollars;
|
||||
fn mul(self, rhs: Dollars) -> Self::Output {
|
||||
Dollars::from(Cents::from(*self) * Cents::from(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<usize> for Close<Dollars> {
|
||||
type Output = Dollars;
|
||||
fn mul(self, rhs: usize) -> Self::Output {
|
||||
Dollars::from(Cents::from(*self) * rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Bitcoin> for Dollars {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: Bitcoin) -> Self::Output {
|
||||
self * Sats::from(rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Bitcoin> for Close<Dollars> {
|
||||
type Output = Dollars;
|
||||
fn mul(self, rhs: Bitcoin) -> Self::Output {
|
||||
*self * Sats::from(rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Sats> for Dollars {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: Sats) -> Self::Output {
|
||||
if self.is_nan() {
|
||||
self
|
||||
} else {
|
||||
Self::from(Cents::from(
|
||||
u128::from(rhs) * u128::from(Cents::from(self)) / u128::from(Sats::ONE_BTC),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<StoredF32> for Dollars {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: StoredF32) -> Self::Output {
|
||||
if rhs.fract() != 0.0 {
|
||||
Self::from(self.0 * *rhs as f64)
|
||||
} else {
|
||||
self * *rhs as i64
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<i64> for Dollars {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: i64) -> Self::Output {
|
||||
Self::from(Cents::from(self) * rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<usize> for Dollars {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: usize) -> Self::Output {
|
||||
if self.is_nan() {
|
||||
self
|
||||
} else {
|
||||
Self::from(Cents::from(self) * rhs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u128> for Dollars {
|
||||
fn from(value: u128) -> Self {
|
||||
Self::from(Cents::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StoredF64> for Dollars {
|
||||
fn from(value: StoredF64) -> Self {
|
||||
Self(*value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Close<Dollars>> for u128 {
|
||||
fn from(value: Close<Dollars>) -> Self {
|
||||
u128::from(*value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Dollars> for u128 {
|
||||
fn from(value: Dollars) -> Self {
|
||||
u128::from(Cents::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for Dollars {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
*self = Dollars::from(Cents::from(*self) + Cents::from(rhs));
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for Dollars {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
if self.is_nan() {
|
||||
Some(self)
|
||||
} else {
|
||||
Cents::from(self)
|
||||
.checked_sub(Cents::from(rhs))
|
||||
.map(Dollars::from)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub<usize> for Dollars {
|
||||
fn checked_sub(self, rhs: usize) -> Option<Self> {
|
||||
Some(Dollars::from(
|
||||
Cents::from(self).checked_sub(Cents::from(rhs)).unwrap(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Dollars {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self.0.is_nan(), other.0.is_nan()) {
|
||||
(true, true) => true,
|
||||
(true, false) => false,
|
||||
(false, true) => false,
|
||||
(false, false) => self.0 == other.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Dollars {}
|
||||
|
||||
#[allow(clippy::derive_ord_xor_partial_ord)]
|
||||
impl Ord for Dollars {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.0.partial_cmp(&other.0).unwrap()
|
||||
impl PartialOrd for Dollars {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
))
|
||||
#[allow(clippy::derive_ord_xor_partial_ord)]
|
||||
impl Ord for Dollars {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
match (self.0.is_nan(), other.0.is_nan()) {
|
||||
(true, true) => Ordering::Equal,
|
||||
(true, false) => Ordering::Less,
|
||||
(false, true) => Ordering::Greater,
|
||||
(false, false) => self.0.partial_cmp(&other.0).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ByteView> for Dollars {
|
||||
fn from(value: ByteView) -> Self {
|
||||
let bytes = copy_first_8bytes(&value).unwrap();
|
||||
Self::from(f64::from_be_bytes(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Dollars> for ByteView {
|
||||
fn from(value: Dollars) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Dollars> for ByteView {
|
||||
fn from(value: &Dollars) -> Self {
|
||||
Self::new(&value.to_be_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,14 @@
|
||||
use std::ops::{Add, Div};
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
ops::{Add, Div},
|
||||
};
|
||||
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use super::{Sats, StoredUsize};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Copy,
|
||||
Serialize,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
#[derive(Debug, Clone, Copy, Serialize, FromBytes, Immutable, IntoBytes, KnownLayout)]
|
||||
pub struct Feerate(f32);
|
||||
|
||||
impl From<(Sats, StoredUsize)> for Feerate {
|
||||
@@ -56,11 +48,34 @@ impl From<usize> for Feerate {
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Feerate {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self.0.is_nan(), other.0.is_nan()) {
|
||||
(true, true) => true,
|
||||
(true, false) => false,
|
||||
(false, true) => false,
|
||||
(false, false) => self.0 == other.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
impl PartialOrd for Feerate {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::derive_ord_xor_partial_ord)]
|
||||
impl Ord for Feerate {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
match (self.0.is_nan(), other.0.is_nan()) {
|
||||
(true, true) => Ordering::Equal,
|
||||
(true, false) => Ordering::Less,
|
||||
(false, true) => Ordering::Greater,
|
||||
(false, false) => self.0.partial_cmp(&other.0).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use std::{fmt::Debug, ops::Add};
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
ops::{Add, Div},
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
@@ -23,27 +26,41 @@ use super::Height;
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct Halvingepoch(u8);
|
||||
pub struct HalvingEpoch(u8);
|
||||
|
||||
impl From<u8> for Halvingepoch {
|
||||
impl HalvingEpoch {
|
||||
pub fn new(value: u8) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for HalvingEpoch {
|
||||
fn from(value: u8) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Halvingepoch {
|
||||
impl From<usize> for HalvingEpoch {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u8)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Halvingepoch> for usize {
|
||||
fn from(value: Halvingepoch) -> Self {
|
||||
impl From<HalvingEpoch> for usize {
|
||||
fn from(value: HalvingEpoch) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Halvingepoch {
|
||||
impl Add for HalvingEpoch {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self::from(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for HalvingEpoch {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
@@ -51,14 +68,21 @@ impl Add<usize> for Halvingepoch {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Height> for Halvingepoch {
|
||||
impl From<Height> for HalvingEpoch {
|
||||
fn from(value: Height) -> Self {
|
||||
Self((u32::from(value) / 210_000) as u8)
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for Halvingepoch {
|
||||
impl CheckedSub for HalvingEpoch {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for HalvingEpoch {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self::from(self.0 as usize / rhs)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,15 @@ use std::{
|
||||
};
|
||||
|
||||
use bitcoincore_rpc::{Client, RpcApi};
|
||||
use byteview::ByteView;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
use zerocopy::{FromBytes, IntoBytes};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
use super::StoredUsize;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
@@ -28,8 +32,8 @@ use crate::CheckedSub;
|
||||
pub struct Height(u32);
|
||||
|
||||
impl Height {
|
||||
pub const ZERO: Self = Height(0);
|
||||
pub const MAX: Self = Height(u32::MAX);
|
||||
pub const ZERO: Self = Self(0);
|
||||
pub const MAX: Self = Self(u32::MAX);
|
||||
|
||||
pub fn new(height: u32) -> Self {
|
||||
Self(height)
|
||||
@@ -146,11 +150,17 @@ impl From<u64> for Height {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StoredUsize> for Height {
|
||||
fn from(value: StoredUsize) -> Self {
|
||||
Self(*value as u32)
|
||||
}
|
||||
}
|
||||
impl From<usize> for Height {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Height> for usize {
|
||||
fn from(value: Height) -> Self {
|
||||
value.0 as usize
|
||||
@@ -181,12 +191,6 @@ impl From<bitcoin::locktime::absolute::Height> for Height {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Height> for bitcoin::locktime::absolute::Height {
|
||||
fn from(value: Height) -> Self {
|
||||
bitcoin::locktime::absolute::Height::from_consensus(value.0).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&std::path::Path> for Height {
|
||||
type Error = crate::Error;
|
||||
fn try_from(value: &std::path::Path) -> Result<Self, Self::Error> {
|
||||
@@ -194,10 +198,9 @@ impl TryFrom<&std::path::Path> for Height {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<byteview::ByteView> for Height {
|
||||
type Error = crate::Error;
|
||||
fn try_from(value: byteview::ByteView) -> Result<Self, Self::Error> {
|
||||
Ok(Self::read_from_bytes(&value)?)
|
||||
impl From<ByteView> for Height {
|
||||
fn from(value: byteview::ByteView) -> Self {
|
||||
Self::read_from_bytes(&value).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-18
@@ -2,7 +2,7 @@ use std::ops::{Add, AddAssign};
|
||||
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
@@ -25,49 +25,49 @@ use super::Vin;
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Txinindex(u64);
|
||||
pub struct InputIndex(u64);
|
||||
|
||||
impl Txinindex {
|
||||
impl InputIndex {
|
||||
pub fn incremented(self) -> Self {
|
||||
Self(*self + 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Txinindex> for Txinindex {
|
||||
impl Add<InputIndex> for InputIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Txinindex) -> Self::Output {
|
||||
fn add(self, rhs: InputIndex) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Vin> for Txinindex {
|
||||
impl Add<Vin> for InputIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Vin) -> Self::Output {
|
||||
Self(self.0 + u64::from(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Txinindex {
|
||||
impl Add<usize> for InputIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 + rhs as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<Txinindex> for Txinindex {
|
||||
fn add_assign(&mut self, rhs: Txinindex) {
|
||||
impl AddAssign<InputIndex> for InputIndex {
|
||||
fn add_assign(&mut self, rhs: InputIndex) {
|
||||
self.0 += rhs.0
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub<Txinindex> for Txinindex {
|
||||
impl CheckedSub<InputIndex> for InputIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self::from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Txinindex> for u32 {
|
||||
fn from(value: Txinindex) -> Self {
|
||||
impl From<InputIndex> for u32 {
|
||||
fn from(value: InputIndex) -> Self {
|
||||
if value.0 > u32::MAX as u64 {
|
||||
panic!()
|
||||
}
|
||||
@@ -75,24 +75,24 @@ impl From<Txinindex> for u32 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Txinindex {
|
||||
impl From<u64> for InputIndex {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<Txinindex> for u64 {
|
||||
fn from(value: Txinindex) -> Self {
|
||||
impl From<InputIndex> for u64 {
|
||||
fn from(value: InputIndex) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Txinindex {
|
||||
impl From<usize> for InputIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u64)
|
||||
}
|
||||
}
|
||||
impl From<Txinindex> for usize {
|
||||
fn from(value: Txinindex) -> Self {
|
||||
impl From<InputIndex> for usize {
|
||||
fn from(value: InputIndex) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
use serde::Serialize;
|
||||
use zerocopy::{Immutable, IntoBytes, KnownLayout, TryFromBytes};
|
||||
|
||||
use super::{Height, Timestamp};
|
||||
|
||||
#[derive(Debug, Immutable, Clone, Copy, IntoBytes, KnownLayout, TryFromBytes, Serialize)]
|
||||
#[repr(C)]
|
||||
#[allow(warnings)]
|
||||
pub enum LockTime {
|
||||
Height(Height),
|
||||
Timestamp(Timestamp),
|
||||
}
|
||||
|
||||
impl From<bitcoin::absolute::LockTime> for LockTime {
|
||||
fn from(value: bitcoin::absolute::LockTime) -> Self {
|
||||
match value {
|
||||
bitcoin::absolute::LockTime::Blocks(h) => LockTime::Height(h.into()),
|
||||
bitcoin::absolute::LockTime::Seconds(t) => LockTime::Timestamp(t.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LockTime> for bitcoin::absolute::LockTime {
|
||||
fn from(value: LockTime) -> Self {
|
||||
match value {
|
||||
LockTime::Height(h) => bitcoin::absolute::LockTime::Blocks(h.into()),
|
||||
LockTime::Timestamp(t) => bitcoin::absolute::LockTime::Seconds(t.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
mod addressbytes;
|
||||
mod addressindex;
|
||||
mod addressindextxoutindex;
|
||||
mod addresstype;
|
||||
mod addresstypeindex;
|
||||
mod addressbyteshash;
|
||||
// mod addressindex;
|
||||
// mod addressindexoutputindex;
|
||||
// mod addresstype;
|
||||
mod bitcoin;
|
||||
mod blockhash;
|
||||
mod blockhashprefix;
|
||||
mod cents;
|
||||
mod compressed;
|
||||
mod date;
|
||||
mod dateindex;
|
||||
mod decadeindex;
|
||||
@@ -15,22 +15,28 @@ mod dollars;
|
||||
mod feerate;
|
||||
mod halvingepoch;
|
||||
mod height;
|
||||
mod locktime;
|
||||
mod inputindex;
|
||||
mod monthindex;
|
||||
mod ohlc;
|
||||
mod outputindex;
|
||||
mod outputtype;
|
||||
mod outputtypeindex;
|
||||
mod quarterindex;
|
||||
mod rawlocktime;
|
||||
mod sats;
|
||||
mod stored_f32;
|
||||
mod stored_f64;
|
||||
mod stored_u32;
|
||||
mod stored_u64;
|
||||
mod stored_u8;
|
||||
mod stored_usize;
|
||||
mod timestamp;
|
||||
mod txid;
|
||||
mod txidprefix;
|
||||
mod txindex;
|
||||
mod txinindex;
|
||||
mod txoutindex;
|
||||
mod txversion;
|
||||
mod unit;
|
||||
mod version;
|
||||
mod vin;
|
||||
mod vout;
|
||||
mod weekindex;
|
||||
@@ -38,14 +44,14 @@ mod weight;
|
||||
mod yearindex;
|
||||
|
||||
pub use addressbytes::*;
|
||||
pub use addressindex::*;
|
||||
pub use addressindextxoutindex::*;
|
||||
pub use addresstype::*;
|
||||
pub use addresstypeindex::*;
|
||||
pub use addressbyteshash::*;
|
||||
// pub use addressindex::*;
|
||||
// pub use addressindexoutputindex::*;
|
||||
// pub use addresstype::*;
|
||||
pub use bitcoin::*;
|
||||
pub use blockhash::*;
|
||||
pub use blockhashprefix::*;
|
||||
pub use cents::*;
|
||||
pub use compressed::*;
|
||||
pub use date::*;
|
||||
pub use dateindex::*;
|
||||
pub use decadeindex::*;
|
||||
@@ -54,24 +60,32 @@ pub use dollars::*;
|
||||
pub use feerate::*;
|
||||
pub use halvingepoch::*;
|
||||
pub use height::*;
|
||||
pub use locktime::*;
|
||||
pub use inputindex::*;
|
||||
pub use monthindex::*;
|
||||
pub use ohlc::*;
|
||||
pub use outputindex::*;
|
||||
pub use outputtype::*;
|
||||
pub use outputtypeindex::*;
|
||||
pub use quarterindex::*;
|
||||
pub use rawlocktime::*;
|
||||
pub use sats::*;
|
||||
pub use stored_f32::*;
|
||||
pub use stored_f64::*;
|
||||
pub use stored_u8::*;
|
||||
pub use stored_u32::*;
|
||||
pub use stored_u64::*;
|
||||
pub use stored_usize::*;
|
||||
pub use timestamp::*;
|
||||
pub use txid::*;
|
||||
pub use txidprefix::*;
|
||||
pub use txindex::*;
|
||||
pub use txinindex::*;
|
||||
pub use txoutindex::*;
|
||||
pub use txversion::*;
|
||||
pub use unit::*;
|
||||
pub use version::*;
|
||||
pub use vin::*;
|
||||
pub use vout::*;
|
||||
pub use weekindex::*;
|
||||
pub use weight::*;
|
||||
pub use yearindex::*;
|
||||
|
||||
pub use rlimit;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use std::{fmt::Debug, ops::Add};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
use super::{Date, Dateindex, Yearindex};
|
||||
use super::{Date, DateIndex, YearIndex};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
@@ -23,27 +23,27 @@ use super::{Date, Dateindex, Yearindex};
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct Monthindex(u16);
|
||||
pub struct MonthIndex(u16);
|
||||
|
||||
impl From<u16> for Monthindex {
|
||||
impl From<u16> for MonthIndex {
|
||||
fn from(value: u16) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Monthindex {
|
||||
impl From<usize> for MonthIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u16)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Monthindex> for usize {
|
||||
fn from(value: Monthindex) -> Self {
|
||||
impl From<MonthIndex> for usize {
|
||||
fn from(value: MonthIndex) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Monthindex {
|
||||
impl Add<usize> for MonthIndex {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
@@ -51,19 +51,19 @@ impl Add<usize> for Monthindex {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Dateindex> for Monthindex {
|
||||
fn from(value: Dateindex) -> Self {
|
||||
impl From<DateIndex> for MonthIndex {
|
||||
fn from(value: DateIndex) -> Self {
|
||||
Self::from(Date::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Date> for Monthindex {
|
||||
impl From<Date> for MonthIndex {
|
||||
fn from(value: Date) -> Self {
|
||||
Self(u16::from(Yearindex::from(value)) * 12 + value.month() as u16 - 1)
|
||||
Self(u16::from(YearIndex::from(value)) * 12 + value.month() as u16 - 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for Monthindex {
|
||||
impl CheckedSub for MonthIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@ use std::ops::{Add, Div};
|
||||
|
||||
use derive_deref::Deref;
|
||||
use serde::{Serialize, Serializer, ser::SerializeTuple};
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use super::{Cents, Dollars, Sats};
|
||||
|
||||
#[derive(Debug, Default, Clone, FromBytes, Immutable, IntoBytes, KnownLayout, Serialize)]
|
||||
#[derive(Debug, Default, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
|
||||
#[repr(C)]
|
||||
pub struct OHLCCents {
|
||||
pub open: Open<Cents>,
|
||||
@@ -37,6 +37,20 @@ impl From<Close<Cents>> for OHLCCents {
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for OHLCCents {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
|
||||
#[repr(C)]
|
||||
pub struct OHLCDollars {
|
||||
@@ -439,6 +453,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<f32> for Close<T>
|
||||
where
|
||||
T: From<f32>,
|
||||
{
|
||||
fn from(value: f32) -> Self {
|
||||
Self(T::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<f64> for Close<T>
|
||||
where
|
||||
T: From<f64>,
|
||||
@@ -448,6 +471,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Close<T>> for f32
|
||||
where
|
||||
f32: From<T>,
|
||||
{
|
||||
fn from(value: Close<T>) -> Self {
|
||||
Self::from(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Close<T>> for f64
|
||||
where
|
||||
f64: From<T>,
|
||||
|
||||
+18
-18
@@ -2,7 +2,7 @@ use std::ops::{Add, AddAssign};
|
||||
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
@@ -25,9 +25,9 @@ use super::Vout;
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Txoutindex(u64);
|
||||
pub struct OutputIndex(u64);
|
||||
|
||||
impl Txoutindex {
|
||||
impl OutputIndex {
|
||||
pub const COINBASE: Self = Self(u64::MAX);
|
||||
|
||||
pub fn incremented(self) -> Self {
|
||||
@@ -39,41 +39,41 @@ impl Txoutindex {
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Txoutindex> for Txoutindex {
|
||||
impl Add<OutputIndex> for OutputIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Txoutindex) -> Self::Output {
|
||||
fn add(self, rhs: OutputIndex) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Vout> for Txoutindex {
|
||||
impl Add<Vout> for OutputIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Vout) -> Self::Output {
|
||||
Self(self.0 + u64::from(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Txoutindex {
|
||||
impl Add<usize> for OutputIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 + rhs as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<Txoutindex> for Txoutindex {
|
||||
fn add_assign(&mut self, rhs: Txoutindex) {
|
||||
impl AddAssign<OutputIndex> for OutputIndex {
|
||||
fn add_assign(&mut self, rhs: OutputIndex) {
|
||||
self.0 += rhs.0
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub<Txoutindex> for Txoutindex {
|
||||
impl CheckedSub<OutputIndex> for OutputIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self::from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Txoutindex> for u32 {
|
||||
fn from(value: Txoutindex) -> Self {
|
||||
impl From<OutputIndex> for u32 {
|
||||
fn from(value: OutputIndex) -> Self {
|
||||
if value.0 > u32::MAX as u64 {
|
||||
panic!()
|
||||
}
|
||||
@@ -81,24 +81,24 @@ impl From<Txoutindex> for u32 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Txoutindex {
|
||||
impl From<u64> for OutputIndex {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<Txoutindex> for u64 {
|
||||
fn from(value: Txoutindex) -> Self {
|
||||
impl From<OutputIndex> for u64 {
|
||||
fn from(value: OutputIndex) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Txoutindex {
|
||||
impl From<usize> for OutputIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u64)
|
||||
}
|
||||
}
|
||||
impl From<Txoutindex> for usize {
|
||||
fn from(value: Txoutindex) -> Self {
|
||||
impl From<OutputIndex> for usize {
|
||||
fn from(value: OutputIndex) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
use bitcoin::{ScriptBuf, opcodes::all::OP_PUSHBYTES_2};
|
||||
use serde::Serialize;
|
||||
use zerocopy_derive::{Immutable, IntoBytes, KnownLayout, TryFromBytes};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
TryFromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
#[repr(u8)]
|
||||
pub enum OutputType {
|
||||
P2PK65,
|
||||
P2PK33,
|
||||
P2PKH,
|
||||
P2MS,
|
||||
P2SH,
|
||||
OpReturn,
|
||||
P2WPKH,
|
||||
P2WSH,
|
||||
P2TR,
|
||||
P2A,
|
||||
Empty = 254,
|
||||
Unknown = 255,
|
||||
}
|
||||
|
||||
impl OutputType {
|
||||
pub fn is_spendable(&self) -> bool {
|
||||
match self {
|
||||
Self::P2PK65 => true,
|
||||
Self::P2PK33 => true,
|
||||
Self::P2PKH => true,
|
||||
Self::P2MS => true,
|
||||
Self::P2SH => true,
|
||||
Self::OpReturn => false,
|
||||
Self::P2WPKH => true,
|
||||
Self::P2WSH => true,
|
||||
Self::P2TR => true,
|
||||
Self::P2A => true,
|
||||
Self::Empty => true,
|
||||
Self::Unknown => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_unspendable(&self) -> bool {
|
||||
!self.is_spendable()
|
||||
}
|
||||
|
||||
pub fn as_vec() -> Vec<Self> {
|
||||
vec![
|
||||
Self::P2PK65,
|
||||
Self::P2PK33,
|
||||
Self::P2PKH,
|
||||
Self::P2MS,
|
||||
Self::P2SH,
|
||||
Self::OpReturn,
|
||||
Self::P2WPKH,
|
||||
Self::P2WSH,
|
||||
Self::P2TR,
|
||||
Self::P2A,
|
||||
Self::Empty,
|
||||
Self::Unknown,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&ScriptBuf> for OutputType {
|
||||
fn from(script: &ScriptBuf) -> Self {
|
||||
if script.is_p2pk() {
|
||||
let bytes = script.as_bytes();
|
||||
|
||||
match bytes.len() {
|
||||
67 => Self::P2PK65,
|
||||
35 => Self::P2PK33,
|
||||
_ => {
|
||||
dbg!(bytes);
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
} else if script.is_p2pkh() {
|
||||
Self::P2PKH
|
||||
} else if script.is_multisig() {
|
||||
Self::P2MS
|
||||
} else if script.is_p2sh() {
|
||||
Self::P2SH
|
||||
} else if script.is_op_return() {
|
||||
Self::OpReturn
|
||||
} else if script.is_p2wpkh() {
|
||||
Self::P2WPKH
|
||||
} else if script.is_p2wsh() {
|
||||
Self::P2WSH
|
||||
} else if script.is_p2tr() {
|
||||
Self::P2TR
|
||||
} else if script.witness_version() == Some(bitcoin::WitnessVersion::V1)
|
||||
&& script.len() == 4
|
||||
&& script.as_bytes()[1] == OP_PUSHBYTES_2.to_u8()
|
||||
&& script.as_bytes()[2..4] == [78, 115]
|
||||
{
|
||||
Self::P2A
|
||||
} else if script.is_empty() {
|
||||
Self::Empty
|
||||
} else {
|
||||
Self::Unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,634 @@
|
||||
use std::ops::Add;
|
||||
|
||||
use byteview::ByteView;
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, IntoBytes};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct OutputTypeIndex(u32);
|
||||
|
||||
impl OutputTypeIndex {
|
||||
pub fn increment(&mut self) {
|
||||
self.0 += 1;
|
||||
}
|
||||
|
||||
pub fn incremented(self) -> Self {
|
||||
Self(self.0 + 1)
|
||||
}
|
||||
|
||||
pub fn copy_then_increment(&mut self) -> Self {
|
||||
let i = *self;
|
||||
self.increment();
|
||||
i
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for OutputTypeIndex {
|
||||
fn from(value: u32) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for OutputTypeIndex {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(value as u32)
|
||||
}
|
||||
}
|
||||
impl From<OutputTypeIndex> for u64 {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
value.0 as u64
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for OutputTypeIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u32)
|
||||
}
|
||||
}
|
||||
impl From<OutputTypeIndex> for usize {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for OutputTypeIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 + rhs as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<OutputTypeIndex> for OutputTypeIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: OutputTypeIndex) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
impl From<ByteView> for OutputTypeIndex {
|
||||
fn from(value: ByteView) -> Self {
|
||||
Self::read_from_bytes(&value).unwrap()
|
||||
}
|
||||
}
|
||||
impl From<OutputTypeIndex> for ByteView {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct EmptyOutputIndex(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for EmptyOutputIndex {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<EmptyOutputIndex> for usize {
|
||||
fn from(value: EmptyOutputIndex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for EmptyOutputIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for EmptyOutputIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<EmptyOutputIndex> for EmptyOutputIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2MSIndex(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for P2MSIndex {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2MSIndex> for usize {
|
||||
fn from(value: P2MSIndex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2MSIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2MSIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<P2MSIndex> for P2MSIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2AIndex(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for P2AIndex {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2AIndex> for usize {
|
||||
fn from(value: P2AIndex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2AIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2AIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<P2AIndex> for P2AIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct OpReturnIndex(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for OpReturnIndex {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<OpReturnIndex> for usize {
|
||||
fn from(value: OpReturnIndex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for OpReturnIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for OpReturnIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<OpReturnIndex> for OpReturnIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct UnknownOutputIndex(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for UnknownOutputIndex {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<UnknownOutputIndex> for usize {
|
||||
fn from(value: UnknownOutputIndex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for UnknownOutputIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for UnknownOutputIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<UnknownOutputIndex> for UnknownOutputIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2PK33Index(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for P2PK33Index {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2PK33Index> for usize {
|
||||
fn from(value: P2PK33Index) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2PK33Index {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2PK33Index {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<P2PK33Index> for P2PK33Index {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2PK65Index(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for P2PK65Index {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2PK65Index> for usize {
|
||||
fn from(value: P2PK65Index) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2PK65Index {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2PK65Index {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<P2PK65Index> for P2PK65Index {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2PKHIndex(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for P2PKHIndex {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2PKHIndex> for usize {
|
||||
fn from(value: P2PKHIndex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2PKHIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2PKHIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<P2PKHIndex> for P2PKHIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2SHIndex(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for P2SHIndex {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2SHIndex> for usize {
|
||||
fn from(value: P2SHIndex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2SHIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2SHIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<P2SHIndex> for P2SHIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2TRIndex(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for P2TRIndex {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2TRIndex> for usize {
|
||||
fn from(value: P2TRIndex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2TRIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2TRIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<P2TRIndex> for P2TRIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2WPKHIndex(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for P2WPKHIndex {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2WPKHIndex> for usize {
|
||||
fn from(value: P2WPKHIndex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2WPKHIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2WPKHIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<P2WPKHIndex> for P2WPKHIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2WSHIndex(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for P2WSHIndex {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2WSHIndex> for usize {
|
||||
fn from(value: P2WSHIndex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2WSHIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2WSHIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<P2WSHIndex> for P2WSHIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
use std::{fmt::Debug, ops::Add};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
use super::Monthindex;
|
||||
use super::MonthIndex;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
@@ -23,27 +23,27 @@ use super::Monthindex;
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct Quarterindex(u16);
|
||||
pub struct QuarterIndex(u16);
|
||||
|
||||
impl From<u16> for Quarterindex {
|
||||
impl From<u16> for QuarterIndex {
|
||||
fn from(value: u16) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Quarterindex {
|
||||
impl From<usize> for QuarterIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u16)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Quarterindex> for usize {
|
||||
fn from(value: Quarterindex) -> Self {
|
||||
impl From<QuarterIndex> for usize {
|
||||
fn from(value: QuarterIndex) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Quarterindex {
|
||||
impl Add<usize> for QuarterIndex {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
@@ -51,13 +51,13 @@ impl Add<usize> for Quarterindex {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Monthindex> for Quarterindex {
|
||||
fn from(value: Monthindex) -> Self {
|
||||
impl From<MonthIndex> for QuarterIndex {
|
||||
fn from(value: MonthIndex) -> Self {
|
||||
Self((usize::from(value) / 3) as u16)
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for Quarterindex {
|
||||
impl CheckedSub for QuarterIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
use bitcoin::absolute::LockTime;
|
||||
use serde::Serialize;
|
||||
use zerocopy_derive::{Immutable, IntoBytes, KnownLayout, TryFromBytes};
|
||||
|
||||
#[derive(Debug, Immutable, Clone, Copy, IntoBytes, KnownLayout, TryFromBytes, Serialize)]
|
||||
pub struct RawLockTime(u32);
|
||||
|
||||
impl From<LockTime> for RawLockTime {
|
||||
fn from(value: LockTime) -> Self {
|
||||
Self(value.to_consensus_u32())
|
||||
}
|
||||
}
|
||||
|
||||
const CONSENSUS_DELIMITER: u32 = 500_000_000;
|
||||
|
||||
impl From<RawLockTime> for LockTime {
|
||||
fn from(value: RawLockTime) -> Self {
|
||||
let value = value.0;
|
||||
if value >= CONSENSUS_DELIMITER {
|
||||
bitcoin::locktime::absolute::Height::from_consensus(value)
|
||||
.unwrap()
|
||||
.into()
|
||||
} else {
|
||||
bitcoin::locktime::absolute::Time::from_consensus(value)
|
||||
.unwrap()
|
||||
.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,15 @@ use std::{
|
||||
ops::{Add, AddAssign, Div, Mul, SubAssign},
|
||||
};
|
||||
|
||||
use bincode::{Decode, Encode};
|
||||
use bitcoin::Amount;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
use byteview::ByteView;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
use crate::{CheckedSub, copy_first_8bytes};
|
||||
|
||||
use super::{Bitcoin, Dollars, Height};
|
||||
use super::{Bitcoin, Cents, Dollars, Height};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
@@ -25,22 +27,36 @@ use super::{Bitcoin, Dollars, Height};
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
)]
|
||||
pub struct Sats(u64);
|
||||
|
||||
#[allow(clippy::inconsistent_digit_grouping)]
|
||||
impl Sats {
|
||||
pub const ZERO: Self = Self(0);
|
||||
pub const ONE_BTC: Self = Self(100_000_000);
|
||||
pub const MAX: Self = Self(u64::MAX);
|
||||
pub const ONE_BTC: Self = Self(1_00_000_000);
|
||||
pub const FIFTY_BTC: Self = Self(50_00_000_000);
|
||||
|
||||
pub fn new(sats: u64) -> Self {
|
||||
Self(sats)
|
||||
}
|
||||
|
||||
pub fn is_zero(&self) -> bool {
|
||||
*self == Self::ZERO
|
||||
}
|
||||
|
||||
pub fn is_not_zero(&self) -> bool {
|
||||
*self != Self::ZERO
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Sats {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Sats) -> Self::Output {
|
||||
Sats::from(self.0 + rhs.0)
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self::from(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +72,12 @@ impl CheckedSub<Sats> for Sats {
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub<usize> for Sats {
|
||||
fn checked_sub(self, rhs: usize) -> Option<Self> {
|
||||
self.0.checked_sub(rhs as u64).map(Self::from)
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign for Sats {
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
*self = self.checked_sub(rhs).unwrap();
|
||||
@@ -65,21 +87,28 @@ impl SubAssign for Sats {
|
||||
impl Mul<Sats> for Sats {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: Sats) -> Self::Output {
|
||||
Sats::from(self.0 * rhs.0)
|
||||
Sats::from(self.0.checked_mul(rhs.0).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<usize> for Sats {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: usize) -> Self::Output {
|
||||
Sats::from(self.0.checked_mul(rhs as u64).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<u64> for Sats {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: u64) -> Self::Output {
|
||||
Sats::from(self.0 * rhs)
|
||||
Sats::from(self.0.checked_mul(rhs).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Height> for Sats {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: Height) -> Self::Output {
|
||||
Sats::from(self.0 * u64::from(rhs))
|
||||
Sats::from(self.0.checked_mul(u64::from(rhs)).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +122,23 @@ impl Sum for Sats {
|
||||
impl Div<Dollars> for Sats {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: Dollars) -> Self::Output {
|
||||
Self((self.0 as f64 / f64::from(rhs)) as u64)
|
||||
let raw_cents = u64::from(Cents::from(rhs));
|
||||
if raw_cents != 0 {
|
||||
Self(self.0 * 100 / raw_cents)
|
||||
} else {
|
||||
Self::MAX
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<Sats> for Sats {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: Sats) -> Self::Output {
|
||||
if rhs.0 == 0 {
|
||||
Self(0)
|
||||
} else {
|
||||
Self(self.0 / rhs.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +163,7 @@ impl From<usize> for Sats {
|
||||
|
||||
impl From<f64> for Sats {
|
||||
fn from(value: f64) -> Self {
|
||||
Self(value as u64)
|
||||
Self(value.round() as u64)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,6 +173,12 @@ impl From<Sats> for f64 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Sats> for usize {
|
||||
fn from(value: Sats) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Amount> for Sats {
|
||||
fn from(value: Amount) -> Self {
|
||||
Self(value.to_sat())
|
||||
@@ -141,7 +192,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)).round() as u64)
|
||||
Self((f64::from(value) * (Sats::ONE_BTC.0 as f64)).round() as u64)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,3 +201,44 @@ impl From<Sats> for u64 {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u128> for Sats {
|
||||
fn from(value: u128) -> Self {
|
||||
if value > u64::MAX as u128 {
|
||||
panic!("u128 bigger than u64")
|
||||
}
|
||||
Self(value as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Sats> for u128 {
|
||||
fn from(value: Sats) -> Self {
|
||||
value.0 as u128
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ByteView> for Sats {
|
||||
fn from(value: ByteView) -> Self {
|
||||
let bytes = copy_first_8bytes(&value).unwrap();
|
||||
Self::from(u64::from_be_bytes(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Sats> for ByteView {
|
||||
fn from(value: &Sats) -> Self {
|
||||
Self::new(&value.0.to_be_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Sats> for ByteView {
|
||||
fn from(value: Sats) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Sats> for usize {
|
||||
type Output = Sats;
|
||||
fn mul(self, rhs: Sats) -> Self::Output {
|
||||
Self::Output::from(rhs.0 * self as u64)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
use core::panic;
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
ops::{Add, Div, Mul, Sub},
|
||||
};
|
||||
|
||||
use derive_deref::Deref;
|
||||
use serde::Serialize;
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
use super::{Dollars, StoredF64};
|
||||
|
||||
#[derive(
|
||||
Debug, Deref, Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout, Serialize,
|
||||
)]
|
||||
pub struct StoredF32(f32);
|
||||
|
||||
impl From<f32> for StoredF32 {
|
||||
fn from(value: f32) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for StoredF32 {
|
||||
fn from(value: f64) -> Self {
|
||||
if value > f32::MAX as f64 {
|
||||
panic!("f64 is too big")
|
||||
}
|
||||
Self(value as f32)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StoredF32> for f64 {
|
||||
fn from(value: StoredF32) -> Self {
|
||||
value.0 as f64
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StoredF64> for StoredF32 {
|
||||
fn from(value: StoredF64) -> Self {
|
||||
Self(*value as f32)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for StoredF32 {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as f32)
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub<StoredF32> for StoredF32 {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
Some(Self(self.0 - rhs.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for StoredF32 {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 / rhs as f32)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for StoredF32 {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StoredF32> for f32 {
|
||||
fn from(value: StoredF32) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Dollars> for StoredF32 {
|
||||
fn from(value: Dollars) -> Self {
|
||||
StoredF32::from(f64::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<Dollars> for StoredF32 {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: Dollars) -> Self::Output {
|
||||
Self::from(self.0 as f64 / *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<StoredF32> for StoredF32 {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: StoredF32) -> Self::Output {
|
||||
Self::from(self.0 / rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<usize> for StoredF32 {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 * rhs as f32)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<StoredF32> for usize {
|
||||
type Output = StoredF32;
|
||||
fn mul(self, rhs: StoredF32) -> Self::Output {
|
||||
StoredF32(self as f32 * rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<StoredF32> for StoredF32 {
|
||||
type Output = Self;
|
||||
fn sub(self, rhs: StoredF32) -> Self::Output {
|
||||
Self(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for StoredF32 {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self.0.is_nan(), other.0.is_nan()) {
|
||||
(true, true) => true,
|
||||
(true, false) => false,
|
||||
(false, true) => false,
|
||||
(false, false) => self.0 == other.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for StoredF32 {}
|
||||
|
||||
#[allow(clippy::derive_ord_xor_partial_ord)]
|
||||
impl PartialOrd for StoredF32 {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::derive_ord_xor_partial_ord)]
|
||||
impl Ord for StoredF32 {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
match (self.0.is_nan(), other.0.is_nan()) {
|
||||
(true, true) => Ordering::Equal,
|
||||
(true, false) => Ordering::Less,
|
||||
(false, true) => Ordering::Greater,
|
||||
(false, false) => self.0.partial_cmp(&other.0).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
f64,
|
||||
ops::{Add, Div, Mul},
|
||||
};
|
||||
|
||||
use derive_deref::Deref;
|
||||
use serde::Serialize;
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::{Bitcoin, CheckedSub, Dollars};
|
||||
|
||||
#[derive(
|
||||
Debug, Deref, Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout, Serialize,
|
||||
)]
|
||||
pub struct StoredF64(f64);
|
||||
|
||||
impl StoredF64 {
|
||||
pub const NAN: Self = Self(f64::NAN);
|
||||
}
|
||||
|
||||
impl From<f64> for StoredF64 {
|
||||
fn from(value: f64) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for StoredF64 {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as f64)
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub<StoredF64> for StoredF64 {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
Some(Self(self.0 - rhs.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<usize> for StoredF64 {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 * rhs as f64)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for StoredF64 {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 / rhs as f64)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for StoredF64 {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StoredF64> for f64 {
|
||||
fn from(value: StoredF64) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Dollars> for StoredF64 {
|
||||
fn from(value: Dollars) -> Self {
|
||||
Self(f64::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub<usize> for StoredF64 {
|
||||
fn checked_sub(self, rhs: usize) -> Option<Self> {
|
||||
Some(Self(self.0 - rhs as f64))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for StoredF64 {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self.0.is_nan(), other.0.is_nan()) {
|
||||
(true, true) => true,
|
||||
(true, false) => false,
|
||||
(false, true) => false,
|
||||
(false, false) => self.0 == other.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for StoredF64 {}
|
||||
|
||||
#[allow(clippy::derive_ord_xor_partial_ord)]
|
||||
impl PartialOrd for StoredF64 {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::derive_ord_xor_partial_ord)]
|
||||
impl Ord for StoredF64 {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
match (self.0.is_nan(), other.0.is_nan()) {
|
||||
(true, true) => Ordering::Equal,
|
||||
(true, false) => Ordering::Less,
|
||||
(false, true) => Ordering::Greater,
|
||||
(false, false) => self.0.partial_cmp(&other.0).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Bitcoin> for StoredF64 {
|
||||
fn from(value: Bitcoin) -> Self {
|
||||
Self(f64::from(value))
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,20 @@ use std::ops::{Add, Div};
|
||||
|
||||
use derive_deref::Deref;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
use super::{
|
||||
EmptyOutputIndex, OpReturnIndex, P2AIndex, P2MSIndex, P2PK33Index, P2PK65Index, P2PKHIndex,
|
||||
P2SHIndex, P2TRIndex, P2WPKHIndex, P2WSHIndex, UnknownOutputIndex,
|
||||
};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Default,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
@@ -39,6 +45,9 @@ impl From<u32> for StoredU32 {
|
||||
|
||||
impl From<usize> for StoredU32 {
|
||||
fn from(value: usize) -> Self {
|
||||
if value > u32::MAX as usize {
|
||||
panic!("usize too big (value = {value})")
|
||||
}
|
||||
Self(value as u32)
|
||||
}
|
||||
}
|
||||
@@ -77,3 +86,81 @@ impl From<StoredU32> for f64 {
|
||||
value.0 as f64
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StoredU32> for usize {
|
||||
fn from(value: StoredU32) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2PK65Index> for StoredU32 {
|
||||
fn from(value: P2PK65Index) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2PK33Index> for StoredU32 {
|
||||
fn from(value: P2PK33Index) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2PKHIndex> for StoredU32 {
|
||||
fn from(value: P2PKHIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OpReturnIndex> for StoredU32 {
|
||||
fn from(value: OpReturnIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2MSIndex> for StoredU32 {
|
||||
fn from(value: P2MSIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2SHIndex> for StoredU32 {
|
||||
fn from(value: P2SHIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2WSHIndex> for StoredU32 {
|
||||
fn from(value: P2WSHIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2WPKHIndex> for StoredU32 {
|
||||
fn from(value: P2WPKHIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2TRIndex> for StoredU32 {
|
||||
fn from(value: P2TRIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2AIndex> for StoredU32 {
|
||||
fn from(value: P2AIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UnknownOutputIndex> for StoredU32 {
|
||||
fn from(value: UnknownOutputIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EmptyOutputIndex> for StoredU32 {
|
||||
fn from(value: EmptyOutputIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@ use std::ops::{Add, Div};
|
||||
|
||||
use derive_deref::Deref;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
use super::{Txindex, Txinindex, Txoutindex};
|
||||
use super::{InputIndex, OutputIndex, TxIndex};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
@@ -80,20 +80,20 @@ impl From<StoredU64> for f64 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Txindex> for StoredU64 {
|
||||
fn from(value: Txindex) -> Self {
|
||||
impl From<TxIndex> for StoredU64 {
|
||||
fn from(value: TxIndex) -> Self {
|
||||
Self(*value as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Txinindex> for StoredU64 {
|
||||
fn from(value: Txinindex) -> Self {
|
||||
impl From<InputIndex> for StoredU64 {
|
||||
fn from(value: InputIndex) -> Self {
|
||||
Self(*value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Txoutindex> for StoredU64 {
|
||||
fn from(value: Txoutindex) -> Self {
|
||||
impl From<OutputIndex> for StoredU64 {
|
||||
fn from(value: OutputIndex) -> Self {
|
||||
Self(*value)
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user