Compare commits

...

69 Commits

Author SHA1 Message Date
nym21 7562f51e07 release: v0.0.36 2025-05-13 13:01:32 +02:00
nym21 09bba99e68 kibo: add priceline 2025-05-13 13:01:11 +02:00
nym21 9d674cd49b global: snapshot 2025-05-13 11:46:03 +02:00
nym21 88a0c9ea03 global: returns (lump sum vs dca) 2025-05-13 01:27:21 +02:00
nym21 5014e0ce3e release: v0.0.35 2025-05-12 12:56:08 +02:00
nym21 b7a1ee9ebc global: averages + ratio datasets 2025-05-12 12:55:40 +02:00
nym21 292ceddd66 comp + kibo: add market smas 2025-05-10 13:17:51 +02:00
nym21 4b52b80000 release: v0.0.34 2025-05-09 21:35:07 +02:00
nym21 9f20664c6e global: add some market charts 2025-05-09 16:04:54 +02:00
nym21 851a6aac0e release: v0.0.33 2025-05-08 12:53:19 +02:00
nym21 1f1e73c47a vec: computed: fix eager path + delete path if lazy 2025-05-08 12:31:31 +02:00
nym21 112f61ca18 release: v0.0.32 2025-05-08 11:17:35 +02:00
nym21 96eeacbe2b lazy: done 2025-05-08 11:15:47 +02:00
nym21 3f62da879c comp + lazy: part 6 2025-05-06 12:23:37 +02:00
nym21 aa30feb875 comp + vec: snapshot before bug hunting 2025-05-06 00:44:39 +02:00
nym21 9ba3c2b7c5 global: big vec refactor + lazy 2025-05-05 12:47:52 +02:00
nym21 320c708e10 computer: lazy part 4 2025-05-03 17:28:48 +02:00
nym21 efa7294f59 computer: lazy part 3 2025-05-03 11:44:33 +02:00
nym21 ae0e092935 computer: lazy part 2 2025-05-01 20:52:39 +02:00
nym21 c77aecbfce computer: lazy part 1 2025-05-01 17:25:59 +02:00
nym21 700352ec45 vec: caching only in iter 2025-04-30 18:29:18 +02:00
nym21 664b125ce2 release: v0.0.31 2025-04-30 01:12:28 +02:00
nym21 5f4b1c9e32 global: fixes 2025-04-30 01:11:42 +02:00
nym21 d11d3f19bd fix: old X links that now directed to impersonater 2025-04-29 15:04:59 +02:00
nym21 f34f4f2738 computer: remove last indexes 2025-04-29 15:02:41 +02:00
nym21 15db7c2310 computer: use count instead of last_index 2025-04-29 11:33:14 +02:00
nym21 f9257ed04d global: vec iter part 2 2025-04-28 18:30:11 +02:00
nym21 15e6ef8488 computer: remove the need for &mut vecs 2025-04-28 11:21:28 +02:00
nym21 9ae0a57f22 global: snapshot 2025-04-27 16:29:21 +02:00
nym21 1e38c21f8e vec: make collect_range use into_iter 2025-04-27 10:39:14 +02:00
nym21 bdc3c19163 vec: iter + global: snapshot 2025-04-27 00:21:21 +02:00
nym21 d55478da54 kibo: remove old packages versions 2025-04-26 17:28:41 +02:00
nym21 82bcc55645 global: fixes + snapshot + packages 2025-04-26 17:22:58 +02:00
nym21 07618ebe43 global: renames + refactor + p2a support 2025-04-25 18:16:23 +02:00
nym21 1492834d1e fjall: use a single keyspace for all stores + core: locktime -> rawlocktime 2025-04-24 15:59:13 +02:00
nym21 5ab6197356 computer: init lazy/eager 2025-04-23 22:36:10 +02:00
nym21 0a789fe551 release: v0.0.30 2025-04-23 00:07:41 +02:00
nym21 caa8ff23ed kibo: fix charts data fetch 2025-04-23 00:04:09 +02:00
nym21 ee30d1d36d release: v0.0.29 2025-04-22 19:34:55 +02:00
nym21 0d9415db9d kibo: fix add ts-ignore 2025-04-22 19:33:57 +02:00
nym21 8020e1126f kibo: database: part 2 2025-04-22 19:31:30 +02:00
nym21 3439422057 kibo: database: part 1 2025-04-21 23:17:37 +02:00
nym21 68d2bf736f release: v0.0.28 2025-04-19 11:46:05 +02:00
nym21 d78c39fd8c computer + kibo: part 14 - fixes 2025-04-19 11:45:26 +02:00
nym21 b1dcad86b4 release: v0.0.27 2025-04-18 19:41:13 +02:00
nym21 9b6124074d dist: another fix 2025-04-18 19:40:09 +02:00
nym21 02cbaa1e80 release: v0.0.26 2025-04-18 19:00:19 +02:00
nym21 a12f1321c7 dist: fix format tag version 2025-04-18 18:59:53 +02:00
nym21 8b67f592ac release: v0.0.25 2025-04-18 18:48:10 +02:00
nym21 319d17b337 dist: fix ubuntu version 2025-04-18 18:45:27 +02:00
nym21 476eaa85da github: add manual trigger 2025-04-18 18:37:51 +02:00
nym21 d26099855c dist: update ubuntu version 2025-04-18 18:36:18 +02:00
nym21 e47456da17 release: v0.0.24 2025-04-18 18:22:23 +02:00
nym21 a464d5d0b6 crates: upgrade 2025-04-18 18:20:40 +02:00
nym21 1cfb7b5615 computer + kibo: part 13 2025-04-18 18:08:11 +02:00
nym21 ac7c2f3d03 kibo: cleanup 2025-04-17 17:06:44 +02:00
nym21 638d9e6e01 computer: part 12 2025-04-17 15:22:34 +02:00
nym21 8b9df2a396 parser: readme 2025-04-15 14:40:56 +02:00
nym21 d7fe911bde parser: readme 2025-04-15 11:56:50 +02:00
nym21 0acc3d511b parser: readme 2025-04-15 11:27:48 +02:00
nym21 4cf465f419 computer: unwrap 2025-04-15 11:18:31 +02:00
nym21 b686d317a9 release: v0.0.23 2025-04-14 22:22:19 +02:00
nym21 dcef541852 release: v0.0.22 2025-04-14 21:57:15 +02:00
nym21 abdd733f11 deps: upgrade 2025-04-14 21:56:47 +02:00
nym21 942431e882 computer + kibo: part 11 2025-04-14 16:27:22 +02:00
nym21 1c75ea046c computer + kibo: part 10 2025-04-11 19:21:35 +02:00
nym21 f32b6daa51 release: v0.0.21 2025-04-11 12:01:30 +02:00
nym21 3736d6ba5e computer + kibo: part 9 2025-04-11 12:00:26 +02:00
nym21 9788b01f35 readmes: update discord link yet again 2025-04-10 22:57:09 +02:00
196 changed files with 23834 additions and 13449 deletions
+4 -4
View File
@@ -47,7 +47,7 @@ on:
jobs:
# Run 'dist plan' (or host) to determine what tasks we need to do
plan:
runs-on: "ubuntu-20.04"
runs-on: "ubuntu-latest"
outputs:
val: ${{ steps.plan.outputs.manifest }}
tag: ${{ !github.event.pull_request && github.ref_name || '' }}
@@ -168,7 +168,7 @@ jobs:
needs:
- plan
- build-local-artifacts
runs-on: "ubuntu-20.04"
runs-on: "ubuntu-latest"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json
@@ -218,7 +218,7 @@ jobs:
if: ${{ always() && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
runs-on: "ubuntu-20.04"
runs-on: "ubuntu-latest"
outputs:
val: ${{ steps.host.outputs.manifest }}
steps:
@@ -282,7 +282,7 @@ jobs:
# still allowing individual publish jobs to skip themselves (for prereleases).
# "host" however must run to completion, no skipping allowed!
if: ${{ always() && needs.host.result == 'success' }}
runs-on: "ubuntu-20.04"
runs-on: "ubuntu-latest"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
-1
View File
@@ -33,6 +33,5 @@ paths.d.ts
# Outputs
_outputs
# Logs
.log
Generated
+262 -230
View File
File diff suppressed because it is too large Load Diff
+22 -11
View File
@@ -4,7 +4,7 @@ members = ["crates/*"]
package.description = "The Bitcoin Research Kit is a suite of tools designed to extract, compute and display data stored on a Bitcoin Core node"
package.license = "MIT"
package.edition = "2024"
package.version = "0.0.20"
package.version = "0.0.36"
package.repository = "https://github.com/bitcoinresearchkit/brk"
[profile.release]
@@ -16,7 +16,7 @@ panic = "abort"
inherits = "release"
[workspace.dependencies]
axum = "0.8.3"
axum = "0.8.4"
bitcoin = { version = "0.32.5", features = ["serde"] }
bitcoincore-rpc = "0.19.0"
brk_cli = { version = "0", path = "crates/brk_cli" }
@@ -30,19 +30,22 @@ 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_vec = { version = "0", path = "crates/brk_vec" }
byteview = "0.6.1"
clap = { version = "4.5.35", features = ["derive", "string"] }
color-eyre = "0.6.3"
byteview = "0.7.0"
clap = { version = "4.5.38", features = ["string"] }
clap_derive = "4.5.32"
color-eyre = "0.6.4"
derive_deref = "1.1.1"
fjall = "2.8.0"
jiff = "0.2.5"
fjall = "2.10.0"
jiff = "0.2.13"
log = { version = "0.4.27" }
minreq = { version = "2.13.3", features = ["https", "serde_json"] }
minreq = { version = "2.13.4", features = ["https", "serde_json"] }
rayon = "1.10.0"
serde = { version = "1.0.219", features = ["derive"] }
serde = { version = "1.0.219" }
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.19.0"
zerocopy = { version = "0.8.25" }
zerocopy-derive = "0.8.25"
[workspace.metadata.release]
shared-version = true
@@ -60,3 +63,11 @@ targets = [
"x86_64-apple-darwin",
"x86_64-unknown-linux-gnu",
]
[workspace.metadata.dist.github-custom-runners]
global = "ubuntu-latest"
aarch64-apple-darwin.runner = "macos-14"
x86_64-unknown-linux-gnu.runner = "ubuntu-latest"
x86_64-unknown-linux-gnu.container = { image = "quay.io/pypa/manylinux_2_28_x86_64", host = "x86_64-unknown-linux-musl" }
aarch64-unknown-linux-gnu.runner = "ubuntu-latest"
aarch64-unknown-linux-gnu.container = { image = "quay.io/pypa/manylinux_2_28_x86_64", host = "x86_64-unknown-linux-musl" }
+6 -3
View File
@@ -20,7 +20,7 @@
<a href="https://deps.rs/crate/brk">
<img src="https://deps.rs/crate/brk/latest/status.svg" alt="Dependency status">
</a>
<a href="https://discord.gg/Cvrwpv3zEG">
<a href="https://discord.gg/HaR3wpH3nr">
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
</a>
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
@@ -29,7 +29,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>
@@ -92,8 +92,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.9% 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
+4 -2
View File
@@ -16,12 +16,14 @@ 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"
toml = "0.8.22"
[[bin]]
name = "brk"
+17 -5
View File
@@ -20,7 +20,7 @@
<a href="https://deps.rs/crate/brk_cli">
<img src="https://deps.rs/crate/brk_cli/latest/status.svg" alt="Dependency status">
</a>
<a href="https://discord.gg/Cvrwpv3zEG">
<a href="https://discord.gg/HaR3wpH3nr">
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
</a>
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
@@ -29,7 +29,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>
@@ -59,16 +59,28 @@ To be determined
- Unix based operating system (Mac OS or Linux)
- Ubuntu users need to install `open-ssl` via `sudo apt install libssl-dev pkg-config`
## Install
## Download
### Binaries
You can find a pre-built binary for your operating system on the releases page ([link](https://github.com/bitcoinresearchkit/brk/releases/latest)).
### Cargo
```bash
# Install
cargo install brk # or `cargo install brk_cli`, the result is the same
# Update
cargo install brk # or `cargo install-update -a` if you have `cargo-update` installed
```
## Update
### Source
```bash
cargo install brk # or `cargo install-update -a` if you have `cargo-update` installed
git clone https://github.com/bitcoinresearchkit/brk.git
cd brk/crates/brk
cargo run -r
```
## Usage
+2 -1
View File
@@ -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};
+3 -3
View File
@@ -10,11 +10,11 @@ pub fn query(params: QueryParams) -> color_eyre::Result<()> {
let compressed = config.compressed();
let mut indexer = Indexer::new(config.indexeddir(), compressed, config.check_collisions())?;
let mut indexer = Indexer::new(&config.outputsdir(), compressed, 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(), compressed);
computer.import_vecs(&indexer, config.computation())?;
let query = Query::build(&indexer, &computer);
+76 -49
View File
@@ -1,7 +1,7 @@
use std::{
fs,
path::{Path, PathBuf},
thread::sleep,
thread::{self, sleep},
time::Duration,
};
@@ -12,7 +12,8 @@ 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_vec::Computation;
use clap_derive::{Parser, ValueEnum};
use color_eyre::eyre::eyre;
use log::info;
use serde::{Deserialize, Serialize};
@@ -28,63 +29,89 @@ pub fn run(config: RunConfig) -> color_eyre::Result<()> {
let compressed = config.compressed();
let mut indexer = Indexer::new(config.indexeddir(), compressed, config.check_collisions())?;
let mut indexer = Indexer::new(&config.outputsdir(), compressed, 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(), compressed);
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() {
loop {
let block_count = rpc.get_block_count()?;
let opt = Some(tokio::spawn(async move {
server.serve().await.unwrap();
}));
info!("{} blocks found.", block_count + 1);
sleep(Duration::from_secs(1));
let starting_indexes = indexer.index(&parser, rpc, &exit)?;
opt
} else {
None
};
computer.compute(&mut indexer, starting_indexes, &exit)?;
if config.process() {
loop {
wait_for_synced_node()?;
if let Some(delay) = config.delay() {
sleep(Duration::from_secs(delay))
}
let block_count = rpc.get_block_count()?;
info!("Waiting for new blocks...");
info!("{} blocks found.", block_count + 1);
while block_count == rpc.get_block_count()? {
sleep(Duration::from_secs(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)]
@@ -105,6 +132,10 @@ 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 = 'C', 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>,
@@ -339,18 +370,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")
}
@@ -403,6 +426,10 @@ impl RunConfig {
.then(|| Fetcher::import(Some(self.harsdir().as_path())).unwrap())
}
pub fn computation(&self) -> Computation {
self.computation.unwrap_or_default()
}
pub fn compressed(&self) -> bool {
self.compressed.is_none_or(|b| b)
}
+6
View File
@@ -14,5 +14,11 @@ brk_indexer = { workspace = true }
brk_logger = { workspace = true }
brk_parser = { workspace = true }
brk_vec = { workspace = true }
clap = { workspace = true }
clap_derive = { workspace = true }
color-eyre = { workspace = true }
fjall = { workspace = true }
log = { workspace = true }
rayon = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
+2 -2
View File
@@ -20,7 +20,7 @@
<a href="https://deps.rs/crate/brk_computer">
<img src="https://deps.rs/crate/brk_computer/latest/status.svg" alt="Dependency status">
</a>
<a href="https://discord.gg/Cvrwpv3zEG">
<a href="https://discord.gg/HaR3wpH3nr">
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
</a>
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
@@ -29,7 +29,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>
+25 -15
View File
@@ -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_vec::Computation;
pub fn main() -> color_eyre::Result<()> {
color_eyre::install()?;
@@ -20,25 +21,34 @@ pub fn main() -> color_eyre::Result<()> {
)?));
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 compressed = false;
let mut indexer = Indexer::new(outputs_dir.join("indexed"), compressed, true)?;
indexer.import_stores()?;
indexer.import_vecs()?;
let mut indexer = Indexer::new(outputs_dir, compressed, 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), compressed);
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()
}
+29 -20
View File
@@ -7,14 +7,17 @@ use std::path::{Path, PathBuf};
use brk_exit::Exit;
use brk_fetcher::Fetcher;
use brk_indexer::{Indexer, Indexes};
use brk_indexer::Indexer;
pub use brk_parser::rpc;
use brk_vec::{AnyCollectableVec, Compressed, Computation};
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 {
@@ -26,9 +29,9 @@ pub struct Computer {
}
impl Computer {
pub fn new(computed_dir: PathBuf, fetcher: Option<Fetcher>, compressed: bool) -> Self {
pub fn new(outputs_dir: &Path, fetcher: Option<Fetcher>, compressed: bool) -> Self {
Self {
path: computed_dir,
path: outputs_dir.to_owned(),
fetcher,
vecs: None,
stores: None,
@@ -36,10 +39,16 @@ impl Computer {
}
}
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"),
&self.path.join("vecs/computed"),
indexer,
self.fetcher.is_some(),
computation,
self.compressed,
)?);
Ok(())
@@ -47,8 +56,11 @@ impl Computer {
/// 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(
&self.path.join("stores"),
indexer.keyspace(),
)?);
Ok(())
}
}
@@ -57,7 +69,7 @@ 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...");
@@ -72,17 +84,14 @@ impl Computer {
Ok(())
}
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()
-5
View File
@@ -1,5 +0,0 @@
mod stores;
mod vecs;
pub use stores::*;
pub use vecs::*;
-25
View File
@@ -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,364 +0,0 @@
use core::error;
use std::{
cmp::Ordering,
fmt::Debug,
ops::{Add, Sub},
path::{Path, PathBuf},
};
use brk_core::CheckedSub;
use brk_exit::Exit;
use brk_vec::{
Compressed, DynamicVec, Error, GenericVec, Result, StoredIndex, StoredType, StoredVec, Value,
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 cached_get(&mut self, index: I) -> Result<Option<Value<T>>> {
self.inner.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.cached_get(i).unwrap().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.cached_get(value)?.unwrap()).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, |(i, v, ..)| {
if let Some(prev_index) = prev_index.take() {
self.forced_push_at(prev_index, v.checked_sub(one).unwrap(), exit)?;
}
prev_index.replace(i);
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 + 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.cached_get(i)?.unwrap();
let count = (*last_index + 1_usize)
.checked_sub(first_index)
.unwrap_or_default();
self.forced_push_at(i, count.into(), 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.cached_get(other)?.unwrap().into_inner() == 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>,
exit: &Exit,
) -> Result<()>
where
T: From<T2>,
T2: StoredType + Copy + Add<usize, Output = T2> + Sub<T2, Output = T2> + TryInto<T>,
<T2 as TryInto<T>>::Error: error::Error + 'static,
{
self.validate_computed_version_or_reset_file(
Version::ZERO + self.version() + first_indexes.version() + last_indexes.version(),
)?;
let index = max_from.min(I::from(self.len()));
first_indexes.iter_from(index, |(index, first_index, ..)| {
let last_index = last_indexes.cached_get(index)?.unwrap();
let count = *last_index + 1_usize - first_index;
self.forced_push_at(index, count.into(), 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,169 +0,0 @@
use std::{fs, path::Path};
use brk_core::{CheckedSub, 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,
grouped::{ComputedVecsFromHeight, StorableVecGeneatorOptions},
indexes,
};
#[derive(Clone)]
pub struct Vecs {
pub indexes_to_block_interval: ComputedVecsFromHeight<Timestamp>,
pub indexes_to_block_count: ComputedVecsFromHeight<StoredU32>,
pub indexes_to_block_weight: ComputedVecsFromHeight<Weight>,
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 {
indexes_to_block_interval: ComputedVecsFromHeight::forced_import(
path,
"block_interval",
true,
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(),
)?,
indexes_to_block_vbytes: ComputedVecsFromHeight::forced_import(
path,
"block_vbytes",
true,
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.indexes_to_block_interval.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|v, indexer, _, starting_indexes, exit| {
let indexer_vecs = indexer.mut_vecs();
v.compute_transform(
starting_indexes.height,
indexer_vecs.height_to_timestamp.mut_vec(),
|(height, timestamp, _, height_to_timestamp)| {
let interval = height.decremented().map_or(Timestamp::ZERO, |prev_h| {
let prev_timestamp = *height_to_timestamp.get(prev_h).unwrap().unwrap();
timestamp
.checked_sub(prev_timestamp)
.unwrap_or(Timestamp::ZERO)
});
(height, interval)
},
exit,
)
},
)?;
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_block_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_block_weight.mut_vec()),
)?;
self.indexes_to_block_size.compute_rest(
indexes,
starting_indexes,
exit,
Some(indexer.mut_vecs().height_to_block_size.mut_vec()),
)?;
self.indexes_to_block_vbytes.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|v, indexer, _, starting_indexes, exit| {
v.compute_transform(
starting_indexes.height,
indexer.mut_vecs().height_to_block_weight.mut_vec(),
|(h, w, ..)| {
(
h,
StoredU64::from(bitcoin::Weight::from(w).to_vbytes_floor()),
)
},
exit,
)
},
)?;
Ok(())
}
pub fn as_any_vecs(&self) -> Vec<&dyn brk_vec::AnyStoredVec> {
[
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,702 +0,0 @@
use std::path::Path;
use brk_exit::Exit;
use brk_vec::{
Compressed, DynamicVec, GenericVec, Result, StoredIndex, StoredType, StoredVec, Version,
};
use crate::storage::vecs::base::ComputedVec;
use super::ComputedType;
#[derive(Clone, Debug)]
pub struct ComputedVecBuilder<I, T>
where
I: StoredIndex,
T: ComputedType,
{
pub first: Option<ComputedVec<I, T>>,
pub average: Option<ComputedVec<I, T>>,
pub sum: Option<ComputedVec<I, T>>,
pub max: Option<ComputedVec<I, T>>,
pub _90p: Option<ComputedVec<I, T>>,
pub _75p: Option<ComputedVec<I, T>>,
pub median: Option<ComputedVec<I, T>>,
pub _25p: Option<ComputedVec<I, T>>,
pub _10p: Option<ComputedVec<I, T>>,
pub min: Option<ComputedVec<I, T>>,
pub last: Option<ComputedVec<I, T>>,
pub total: Option<ComputedVec<I, T>>,
}
impl<I, T> ComputedVecBuilder<I, T>
where
I: StoredIndex,
T: ComputedType,
{
pub fn forced_import(
path: &Path,
name: &str,
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 s = Self {
first: options.first.then(|| {
ComputedVec::forced_import(&maybe_prefix("first"), Version::ZERO, compressed)
.unwrap()
}),
last: options.last.then(|| {
ComputedVec::forced_import(
&path.join(format!("{key}_to_{name}")),
Version::ZERO,
compressed,
)
.unwrap()
}),
min: options.min.then(|| {
ComputedVec::forced_import(&maybe_suffix("min"), Version::ZERO, compressed).unwrap()
}),
max: options.max.then(|| {
ComputedVec::forced_import(&maybe_suffix("max"), Version::ZERO, compressed).unwrap()
}),
median: options.median.then(|| {
ComputedVec::forced_import(&maybe_suffix("median"), Version::ZERO, compressed)
.unwrap()
}),
average: options.average.then(|| {
ComputedVec::forced_import(&maybe_suffix("average"), Version::ZERO, compressed)
.unwrap()
}),
sum: options.sum.then(|| {
ComputedVec::forced_import(&maybe_suffix("sum"), Version::ZERO, compressed).unwrap()
}),
total: options.total.then(|| {
ComputedVec::forced_import(&prefix("total"), Version::ZERO, compressed).unwrap()
}),
_90p: options._90p.then(|| {
ComputedVec::forced_import(&maybe_suffix("90p"), Version::ZERO, compressed).unwrap()
}),
_75p: options._75p.then(|| {
ComputedVec::forced_import(&maybe_suffix("75p"), Version::ZERO, compressed).unwrap()
}),
_25p: options._25p.then(|| {
ComputedVec::forced_import(&maybe_suffix("25p"), Version::ZERO, compressed).unwrap()
}),
_10p: options._10p.then(|| {
ComputedVec::forced_import(&maybe_suffix("10p"), 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
.to_usize()
.unwrap()
.checked_sub(1)
.map_or(T::from(0_usize), |prev_i| {
total_vec
.cached_get(I::from(prev_i))
.unwrap()
.map_or(T::from(0_usize), |v| v.into_inner())
});
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, ..)| {
let last_index = *last_indexes.cached_get(i)?.unwrap();
if let Some(first) = self.first.as_mut() {
let v = source.cached_get(first_index)?.unwrap().into_inner();
first.forced_push_at(index, v, exit)?;
}
if let Some(last) = self.last.as_mut() {
let v = source
.cached_get(last_index)
.inspect_err(|_| {
dbg!(last.path(), last_index);
})?
.unwrap()
.into_inner();
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().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.to_usize().unwrap().checked_sub(1).map_or(
T::from(0_usize),
|prev_i| {
total_vec
.cached_get(I::from(prev_i))
.unwrap()
.unwrap()
.to_owned()
.into_inner()
},
);
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.cached_get(i).unwrap().unwrap();
if let Some(first) = self.first.as_mut() {
let v = source
.first
.as_mut()
.unwrap()
.cached_get(first_index)
.unwrap()
.unwrap()
.into_inner();
first.forced_push_at(index, v, exit)?;
}
if let Some(last) = self.last.as_mut() {
let v = source
.last
.as_mut()
.unwrap()
.cached_get(last_index)
.unwrap()
.unwrap()
.into_inner();
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.to_usize().unwrap().checked_sub(1).map_or(
T::from(0_usize),
|prev_i| {
total_vec
.cached_get(I::from(prev_i))
.unwrap()
.unwrap()
.into_inner()
},
);
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 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,141 +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>,
}
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 dateindex_extra =
ComputedVecBuilder::forced_import(path, name, 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, compressed, options)?,
monthindex: ComputedVecBuilder::forced_import(path, name, compressed, options)?,
quarterindex: ComputedVecBuilder::forced_import(path, name, compressed, options)?,
yearindex: ComputedVecBuilder::forced_import(path, name, compressed, options)?,
decadeindex: ComputedVecBuilder::forced_import(path, name, 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,186 +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>,
}
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 height = compute_source.then(|| {
ComputedVec::forced_import(&path.join(format!("height_to_{name}")), version, compressed)
.unwrap()
});
let height_extra =
ComputedVecBuilder::forced_import(path, name, compressed, options.copy_self_extra())?;
let dateindex = ComputedVecBuilder::forced_import(path, name, compressed, options)?;
let options = options.remove_percentiles();
Ok(Self {
height,
height_extra,
dateindex,
weekindex: ComputedVecBuilder::forced_import(path, name, compressed, options)?,
difficultyepoch: ComputedVecBuilder::forced_import(path, name, compressed, options)?,
monthindex: ComputedVecBuilder::forced_import(path, name, compressed, options)?,
quarterindex: ComputedVecBuilder::forced_import(path, name, compressed, options)?,
yearindex: ComputedVecBuilder::forced_import(path, name, compressed, options)?,
// halvingepoch: StorableVecGeneator::forced_import(path, name, compressed, options)?,
decadeindex: ComputedVecBuilder::forced_import(path, name, 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,208 +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 txindex_extra: ComputedVecBuilder<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>,
}
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 txindex = compute_source.then(|| {
ComputedVec::forced_import(
&path.join(format!("txindex_to_{name}")),
version,
compressed,
)
.unwrap()
});
let txindex_extra = ComputedVecBuilder::forced_import(
path,
name,
compressed,
StorableVecGeneatorOptions::default(),
)?;
let height = ComputedVecBuilder::forced_import(path, name, compressed, options)?;
let dateindex = ComputedVecBuilder::forced_import(path, name, compressed, options)?;
let options = options.remove_percentiles();
Ok(Self {
txindex,
txindex_extra,
height,
dateindex,
weekindex: ComputedVecBuilder::forced_import(path, name, compressed, options)?,
difficultyepoch: ComputedVecBuilder::forced_import(path, name, compressed, options)?,
monthindex: ComputedVecBuilder::forced_import(path, name, compressed, options)?,
quarterindex: ComputedVecBuilder::forced_import(path, name, compressed, options)?,
yearindex: ComputedVecBuilder::forced_import(path, name, compressed, options)?,
// halvingepoch: StorableVecGeneator::forced_import(path, name, compressed, options)?,
decadeindex: ComputedVecBuilder::forced_import(path, name, 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.txindex_extra
.extend(starting_indexes.txindex, txindex, exit)?;
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.txindex_extra.any_vecs(),
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,879 +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 height_to_last_addressindex: StorableVec<Height, Addressindex>,
// pub height_to_last_txoutindex: StorableVec<Height, Txoutindex>,
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_block_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.cached_get(h).ok())
.flatten()
.map_or(d, |prev_d| {
let prev_d = *prev_d;
if prev_d > d { prev_d } else { 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 starting_dateindex = self
.height_to_dateindex
.cached_get(starting_indexes.height.decremented().unwrap_or_default())?
.map_or_else(Default::default, |v| v.into_inner());
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
.cached_get(starting_indexes.height.decremented().unwrap_or_default())?
.map(|v| v.into_inner())
{
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
.cached_get(starting_dateindex)?
.map_or_else(Default::default, |v| v.into_inner());
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.cached_get(d).unwrap().unwrap(),
)
},
exit,
)?;
// ---
let starting_monthindex = self
.dateindex_to_monthindex
.cached_get(starting_dateindex)?
.map_or_else(Default::default, |v| v.into_inner());
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.cached_get(d).unwrap().unwrap(),
)
},
exit,
)?;
// ---
let starting_quarterindex = self
.monthindex_to_quarterindex
.cached_get(starting_monthindex)?
.map_or_else(Default::default, |v| v.into_inner());
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.cached_get(m).unwrap().unwrap(),
)
},
exit,
)?;
// ---
let starting_yearindex = self
.monthindex_to_yearindex
.cached_get(starting_monthindex)?
.map_or_else(Default::default, |v| v.into_inner());
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.cached_get(m).unwrap().unwrap(),
)
},
exit,
)?;
// ---
let starting_decadeindex = self
.yearindex_to_decadeindex
.cached_get(starting_yearindex)?
.map_or_else(Default::default, |v| v.into_inner());
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.cached_get(y).unwrap().unwrap(),
)
},
exit,
)?;
// ---
let starting_difficultyepoch = self
.height_to_difficultyepoch
.cached_get(starting_indexes.height)?
.map_or_else(Default::default, |v| v.into_inner());
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
.cached_get(h)
.unwrap()
.unwrap(),
)
},
exit,
)?;
// ---
let starting_halvingepoch = self
.height_to_halvingepoch
.cached_get(starting_indexes.height)?
.map_or_else(Default::default, |v| v.into_inner());
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.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
}
}
@@ -1,805 +0,0 @@
use std::{fs, path::Path};
use brk_core::{
Cents, Close, Dateindex, Decadeindex, Difficultyepoch, Dollars, Height, High, Low, Monthindex,
OHLCCents, OHLCDollars, Open, Quarterindex, Sats, Weekindex, Yearindex,
};
use brk_exit::Exit;
use brk_fetcher::Fetcher;
use brk_indexer::Indexer;
use brk_vec::{Compressed, Version};
use super::{
ComputedVec, Indexes,
grouped::{
ComputedVecsFromDateindex, ComputedVecsFromHeightStrict, StorableVecGeneatorOptions,
},
indexes,
};
#[derive(Clone)]
pub struct Vecs {
// pub dateindex_to_close: ComputedVec<Dateindex, Close<Dollars>>,
pub dateindex_to_close_in_cents: ComputedVec<Dateindex, Close<Cents>>,
pub dateindex_to_high_in_cents: ComputedVec<Dateindex, High<Cents>>,
pub dateindex_to_low_in_cents: ComputedVec<Dateindex, Low<Cents>>,
pub dateindex_to_ohlc: ComputedVec<Dateindex, OHLCDollars>,
pub dateindex_to_ohlc_in_cents: ComputedVec<Dateindex, OHLCCents>,
pub dateindex_to_open_in_cents: ComputedVec<Dateindex, Open<Cents>>,
pub height_to_close_in_cents: ComputedVec<Height, Close<Cents>>,
pub height_to_high_in_cents: ComputedVec<Height, High<Cents>>,
pub height_to_low_in_cents: ComputedVec<Height, Low<Cents>>,
pub height_to_ohlc: ComputedVec<Height, OHLCDollars>,
pub height_to_ohlc_in_cents: ComputedVec<Height, OHLCCents>,
pub height_to_open_in_cents: ComputedVec<Height, Open<Cents>>,
pub timeindexes_to_close: ComputedVecsFromDateindex<Close<Dollars>>,
pub timeindexes_to_high: ComputedVecsFromDateindex<High<Dollars>>,
pub timeindexes_to_low: ComputedVecsFromDateindex<Low<Dollars>>,
pub timeindexes_to_open: ComputedVecsFromDateindex<Open<Dollars>>,
pub timeindexes_to_sats_per_dollar: ComputedVecsFromDateindex<Close<Sats>>,
pub chainindexes_to_close: ComputedVecsFromHeightStrict<Close<Dollars>>,
pub chainindexes_to_high: ComputedVecsFromHeightStrict<High<Dollars>>,
pub chainindexes_to_low: ComputedVecsFromHeightStrict<Low<Dollars>>,
pub chainindexes_to_open: ComputedVecsFromHeightStrict<Open<Dollars>>,
pub chainindexes_to_sats_per_dollar: ComputedVecsFromHeightStrict<Close<Sats>>,
pub weekindex_to_ohlc: ComputedVec<Weekindex, OHLCDollars>,
pub difficultyepoch_to_ohlc: ComputedVec<Difficultyepoch, OHLCDollars>,
pub monthindex_to_ohlc: ComputedVec<Monthindex, OHLCDollars>,
pub quarterindex_to_ohlc: ComputedVec<Quarterindex, OHLCDollars>,
pub yearindex_to_ohlc: ComputedVec<Yearindex, OHLCDollars>,
// pub halvingepoch_to_ohlc: StorableVec<Halvingepoch, OHLCDollars>,
pub decadeindex_to_ohlc: ComputedVec<Decadeindex, OHLCDollars>,
}
impl Vecs {
pub fn forced_import(path: &Path, compressed: Compressed) -> color_eyre::Result<Self> {
fs::create_dir_all(path)?;
let mut fetched_path = path.to_owned();
fetched_path.pop();
fetched_path.pop();
fetched_path = fetched_path.join("fetched/vecs");
Ok(Self {
dateindex_to_ohlc_in_cents: ComputedVec::forced_import(
&fetched_path.join("dateindex_to_ohlc_in_cents"),
Version::ZERO,
compressed,
)?,
dateindex_to_ohlc: ComputedVec::forced_import(
&path.join("dateindex_to_ohlc"),
Version::ZERO,
compressed,
)?,
dateindex_to_close_in_cents: ComputedVec::forced_import(
&path.join("dateindex_to_close_in_cents"),
Version::ZERO,
compressed,
)?,
dateindex_to_high_in_cents: ComputedVec::forced_import(
&path.join("dateindex_to_high_in_cents"),
Version::ZERO,
compressed,
)?,
dateindex_to_low_in_cents: ComputedVec::forced_import(
&path.join("dateindex_to_low_in_cents"),
Version::ZERO,
compressed,
)?,
dateindex_to_open_in_cents: ComputedVec::forced_import(
&path.join("dateindex_to_open_in_cents"),
Version::ZERO,
compressed,
)?,
height_to_ohlc_in_cents: ComputedVec::forced_import(
&fetched_path.join("height_to_ohlc_in_cents"),
Version::ZERO,
compressed,
)?,
height_to_ohlc: ComputedVec::forced_import(
&path.join("height_to_ohlc"),
Version::ZERO,
compressed,
)?,
height_to_close_in_cents: ComputedVec::forced_import(
&path.join("height_to_close_in_cents"),
Version::ZERO,
compressed,
)?,
height_to_high_in_cents: ComputedVec::forced_import(
&path.join("height_to_high_in_cents"),
Version::ZERO,
compressed,
)?,
height_to_low_in_cents: ComputedVec::forced_import(
&path.join("height_to_low_in_cents"),
Version::ZERO,
compressed,
)?,
height_to_open_in_cents: ComputedVec::forced_import(
&path.join("height_to_open_in_cents"),
Version::ZERO,
compressed,
)?,
timeindexes_to_open: ComputedVecsFromDateindex::forced_import(
path,
"open",
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_first(),
)?,
timeindexes_to_high: ComputedVecsFromDateindex::forced_import(
path,
"high",
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_max(),
)?,
timeindexes_to_low: ComputedVecsFromDateindex::forced_import(
path,
"low",
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_min(),
)?,
timeindexes_to_close: ComputedVecsFromDateindex::forced_import(
path,
"close",
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_last(),
)?,
timeindexes_to_sats_per_dollar: ComputedVecsFromDateindex::forced_import(
path,
"sats_per_dollar",
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_last(),
)?,
chainindexes_to_open: ComputedVecsFromHeightStrict::forced_import(
path,
"open",
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_first(),
)?,
chainindexes_to_high: ComputedVecsFromHeightStrict::forced_import(
path,
"high",
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_max(),
)?,
chainindexes_to_low: ComputedVecsFromHeightStrict::forced_import(
path,
"low",
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_min(),
)?,
chainindexes_to_close: ComputedVecsFromHeightStrict::forced_import(
path,
"close",
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_last(),
)?,
chainindexes_to_sats_per_dollar: ComputedVecsFromHeightStrict::forced_import(
path,
"sats_per_dollar",
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_last(),
)?,
weekindex_to_ohlc: ComputedVec::forced_import(
&path.join("weekindex_to_ohlc"),
Version::ZERO,
compressed,
)?,
difficultyepoch_to_ohlc: ComputedVec::forced_import(
&path.join("difficultyepoch_to_ohlc"),
Version::ZERO,
compressed,
)?,
monthindex_to_ohlc: ComputedVec::forced_import(
&path.join("monthindex_to_ohlc"),
Version::ZERO,
compressed,
)?,
quarterindex_to_ohlc: ComputedVec::forced_import(
&path.join("quarterindex_to_ohlc"),
Version::ZERO,
compressed,
)?,
yearindex_to_ohlc: ComputedVec::forced_import(
&path.join("yearindex_to_ohlc"),
Version::ZERO,
compressed,
)?,
// halvingepoch_to_ohlc: StorableVec::forced_import(&path.join("halvingepoch_to_ohlc"), Version::ZERO, compressed)?,
decadeindex_to_ohlc: ComputedVec::forced_import(
&path.join("decadeindex_to_ohlc"),
Version::ZERO,
compressed,
)?,
})
}
pub fn compute(
&mut self,
indexer: &mut Indexer,
indexes: &mut indexes::Vecs,
starting_indexes: &Indexes,
fetcher: &mut Fetcher,
exit: &Exit,
) -> color_eyre::Result<()> {
let indexer_vecs = indexer.mut_vecs();
self.height_to_ohlc_in_cents.compute_transform(
starting_indexes.height,
indexer_vecs.height_to_timestamp.mut_vec(),
|(h, t, _, height_to_timestamp)| {
let ohlc = fetcher
.get_height(
h,
t,
h.decremented().map(|prev_h| {
*height_to_timestamp.cached_get(prev_h).unwrap().unwrap()
}),
)
.unwrap();
(h, ohlc)
},
exit,
)?;
self.height_to_open_in_cents.compute_transform(
starting_indexes.height,
self.height_to_ohlc_in_cents.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.open),
exit,
)?;
self.height_to_high_in_cents.compute_transform(
starting_indexes.height,
self.height_to_ohlc_in_cents.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.high),
exit,
)?;
self.height_to_low_in_cents.compute_transform(
starting_indexes.height,
self.height_to_ohlc_in_cents.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.low),
exit,
)?;
self.height_to_close_in_cents.compute_transform(
starting_indexes.height,
self.height_to_ohlc_in_cents.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.close),
exit,
)?;
self.height_to_ohlc.compute_transform(
starting_indexes.height,
self.height_to_ohlc_in_cents.mut_vec(),
|(di, ohlc, ..)| (di, OHLCDollars::from(ohlc)),
exit,
)?;
self.dateindex_to_ohlc_in_cents.compute_transform(
starting_indexes.dateindex,
indexes.dateindex_to_date.mut_vec(),
|(di, d, ..)| {
let ohlc = fetcher.get_date(d).unwrap();
(di, ohlc)
},
exit,
)?;
self.dateindex_to_open_in_cents.compute_transform(
starting_indexes.dateindex,
self.dateindex_to_ohlc_in_cents.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.open),
exit,
)?;
self.dateindex_to_high_in_cents.compute_transform(
starting_indexes.dateindex,
self.dateindex_to_ohlc_in_cents.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.high),
exit,
)?;
self.dateindex_to_low_in_cents.compute_transform(
starting_indexes.dateindex,
self.dateindex_to_ohlc_in_cents.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.low),
exit,
)?;
self.dateindex_to_close_in_cents.compute_transform(
starting_indexes.dateindex,
self.dateindex_to_ohlc_in_cents.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.close),
exit,
)?;
self.dateindex_to_ohlc.compute_transform(
starting_indexes.dateindex,
self.dateindex_to_ohlc_in_cents.mut_vec(),
|(di, ohlc, ..)| (di, OHLCDollars::from(ohlc)),
exit,
)?;
self.timeindexes_to_close.compute(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_transform(
starting_indexes.dateindex,
self.dateindex_to_ohlc.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.close),
exit,
)
},
)?;
self.timeindexes_to_high.compute(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_transform(
starting_indexes.dateindex,
self.dateindex_to_ohlc.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.high),
exit,
)
},
)?;
self.timeindexes_to_low.compute(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_transform(
starting_indexes.dateindex,
self.dateindex_to_ohlc.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.low),
exit,
)
},
)?;
self.timeindexes_to_open.compute(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_transform(
starting_indexes.dateindex,
self.dateindex_to_ohlc.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.open),
exit,
)
},
)?;
self.chainindexes_to_close.compute(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_transform(
starting_indexes.height,
self.height_to_ohlc.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.close),
exit,
)
},
)?;
self.chainindexes_to_high.compute(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_transform(
starting_indexes.height,
self.height_to_ohlc.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.high),
exit,
)
},
)?;
self.chainindexes_to_low.compute(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_transform(
starting_indexes.height,
self.height_to_ohlc.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.low),
exit,
)
},
)?;
self.chainindexes_to_open.compute(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_transform(
starting_indexes.height,
self.height_to_ohlc.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.open),
exit,
)
},
)?;
self.weekindex_to_ohlc.compute_transform(
starting_indexes.weekindex,
self.timeindexes_to_close
.weekindex
.last
.as_mut()
.unwrap()
.mut_vec(),
|(i, close, ..)| {
(
i,
OHLCDollars {
open: *self
.timeindexes_to_open
.weekindex
.first
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
high: *self
.timeindexes_to_high
.weekindex
.max
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
low: *self
.timeindexes_to_low
.weekindex
.min
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
close,
},
)
},
exit,
)?;
self.difficultyepoch_to_ohlc.compute_transform(
starting_indexes.difficultyepoch,
self.chainindexes_to_close
.difficultyepoch
.last
.as_mut()
.unwrap()
.mut_vec(),
|(i, close, ..)| {
(
i,
OHLCDollars {
open: *self
.chainindexes_to_open
.difficultyepoch
.first
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
high: *self
.chainindexes_to_high
.difficultyepoch
.max
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
low: *self
.chainindexes_to_low
.difficultyepoch
.min
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
close,
},
)
},
exit,
)?;
self.monthindex_to_ohlc.compute_transform(
starting_indexes.monthindex,
self.timeindexes_to_close
.monthindex
.last
.as_mut()
.unwrap()
.mut_vec(),
|(i, close, ..)| {
(
i,
OHLCDollars {
open: *self
.timeindexes_to_open
.monthindex
.first
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
high: *self
.timeindexes_to_high
.monthindex
.max
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
low: *self
.timeindexes_to_low
.monthindex
.min
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
close,
},
)
},
exit,
)?;
self.quarterindex_to_ohlc.compute_transform(
starting_indexes.quarterindex,
self.timeindexes_to_close
.quarterindex
.last
.as_mut()
.unwrap()
.mut_vec(),
|(i, close, ..)| {
(
i,
OHLCDollars {
open: *self
.timeindexes_to_open
.quarterindex
.first
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
high: *self
.timeindexes_to_high
.quarterindex
.max
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
low: *self
.timeindexes_to_low
.quarterindex
.min
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
close,
},
)
},
exit,
)?;
self.yearindex_to_ohlc.compute_transform(
starting_indexes.yearindex,
self.timeindexes_to_close
.yearindex
.last
.as_mut()
.unwrap()
.mut_vec(),
|(i, close, ..)| {
(
i,
OHLCDollars {
open: *self
.timeindexes_to_open
.yearindex
.first
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
high: *self
.timeindexes_to_high
.yearindex
.max
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
low: *self
.timeindexes_to_low
.yearindex
.min
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
close,
},
)
},
exit,
)?;
// self.halvingepoch_to_ohlc
// .compute_transform(starting_indexes.halvingepoch, other, t, exit)?;
self.decadeindex_to_ohlc.compute_transform(
starting_indexes.decadeindex,
self.timeindexes_to_close
.decadeindex
.last
.as_mut()
.as_mut()
.unwrap()
.mut_vec(),
|(i, close, ..)| {
(
i,
OHLCDollars {
open: *self
.timeindexes_to_open
.decadeindex
.first
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
high: *self
.timeindexes_to_high
.decadeindex
.max
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
low: *self
.timeindexes_to_low
.decadeindex
.min
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
close,
},
)
},
exit,
)?;
self.chainindexes_to_sats_per_dollar.compute(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_transform(
starting_indexes.height,
self.chainindexes_to_close.height.mut_vec(),
|(i, close, ..)| (i, Close::from(Sats::ONE_BTC / *close)),
exit,
)
},
)?;
self.timeindexes_to_sats_per_dollar.compute(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_transform(
starting_indexes.dateindex,
self.timeindexes_to_close.dateindex.mut_vec(),
|(i, close, ..)| (i, Close::from(Sats::ONE_BTC / *close)),
exit,
)
},
)?;
Ok(())
}
pub fn as_any_vecs(&self) -> Vec<&dyn brk_vec::AnyStoredVec> {
vec![
vec![
self.dateindex_to_close_in_cents.any_vec(),
self.dateindex_to_high_in_cents.any_vec(),
self.dateindex_to_low_in_cents.any_vec(),
self.dateindex_to_ohlc.any_vec(),
self.dateindex_to_ohlc_in_cents.any_vec(),
self.dateindex_to_open_in_cents.any_vec(),
self.height_to_close_in_cents.any_vec(),
self.height_to_high_in_cents.any_vec(),
self.height_to_low_in_cents.any_vec(),
self.height_to_ohlc.any_vec(),
self.height_to_ohlc_in_cents.any_vec(),
self.height_to_open_in_cents.any_vec(),
self.weekindex_to_ohlc.any_vec(),
self.difficultyepoch_to_ohlc.any_vec(),
self.monthindex_to_ohlc.any_vec(),
self.quarterindex_to_ohlc.any_vec(),
self.yearindex_to_ohlc.any_vec(),
// self.halvingepoch_to_ohlc.any_vec(),
self.decadeindex_to_ohlc.any_vec(),
],
self.chainindexes_to_sats_per_dollar.any_vecs(),
self.timeindexes_to_sats_per_dollar.any_vecs(),
self.timeindexes_to_close.any_vecs(),
self.timeindexes_to_high.any_vecs(),
self.timeindexes_to_low.any_vecs(),
self.timeindexes_to_open.any_vecs(),
self.chainindexes_to_close.any_vecs(),
self.chainindexes_to_high.any_vecs(),
self.chainindexes_to_low.any_vecs(),
self.chainindexes_to_open.any_vecs(),
]
.concat()
}
}
@@ -1,77 +0,0 @@
use std::{fs, path::Path};
use brk_exit::Exit;
use brk_fetcher::Fetcher;
use brk_indexer::Indexer;
use brk_vec::{AnyStoredVec, Compressed};
mod base;
mod blocks;
mod grouped;
mod indexes;
mod marketprice;
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)?,
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)?;
self.transactions
.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,
)?;
}
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,313 +0,0 @@
use std::{fs, path::Path};
use brk_core::{Sats, StoredU8, StoredU32, StoredU64, Txindex, Txinindex, Txoutindex};
use brk_exit::Exit;
use brk_indexer::Indexer;
use brk_vec::{Compressed, DynamicVec, Version};
use super::{
ComputedVec, Indexes,
grouped::{ComputedVecsFromHeight, ComputedVecsFromTxindex, StorableVecGeneatorOptions},
indexes,
};
#[derive(Clone)]
pub struct Vecs {
// pub height_to_fee: ComputedVec<Txindex, Sats>,
// pub height_to_inputcount: ComputedVec<Height, u32>,
// pub height_to_maxfeerate: ComputedVec<Height, Feerate>,
// pub height_to_medianfeerate: ComputedVec<Height, Feerate>,
// pub height_to_minfeerate: ComputedVec<Height, Feerate>,
// pub height_to_outputcount: ComputedVec<Height, u32>,
// pub height_to_subsidy: ComputedVec<Height, u32>,
// pub height_to_totalfees: ComputedVec<Height, Sats>,
// pub txindex_to_fee: ComputedVec<Txindex, Sats>,
// pub txindex_to_feerate: ComputedVec<Txindex, Feerate>,
// pub txindex_to_input_sum: ComputedVec<Txindex, Sats>,
// pub txindex_to_output_sum: ComputedVec<Txindex, Sats>,
// pub txindex_to_output_value: ComputedVecsFromTxindex<Sats>,
pub txindex_to_v1: ComputedVec<Txindex, StoredU8>,
pub txindex_to_v2: ComputedVec<Txindex, StoredU8>,
pub txindex_to_v3: ComputedVec<Txindex, StoredU8>,
pub indexes_to_tx_v1: ComputedVecsFromHeight<StoredU32>,
pub indexes_to_tx_v2: ComputedVecsFromHeight<StoredU32>,
pub indexes_to_tx_v3: ComputedVecsFromHeight<StoredU32>,
// pub txinindex_to_value: ComputedVec<Txinindex, Sats>,
pub height_to_tx_count: ComputedVecsFromHeight<StoredU64>,
pub txindex_to_input_count: ComputedVecsFromTxindex<StoredU64>,
pub txindex_to_is_coinbase: ComputedVec<Txindex, bool>,
pub txindex_to_output_count: ComputedVecsFromTxindex<StoredU64>,
/// Value == 0 when Coinbase
pub txinindex_to_value: ComputedVec<Txinindex, Sats>,
}
impl Vecs {
pub fn forced_import(path: &Path, compressed: Compressed) -> color_eyre::Result<Self> {
fs::create_dir_all(path)?;
Ok(Self {
height_to_tx_count: ComputedVecsFromHeight::forced_import(
path,
"tx_count",
true,
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_sum().add_total(),
)?,
// height_to_fee: StorableVec::forced_import(&path.join("height_to_fee"), Version::ZERO)?,
// height_to_input_count: StorableVec::forced_import(
// &path.join("height_to_input_count"),
// Version::ZERO,
// )?,
// height_to_maxfeerate: StorableVec::forced_import(&path.join("height_to_maxfeerate"), Version::ZERO)?,
// height_to_medianfeerate: StorableVec::forced_import(&path.join("height_to_medianfeerate"), Version::ZERO)?,
// height_to_minfeerate: StorableVec::forced_import(&path.join("height_to_minfeerate"), Version::ZERO)?,
// height_to_output_count: StorableVec::forced_import(
// &path.join("height_to_output_count"),
// Version::ZERO,
// )?,
// height_to_subsidy: StorableVec::forced_import(&path.join("height_to_subsidy"), Version::ZERO)?,
// height_to_totalfees: StorableVec::forced_import(&path.join("height_to_totalfees"), Version::ZERO)?,
// height_to_txcount: StorableVec::forced_import(&path.join("height_to_txcount"), Version::ZERO)?,
// txindex_to_fee: StorableVec::forced_import(
// &path.join("txindex_to_fee"),
// Version::ZERO,
// )?,
txindex_to_is_coinbase: ComputedVec::forced_import(
&path.join("txindex_to_is_coinbase"),
Version::ZERO,
compressed,
)?,
// txindex_to_feerate: StorableVec::forced_import(&path.join("txindex_to_feerate"), Version::ZERO)?,
txindex_to_input_count: ComputedVecsFromTxindex::forced_import(
path,
"input_count",
true,
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_sum().add_total(),
)?,
txindex_to_output_count: ComputedVecsFromTxindex::forced_import(
path,
"output_count",
true,
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_sum().add_total(),
)?,
// txindex_to_output_value: ComputedVecsFromTxindex::forced_import(
// path,
// "output_value",
// Version::ZERO,
// compressed,
// StorableVecGeneatorOptions::default().add_sum().add_total(),
// )?,
txinindex_to_value: ComputedVec::forced_import(
&path.join("txinindex_to_value"),
Version::ZERO,
compressed,
)?,
txindex_to_v1: ComputedVec::forced_import(
&path.join("txindex_to_v1"),
Version::ZERO,
compressed,
)?,
txindex_to_v2: ComputedVec::forced_import(
&path.join("txindex_to_v2"),
Version::ZERO,
compressed,
)?,
txindex_to_v3: ComputedVec::forced_import(
&path.join("txindex_to_v3"),
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(),
)?,
})
}
pub fn compute(
&mut self,
indexer: &mut Indexer,
indexes: &mut indexes::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> color_eyre::Result<()> {
self.height_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,
)
},
)?;
// self.txindex_to_output_value.compute_rest(
// indexer,
// indexes,
// starting_indexes,
// exit,
// Some(indexer.mut_vecs().txoutindex_to_value.mut_vec()),
// )?;
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_v1.compute_transform(
starting_indexes.txindex,
indexer_vecs.txindex_to_txversion.mut_vec(),
|(i, v, ..)| (i, StoredU8::from(v)),
exit,
)?;
// self.indexes_to_tx_v1.compute_all(
// indexer,
// indexes,
// starting_indexes,
// exit,
// |vec, indexer, indexes, indexes, exit| {
// vec.compute_transform(
// starting_indexes.height,
// indexer.mut_vecs().txindex_to_txversion.mut_vec(),
// || {},
// exit,
// )?;
// },
// )?;
self.txindex_to_v2.compute_transform(
starting_indexes.txindex,
indexer_vecs.txindex_to_txversion.mut_vec(),
|(i, v, ..)| (i, StoredU8::from(v)),
exit,
)?;
// self.indexes_to_tx_v1.compute_rest(
// starting_indexes.txindex,
// indexer_vecs.txindex_to_txversion.mut_vec(),
// |(i, v, ..)| (i, StoredU8::from(v)),
// exit,
// )?;
self.txindex_to_v3.compute_transform(
starting_indexes.txindex,
indexer_vecs.txindex_to_txversion.mut_vec(),
|(i, v, ..)| (i, StoredU8::from(v)),
exit,
)?;
// self.indexes_to_tx_v1.compute_rest(
// starting_indexes.txindex,
// indexer_vecs.txindex_to_txversion.mut_vec(),
// |(i, v, ..)| (i, StoredU8::from(v)),
// 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 Ok(Some(value)) = indexer_vecs
.txoutindex_to_value
.mut_vec()
.cached_get(txoutindex)
{
*value
} else {
dbg!(txinindex, txoutindex, slf.len(), other.len());
panic!()
};
(txinindex, value)
},
exit,
)?;
// self.txindex_to_fee.compute_transform(
// &mut self.vecs.txindex_to_height,
// &mut indexer.vecs().height_to_first_txindex,
// )?;
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_v1.any_vec(),
self.txindex_to_v2.any_vec(),
self.txindex_to_v3.any_vec(),
],
self.height_to_tx_count.any_vecs(),
self.txindex_to_output_count.any_vecs(),
self.txindex_to_input_count.any_vecs(),
self.indexes_to_tx_v1.any_vecs(),
self.indexes_to_tx_v2.any_vecs(),
self.indexes_to_tx_v3.any_vecs(),
]
.concat()
}
}
+31
View File
@@ -0,0 +1,31 @@
use std::path::Path;
use fjall::TransactionalKeyspace;
#[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, _: &TransactionalKeyspace) -> color_eyre::Result<Self> {
// let address_to_utxos_received = Store::import(
// keyspace.clone(),
// path,
// "address_to_utxos_received",
// Version::ZERO,
// )?;
// let address_to_utxos_spent = Store::import(
// keyspace.clone(),
// path,
// "address_to_utxos_spent",
// Version::ZERO,
// )?;
Ok(Self {
// address_to_utxos_received,
// address_to_utxos_spent,
})
}
}
+27
View File
@@ -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()
}
}
}
+247
View File
@@ -0,0 +1,247 @@
use std::{fs, path::Path};
use brk_core::{
CheckedSub, DifficultyEpoch, HalvingEpoch, Height, StoredU32, StoredU64, StoredUsize,
Timestamp, Weight,
};
use brk_exit::Exit;
use brk_indexer::Indexer;
use brk_parser::bitcoin;
use brk_vec::{AnyCollectableVec, AnyIterableVec, Compressed, Computation, EagerVec, Version};
use super::{
Indexes,
grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, StorableVecGeneatorOptions},
indexes,
};
#[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,
_computation: Computation,
compressed: Compressed,
) -> color_eyre::Result<Self> {
fs::create_dir_all(path)?;
Ok(Self {
height_to_interval: EagerVec::forced_import(
&path.join("height_to_interval"),
Version::ZERO,
compressed,
)?,
timeindexes_to_timestamp: ComputedVecsFromDateIndex::forced_import(
path,
"timestamp",
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_first(),
)?,
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: EagerVec::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(),
)?,
difficultyepoch_to_timestamp: EagerVec::forced_import(
&path.join("difficultyepoch_to_timestamp"),
Version::ZERO,
compressed,
)?,
halvingepoch_to_timestamp: EagerVec::forced_import(
&path.join("halvingepoch_to_timestamp"),
Version::ZERO,
compressed,
)?,
})
}
pub fn compute(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> color_eyre::Result<()> {
self.timeindexes_to_timestamp.compute(
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(),
]
.concat()
}
}
+149
View File
@@ -0,0 +1,149 @@
use std::{fs, path::Path};
use brk_core::StoredU8;
use brk_exit::Exit;
use brk_indexer::Indexer;
use brk_vec::{AnyCollectableVec, AnyVec, Compressed, Computation, Version};
use super::{
Indexes,
grouped::{ComputedVecsFromHeight, StorableVecGeneatorOptions},
indexes,
};
#[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,
_computation: Computation,
compressed: Compressed,
) -> color_eyre::Result<Self> {
fs::create_dir_all(path)?;
Ok(Self {
_0: ComputedVecsFromHeight::forced_import(
path,
"0",
true,
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_last(),
)?,
_1: ComputedVecsFromHeight::forced_import(
path,
"1",
true,
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_last(),
)?,
_50: ComputedVecsFromHeight::forced_import(
path,
"50",
true,
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_last(),
)?,
_100: ComputedVecsFromHeight::forced_import(
path,
"100",
true,
Version::ZERO,
compressed,
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(),
]
.concat()
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,846 @@
use std::path::Path;
use brk_core::{CheckedSub, StoredUsize};
use brk_exit::Exit;
use brk_vec::{
AnyCollectableVec, AnyIterableVec, Compressed, EagerVec, Result, StoredIndex, StoredType,
Version,
};
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,
{
first: Option<EagerVec<I, T>>,
average: Option<EagerVec<I, T>>,
sum: Option<EagerVec<I, T>>,
max: Option<EagerVec<I, T>>,
_90p: Option<EagerVec<I, T>>,
_75p: Option<EagerVec<I, T>>,
median: Option<EagerVec<I, T>>,
_25p: Option<EagerVec<I, T>>,
_10p: Option<EagerVec<I, T>>,
min: Option<EagerVec<I, T>>,
last: Option<EagerVec<I, T>>,
total: Option<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,
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(|| {
EagerVec::forced_import(&maybe_prefix("first"), version + Version::ZERO, compressed)
.unwrap()
}),
last: options.last.then(|| {
EagerVec::forced_import(
&path.join(format!("{key}_to_{name}")),
version + Version::ZERO,
compressed,
)
.unwrap()
}),
min: options.min.then(|| {
EagerVec::forced_import(&maybe_suffix("min"), version + Version::ZERO, compressed)
.unwrap()
}),
max: options.max.then(|| {
EagerVec::forced_import(&maybe_suffix("max"), version + Version::ZERO, compressed)
.unwrap()
}),
median: options.median.then(|| {
EagerVec::forced_import(
&maybe_suffix("median"),
version + Version::ZERO,
compressed,
)
.unwrap()
}),
average: options.average.then(|| {
EagerVec::forced_import(
&maybe_suffix("average"),
version + Version::ZERO,
compressed,
)
.unwrap()
}),
sum: options.sum.then(|| {
EagerVec::forced_import(&maybe_suffix("sum"), version + Version::ZERO, compressed)
.unwrap()
}),
total: options.total.then(|| {
EagerVec::forced_import(&prefix("total"), version + Version::ZERO, compressed)
.unwrap()
}),
_90p: options._90p.then(|| {
EagerVec::forced_import(&maybe_suffix("90p"), version + Version::ZERO, compressed)
.unwrap()
}),
_75p: options._75p.then(|| {
EagerVec::forced_import(&maybe_suffix("75p"), version + Version::ZERO, compressed)
.unwrap()
}),
_25p: options._25p.then(|| {
EagerVec::forced_import(&maybe_suffix("25p"), version + Version::ZERO, compressed)
.unwrap()
}),
_10p: options._10p.then(|| {
EagerVec::forced_import(&maybe_suffix("10p"), version + Version::ZERO, compressed)
.unwrap()
}),
};
Ok(s)
}
pub fn extend(
&mut self,
max_from: I,
source: &impl AnyIterableVec<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();
let mut total = index.decremented().map_or(T::from(0_usize), |index| {
total_vec.iter().unwrap_get_inner(index)
});
source.iter_at(index).try_for_each(|(i, v)| -> Result<()> {
total = total.clone() + v.into_inner();
total_vec.forced_push_at(i, total.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 total_vec = self.total.as_mut();
let mut total = total_vec.map(|total_vec| {
index.decremented().map_or(T::from(0_usize), |index| {
total_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_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 {
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_total {
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_total {
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 t = total.as_ref().unwrap().clone() + sum;
total.replace(t.clone());
total_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 total = self.total.as_mut().map(|total_vec| {
index.decremented().map_or(T::from(0_usize), |index| {
total_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_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 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_total {
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 total = values.into_iter().fold(T::from(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 = total / len;
average.forced_push_at(i, avg, exit)?;
}
if needs_sum_or_total {
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(total_vec) = self.total.as_mut() {
let t = total.as_ref().unwrap().clone() + sum;
total.replace(t.clone());
total_vec.forced_push_at(i, t, exit)?;
}
}
}
}
Ok(())
})?;
self.safe_flush(exit)?;
Ok(())
}
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(&mut self) -> &mut EagerVec<I, T> {
self.first.as_mut().unwrap()
}
#[allow(unused)]
pub fn unwrap_average(&mut self) -> &mut EagerVec<I, T> {
self.average.as_mut().unwrap()
}
pub fn unwrap_sum(&mut self) -> &mut EagerVec<I, T> {
self.sum.as_mut().unwrap()
}
pub fn unwrap_max(&mut self) -> &mut EagerVec<I, T> {
self.max.as_mut().unwrap()
}
#[allow(unused)]
pub fn unwrap_90p(&mut self) -> &mut EagerVec<I, T> {
self._90p.as_mut().unwrap()
}
#[allow(unused)]
pub fn unwrap_75p(&mut self) -> &mut EagerVec<I, T> {
self._75p.as_mut().unwrap()
}
#[allow(unused)]
pub fn unwrap_median(&mut self) -> &mut EagerVec<I, T> {
self.median.as_mut().unwrap()
}
#[allow(unused)]
pub fn unwrap_25p(&mut self) -> &mut EagerVec<I, T> {
self._25p.as_mut().unwrap()
}
#[allow(unused)]
pub fn unwrap_10p(&mut self) -> &mut EagerVec<I, T> {
self._10p.as_mut().unwrap()
}
pub fn unwrap_min(&mut self) -> &mut EagerVec<I, T> {
self.min.as_mut().unwrap()
}
pub fn unwrap_last(&mut self) -> &mut EagerVec<I, T> {
self.last.as_mut().unwrap()
}
#[allow(unused)]
pub fn unwrap_total(&mut self) -> &mut EagerVec<I, T> {
self.total.as_mut().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);
}
if let Some(last) = self.last.as_ref() {
v.push(last);
}
if let Some(min) = self.min.as_ref() {
v.push(min);
}
if let Some(max) = self.max.as_ref() {
v.push(max);
}
if let Some(median) = self.median.as_ref() {
v.push(median);
}
if let Some(average) = self.average.as_ref() {
v.push(average);
}
if let Some(sum) = self.sum.as_ref() {
v.push(sum);
}
if let Some(total) = self.total.as_ref() {
v.push(total);
}
if let Some(_90p) = self._90p.as_ref() {
v.push(_90p);
}
if let Some(_75p) = self._75p.as_ref() {
v.push(_75p);
}
if let Some(_25p) = self._25p.as_ref() {
v.push(_25p);
}
if let Some(_10p) = self._10p.as_ref() {
v.push(_10p);
}
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(())
}
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(total) = self.total.as_mut() {
total.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,
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
}
#[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_total(mut self) -> Self {
self.total = 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_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()
}
}
}
@@ -0,0 +1,164 @@
use std::path::Path;
use brk_core::{DateIndex, DecadeIndex, MonthIndex, QuarterIndex, WeekIndex, YearIndex};
use brk_exit::Exit;
use brk_indexer::Indexer;
use brk_vec::{AnyCollectableVec, Compressed, EagerVec, Result, Version};
use crate::vecs::{Indexes, indexes};
use super::{ComputedType, ComputedVecBuilder, StorableVecGeneatorOptions};
#[derive(Clone)]
pub struct ComputedVecsFromDateIndex<T>
where
T: ComputedType + PartialOrd,
{
pub dateindex: 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,
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: EagerVec::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: &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(
&mut self.dateindex,
indexer,
indexes,
starting_indexes,
exit,
)?;
self.compute_rest(indexes, starting_indexes, exit)
}
pub fn compute_rest(
&mut self,
indexes: &indexes::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> color_eyre::Result<()> {
self.dateindex_extra
.extend(starting_indexes.dateindex, &self.dateindex, exit)?;
self.weekindex.compute(
starting_indexes.weekindex,
&self.dateindex,
&indexes.weekindex_to_first_dateindex,
&indexes.weekindex_to_dateindex_count,
exit,
)?;
self.monthindex.compute(
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> {
[
vec![&self.dateindex as &dyn AnyCollectableVec],
self.dateindex_extra.vecs(),
self.weekindex.vecs(),
self.monthindex.vecs(),
self.quarterindex.vecs(),
self.yearindex.vecs(),
self.decadeindex.vecs(),
]
.concat()
}
}
@@ -0,0 +1,222 @@
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::{AnyCollectableVec, AnyIterableVec, Compressed, EagerVec, Result, Version};
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,
compressed: Compressed,
options: StorableVecGeneatorOptions,
) -> color_eyre::Result<Self> {
let version = VERSION + version;
let height = compute_source.then(|| {
EagerVec::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: &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)?;
Ok(())
}
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(),
]
.concat()
}
}
@@ -1,11 +1,11 @@
use std::path::Path;
use brk_core::{Difficultyepoch, Height};
use brk_core::{DifficultyEpoch, Height};
use brk_exit::Exit;
use brk_indexer::Indexer;
use brk_vec::{AnyStoredVec, Compressed, Result, Version};
use brk_vec::{AnyCollectableVec, Compressed, EagerVec, Result, Version};
use crate::storage::vecs::{Indexes, base::ComputedVec, indexes};
use crate::vecs::{Indexes, indexes};
use super::{ComputedType, ComputedVecBuilder, StorableVecGeneatorOptions};
@@ -14,12 +14,14 @@ 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>,
}
const VERSION: Version = Version::ZERO;
impl<T> ComputedVecsFromHeightStrict<T>
where
T: ComputedType + Ord + From<f64>,
@@ -32,64 +34,64 @@ where
compressed: Compressed,
options: StorableVecGeneatorOptions,
) -> color_eyre::Result<Self> {
let height = ComputedVec::forced_import(
&path.join(format!("height_to_{name}")),
let version = VERSION + version;
let height =
EagerVec::forced_import(&path.join(format!("height_to_{name}")), version, compressed)?;
let height_extra = ComputedVecBuilder::forced_import(
path,
name,
version,
compressed,
options.copy_self_extra(),
)?;
let height_extra =
ComputedVecBuilder::forced_import(path, name, compressed, options.copy_self_extra())?;
let options = options.remove_percentiles();
Ok(Self {
height,
height_extra,
difficultyepoch: ComputedVecBuilder::forced_import(path, name, compressed, options)?,
// halvingepoch: StorableVecGeneator::forced_import(path, name, compressed, options)?,
difficultyepoch: ComputedVecBuilder::forced_import(
path, name, version, compressed, options,
)?,
// halvingepoch: StorableVecGeneator::forced_import(path, name, version, compressed, options)?,
})
}
pub fn compute<F>(
&mut self,
indexer: &mut Indexer,
indexes: &mut indexes::Vecs,
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()
}
@@ -0,0 +1,222 @@
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::{
AnyCollectableVec, CollectableVec, Compressed, EagerVec, Result, StoredVec, Version,
};
use crate::vecs::{Indexes, indexes};
use super::{ComputedType, ComputedVecBuilder, StorableVecGeneatorOptions};
#[derive(Clone)]
pub struct ComputedVecsFromTxindex<T>
where
T: ComputedType + PartialOrd,
{
pub txindex: Option<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,
compressed: Compressed,
options: StorableVecGeneatorOptions,
) -> color_eyre::Result<Self> {
let version = VERSION + version;
let txindex = compute_source.then(|| {
EagerVec::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,
)?,
})
}
#[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>>,
) -> color_eyre::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();
self.height.compute(
starting_indexes.height,
txindex,
&indexer.vecs().height_to_first_txindex,
&indexes.height_to_txindex_count,
exit,
)?;
}
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 &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(),
]
.concat()
}
}
@@ -3,11 +3,17 @@ 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_height;
mod value_from_txindex;
pub use builder::*;
pub use from_dateindex::*;
pub use from_height::*;
pub use from_height_strict::*;
pub use from_txindex::*;
pub use stored_type::*;
pub use ratio_from_dateindex::*;
use r#type::*;
pub use value_from_height::*;
pub use value_from_txindex::*;
@@ -0,0 +1,872 @@
use std::{f32, path::Path};
use brk_core::{Date, DateIndex, Dollars, StoredF32};
use brk_exit::Exit;
use brk_indexer::Indexer;
use brk_vec::{
AnyCollectableVec, AnyIterableVec, AnyVec, CollectableVec, Compressed, EagerVec, Result,
StoredIndex, VecIterator, Version,
};
// use rayon::prelude::*;
use crate::{
utils::get_percentile,
vecs::{Indexes, fetched, indexes},
};
use super::{ComputedVecsFromDateIndex, StorableVecGeneatorOptions};
#[derive(Clone)]
pub struct ComputedRatioVecsFromDateIndex {
pub price: ComputedVecsFromDateIndex<Dollars>,
pub ratio: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_sma: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_1w_sma: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_1m_sma: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_1y_sma: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_1y_sma_momentum_oscillator: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_standard_deviation: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_p99_9: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_p99_5: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_p99: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_p1: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_p0_5: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_p0_1: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_p1sd: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_p2sd: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_p3sd: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_m1sd: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_m2sd: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_m3sd: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_p99_9_as_price: ComputedVecsFromDateIndex<Dollars>,
pub ratio_p99_5_as_price: ComputedVecsFromDateIndex<Dollars>,
pub ratio_p99_as_price: ComputedVecsFromDateIndex<Dollars>,
pub ratio_p1_as_price: ComputedVecsFromDateIndex<Dollars>,
pub ratio_p0_5_as_price: ComputedVecsFromDateIndex<Dollars>,
pub ratio_p0_1_as_price: ComputedVecsFromDateIndex<Dollars>,
pub ratio_p1sd_as_price: ComputedVecsFromDateIndex<Dollars>,
pub ratio_p2sd_as_price: ComputedVecsFromDateIndex<Dollars>,
pub ratio_p3sd_as_price: ComputedVecsFromDateIndex<Dollars>,
pub ratio_m1sd_as_price: ComputedVecsFromDateIndex<Dollars>,
pub ratio_m2sd_as_price: ComputedVecsFromDateIndex<Dollars>,
pub ratio_m3sd_as_price: ComputedVecsFromDateIndex<Dollars>,
}
const VERSION: Version = Version::ZERO;
impl ComputedRatioVecsFromDateIndex {
pub fn forced_import(
path: &Path,
name: &str,
// _compute_source: bool,
version: Version,
compressed: Compressed,
options: StorableVecGeneatorOptions,
) -> color_eyre::Result<Self> {
Ok(Self {
price: ComputedVecsFromDateIndex::forced_import(
path,
name,
VERSION + version,
compressed,
options,
)?,
ratio: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_sma: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_sma"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_1w_sma: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_1w_sma"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_1m_sma: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_1m_sma"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_1y_sma: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_1y_sma"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_1y_sma_momentum_oscillator: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_1y_sma_momentum_oscillator"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_standard_deviation: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_standard_deviation"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_p99_9: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_p99_9"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_p99_5: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_p99_5"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_p99: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_p99"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_p1: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_p1"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_p0_5: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_p0_5"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_p0_1: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_p0_1"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_p1sd: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_p1sd"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_p2sd: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_p2sd"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_p3sd: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_p3sd"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_m1sd: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_m1sd"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_m2sd: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_m2sd"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_m3sd: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_m3sd"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_p99_9_as_price: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_p99_9_as_price"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_p99_5_as_price: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_p99_5_as_price"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_p99_as_price: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_p99_as_price"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_p1_as_price: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_p1_as_price"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_p0_5_as_price: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_p0_5_as_price"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_p0_1_as_price: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_p0_1_as_price"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_p1sd_as_price: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_p1sd_as_price"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_p2sd_as_price: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_p2sd_as_price"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_p3sd_as_price: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_p3sd_as_price"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_m1sd_as_price: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_m1sd_as_price"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_m2sd_as_price: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_m2sd_as_price"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
ratio_m3sd_as_price: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_m3sd_as_price"),
VERSION + version + Version::TWO,
compressed,
options,
)?,
})
}
pub fn compute<F>(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
fetched: &fetched::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
compute: F,
) -> color_eyre::Result<()>
where
F: FnMut(
&mut EagerVec<DateIndex, Dollars>,
&Indexer,
&indexes::Vecs,
&Indexes,
&Exit,
) -> Result<()>,
{
self.price
.compute(indexer, indexes, starting_indexes, exit, compute)?;
let closes = &fetched.timeindexes_to_close.dateindex;
self.ratio.compute(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
let mut price = self.price.dateindex.into_iter();
v.compute_transform(
starting_indexes.dateindex,
closes,
|(i, close, ..)| {
let price = price.unwrap_get_inner(i);
if price == Dollars::ZERO {
(i, StoredF32::from(1.0))
} else {
(i, StoredF32::from(*close / price))
}
},
exit,
)
},
)?;
let min_ratio_date = DateIndex::try_from(Date::MIN_RATIO).unwrap();
self.ratio_sma.compute(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_sma_(
starting_indexes.dateindex,
&self.ratio.dateindex,
usize::MAX,
exit,
Some(min_ratio_date),
)
},
)?;
self.ratio_1w_sma.compute(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_sma_(
starting_indexes.dateindex,
&self.ratio.dateindex,
7,
exit,
Some(min_ratio_date),
)
},
)?;
self.ratio_1m_sma.compute(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_sma_(
starting_indexes.dateindex,
&self.ratio.dateindex,
30,
exit,
Some(min_ratio_date),
)
},
)?;
self.ratio_1y_sma.compute(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_sma_(
starting_indexes.dateindex,
&self.ratio.dateindex,
365,
exit,
Some(min_ratio_date),
)
},
)?;
self.ratio_1y_sma_momentum_oscillator.compute(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
let mut ratio_1y_sma_iter = self.ratio_1y_sma.dateindex.into_iter();
v.compute_transform(
starting_indexes.dateindex,
&self.ratio.dateindex,
|(i, ratio, ..)| {
(
i,
StoredF32::from(*ratio / *ratio_1y_sma_iter.unwrap_get_inner(i) - 1.0),
)
},
exit,
)
},
)?;
let ratio_version = self.ratio.dateindex.version();
self.mut_ratio_vecs()
.iter_mut()
.try_for_each(|v| -> Result<()> {
v.validate_computed_version_or_reset_file(
Version::ZERO + v.inner_version() + ratio_version,
)
})?;
let starting_dateindex = self
.mut_ratio_vecs()
.iter()
.map(|v| DateIndex::from(v.len()))
.min()
.unwrap()
.min(starting_indexes.dateindex);
let mut sorted = self.ratio.dateindex.collect_range(
Some(min_ratio_date.unwrap_to_usize()),
Some(starting_dateindex.unwrap_to_usize()),
)?;
sorted.sort_unstable();
// if sorted.len() != starting_dateindex.unwrap_to_usize() - min_ratio_date.unwrap_to_usize() {
// unreachable!();
// }
let mut sma_iter = self.ratio_sma.dateindex.into_iter();
let nan = StoredF32::from(f32::NAN);
self.ratio
.dateindex
.iter_at(starting_dateindex)
.try_for_each(|(index, ratio)| -> Result<()> {
if index < min_ratio_date {
self.ratio_p0_1.dateindex.forced_push_at(index, nan, exit)?;
self.ratio_p0_5.dateindex.forced_push_at(index, nan, exit)?;
self.ratio_p1.dateindex.forced_push_at(index, nan, exit)?;
self.ratio_p99.dateindex.forced_push_at(index, nan, exit)?;
self.ratio_p99_5
.dateindex
.forced_push_at(index, nan, exit)?;
self.ratio_p99_9
.dateindex
.forced_push_at(index, nan, exit)?;
self.ratio_standard_deviation
.dateindex
.forced_push_at(index, nan, exit)?;
self.ratio_p1sd.dateindex.forced_push_at(index, nan, exit)?;
self.ratio_p2sd.dateindex.forced_push_at(index, nan, exit)?;
self.ratio_p3sd.dateindex.forced_push_at(index, nan, exit)?;
self.ratio_m1sd.dateindex.forced_push_at(index, nan, exit)?;
self.ratio_m2sd.dateindex.forced_push_at(index, nan, exit)?;
self.ratio_m3sd.dateindex.forced_push_at(index, nan, exit)?;
} else {
let ratio = ratio.into_inner();
let pos = sorted.binary_search(&ratio).unwrap_or_else(|pos| pos);
sorted.insert(pos, ratio);
self.ratio_p0_1.dateindex.forced_push_at(
index,
get_percentile(&sorted, 0.001),
exit,
)?;
self.ratio_p0_5.dateindex.forced_push_at(
index,
get_percentile(&sorted, 0.005),
exit,
)?;
self.ratio_p1.dateindex.forced_push_at(
index,
get_percentile(&sorted, 0.01),
exit,
)?;
self.ratio_p99.dateindex.forced_push_at(
index,
get_percentile(&sorted, 0.99),
exit,
)?;
self.ratio_p99_5.dateindex.forced_push_at(
index,
get_percentile(&sorted, 0.995),
exit,
)?;
self.ratio_p99_9.dateindex.forced_push_at(
index,
get_percentile(&sorted, 0.999),
exit,
)?;
let avg = sma_iter.unwrap_get_inner(index);
let sd = StoredF32::from(
(sorted.iter().map(|v| (**v - *avg).powi(2)).sum::<f32>()
/ (index.unwrap_to_usize() + 1) as f32)
.sqrt(),
);
self.ratio_standard_deviation
.dateindex
.forced_push_at(index, sd, exit)?;
self.ratio_p1sd
.dateindex
.forced_push_at(index, avg + sd, exit)?;
self.ratio_p2sd
.dateindex
.forced_push_at(index, avg + 2 * sd, exit)?;
self.ratio_p3sd
.dateindex
.forced_push_at(index, avg + 3 * sd, exit)?;
self.ratio_m1sd
.dateindex
.forced_push_at(index, avg - sd, exit)?;
self.ratio_m2sd
.dateindex
.forced_push_at(index, avg - 2 * sd, exit)?;
self.ratio_m3sd
.dateindex
.forced_push_at(index, avg - 3 * sd, exit)?;
}
Ok(())
})?;
self.mut_ratio_vecs()
.into_iter()
.try_for_each(|v| v.safe_flush(exit))?;
self.ratio_p99_9
.compute_rest(indexes, starting_indexes, exit)?;
self.ratio_p99_5
.compute_rest(indexes, starting_indexes, exit)?;
self.ratio_p99
.compute_rest(indexes, starting_indexes, exit)?;
self.ratio_p1
.compute_rest(indexes, starting_indexes, exit)?;
self.ratio_p0_5
.compute_rest(indexes, starting_indexes, exit)?;
self.ratio_p0_1
.compute_rest(indexes, starting_indexes, exit)?;
self.ratio_standard_deviation
.compute_rest(indexes, starting_indexes, exit)?;
self.ratio_p1sd
.compute_rest(indexes, starting_indexes, exit)?;
self.ratio_p2sd
.compute_rest(indexes, starting_indexes, exit)?;
self.ratio_p3sd
.compute_rest(indexes, starting_indexes, exit)?;
self.ratio_m1sd
.compute_rest(indexes, starting_indexes, exit)?;
self.ratio_m2sd
.compute_rest(indexes, starting_indexes, exit)?;
self.ratio_m3sd
.compute_rest(indexes, starting_indexes, exit)?;
self.ratio_p99_as_price.compute(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
let mut iter = self.ratio_p99.dateindex.into_iter();
vec.compute_transform(
starting_indexes.dateindex,
&self.price.dateindex,
|(i, price, ..)| {
let multiplier = iter.unwrap_get_inner(i);
(i, price * multiplier)
},
exit,
)
},
)?;
self.ratio_p99_5_as_price.compute(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
let mut iter = self.ratio_p99_5.dateindex.into_iter();
vec.compute_transform(
starting_indexes.dateindex,
&self.price.dateindex,
|(i, price, ..)| {
let multiplier = iter.unwrap_get_inner(i);
(i, price * multiplier)
},
exit,
)
},
)?;
self.ratio_p99_9_as_price.compute(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
let mut iter = self.ratio_p99_9.dateindex.into_iter();
vec.compute_transform(
starting_indexes.dateindex,
&self.price.dateindex,
|(i, price, ..)| {
let multiplier = iter.unwrap_get_inner(i);
(i, price * multiplier)
},
exit,
)
},
)?;
self.ratio_p1_as_price.compute(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
let mut iter = self.ratio_p1.dateindex.into_iter();
vec.compute_transform(
starting_indexes.dateindex,
&self.price.dateindex,
|(i, price, ..)| {
let multiplier = iter.unwrap_get_inner(i);
(i, price * multiplier)
},
exit,
)
},
)?;
self.ratio_p0_5_as_price.compute(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
let mut iter = self.ratio_p0_5.dateindex.into_iter();
vec.compute_transform(
starting_indexes.dateindex,
&self.price.dateindex,
|(i, price, ..)| {
let multiplier = iter.unwrap_get_inner(i);
(i, price * multiplier)
},
exit,
)
},
)?;
self.ratio_p0_1_as_price.compute(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
let mut iter = self.ratio_p0_1.dateindex.into_iter();
vec.compute_transform(
starting_indexes.dateindex,
&self.price.dateindex,
|(i, price, ..)| {
let multiplier = iter.unwrap_get_inner(i);
(i, price * multiplier)
},
exit,
)
},
)?;
self.ratio_p1sd_as_price.compute(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
let mut iter = self.ratio_p1sd.dateindex.into_iter();
vec.compute_transform(
starting_indexes.dateindex,
&self.price.dateindex,
|(i, price, ..)| {
let multiplier = iter.unwrap_get_inner(i);
(i, price * multiplier)
},
exit,
)
},
)?;
self.ratio_p2sd_as_price.compute(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
let mut iter = self.ratio_p2sd.dateindex.into_iter();
vec.compute_transform(
starting_indexes.dateindex,
&self.price.dateindex,
|(i, price, ..)| {
let multiplier = iter.unwrap_get_inner(i);
(i, price * multiplier)
},
exit,
)
},
)?;
self.ratio_p3sd_as_price.compute(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
let mut iter = self.ratio_p3sd.dateindex.into_iter();
vec.compute_transform(
starting_indexes.dateindex,
&self.price.dateindex,
|(i, price, ..)| {
let multiplier = iter.unwrap_get_inner(i);
(i, price * multiplier)
},
exit,
)
},
)?;
self.ratio_m1sd_as_price.compute(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
let mut iter = self.ratio_m1sd.dateindex.into_iter();
vec.compute_transform(
starting_indexes.dateindex,
&self.price.dateindex,
|(i, price, ..)| {
let multiplier = iter.unwrap_get_inner(i);
(i, price * multiplier)
},
exit,
)
},
)?;
self.ratio_m2sd_as_price.compute(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
let mut iter = self.ratio_m2sd.dateindex.into_iter();
vec.compute_transform(
starting_indexes.dateindex,
&self.price.dateindex,
|(i, price, ..)| {
let multiplier = iter.unwrap_get_inner(i);
(i, price * multiplier)
},
exit,
)
},
)?;
self.ratio_m3sd_as_price.compute(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
let mut iter = self.ratio_m3sd.dateindex.into_iter();
vec.compute_transform(
starting_indexes.dateindex,
&self.price.dateindex,
|(i, price, ..)| {
let multiplier = iter.unwrap_get_inner(i);
(i, price * multiplier)
},
exit,
)
},
)?;
Ok(())
}
fn mut_ratio_vecs(&mut self) -> Vec<&mut EagerVec<DateIndex, StoredF32>> {
vec![
&mut self.ratio_standard_deviation.dateindex,
&mut self.ratio_p99_9.dateindex,
&mut self.ratio_p99_5.dateindex,
&mut self.ratio_p99.dateindex,
&mut self.ratio_p1.dateindex,
&mut self.ratio_p0_5.dateindex,
&mut self.ratio_p0_1.dateindex,
&mut self.ratio_p1sd.dateindex,
&mut self.ratio_p2sd.dateindex,
&mut self.ratio_p3sd.dateindex,
&mut self.ratio_m1sd.dateindex,
&mut self.ratio_m2sd.dateindex,
&mut self.ratio_m3sd.dateindex,
]
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
[
self.price.vecs(),
self.ratio.vecs(),
self.ratio_sma.vecs(),
self.ratio_1w_sma.vecs(),
self.ratio_1m_sma.vecs(),
self.ratio_1y_sma.vecs(),
self.ratio_1y_sma_momentum_oscillator.vecs(),
self.ratio_standard_deviation.vecs(),
self.ratio_p99_9.vecs(),
self.ratio_p99_5.vecs(),
self.ratio_p99.vecs(),
self.ratio_p1.vecs(),
self.ratio_p0_5.vecs(),
self.ratio_p0_1.vecs(),
self.ratio_p1sd.vecs(),
self.ratio_p2sd.vecs(),
self.ratio_p3sd.vecs(),
self.ratio_m1sd.vecs(),
self.ratio_m2sd.vecs(),
self.ratio_m3sd.vecs(),
self.ratio_p99_9_as_price.vecs(),
self.ratio_p99_5_as_price.vecs(),
self.ratio_p99_as_price.vecs(),
self.ratio_p1_as_price.vecs(),
self.ratio_p0_5_as_price.vecs(),
self.ratio_p0_1_as_price.vecs(),
self.ratio_p1sd_as_price.vecs(),
self.ratio_p2sd_as_price.vecs(),
self.ratio_p3sd_as_price.vecs(),
self.ratio_m1sd_as_price.vecs(),
self.ratio_m2sd_as_price.vecs(),
self.ratio_m3sd_as_price.vecs(),
]
.concat()
}
}
@@ -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,165 @@
use std::path::Path;
use brk_core::{Bitcoin, Dollars, Height, Sats};
use brk_exit::Exit;
use brk_indexer::Indexer;
use brk_vec::{
AnyCollectableVec, CollectableVec, Compressed, EagerVec, Result, StoredVec, Version,
};
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::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: &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 txindex = self.bitcoin.height.as_ref().unwrap();
let price = &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, txindex, price, 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()),
]
.concat()
}
}
@@ -0,0 +1,223 @@
use std::path::Path;
use brk_core::{Bitcoin, Close, Dollars, Height, Sats, TxIndex};
use brk_exit::Exit;
use brk_indexer::Indexer;
use brk_vec::{
AnyCollectableVec, BoxedAnyIterableVec, CloneableAnyIterableVec, CollectableVec, Compressed,
Computation, ComputedVecFrom3, LazyVecFrom1, StoredIndex, StoredVec, Version,
};
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::ONE;
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,
compressed: Compressed,
fetched: Option<&fetched::Vecs>,
options: StorableVecGeneatorOptions,
) -> color_eyre::Result<Self> {
let compute_source = source.is_none();
let compute_dollars = fetched.is_some();
let sats = ComputedVecsFromTxindex::forced_import(
path,
name,
compute_source,
VERSION + version,
compressed,
options,
)?;
let bitcoin_txindex = LazyVecFrom1::init(
"txindex_to_{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,
&format!("{name}_in_btc"),
false,
VERSION + version,
compressed,
options,
)?;
let dollars_txindex = fetched.map(|fetched| {
ComputedVecFrom3::forced_import_or_init_from_3(
computation,
path,
"txindex_to_{name}_in_usd",
VERSION + version,
compressed,
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,
&format!("{name}_in_usd"),
false,
VERSION + version,
compressed,
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>>,
) -> 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(
indexer,
indexes,
starting_indexes,
exit,
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, exit)?;
dollars.compute_rest(
indexer,
indexes,
starting_indexes,
exit,
Some(dollars_txindex),
)?;
}
Ok(())
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
[
self.sats.vecs(),
self.bitcoin.vecs(),
self.dollars.as_ref().map_or(vec![], |v| v.vecs()),
]
.concat()
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+128
View File
@@ -0,0 +1,128 @@
use std::{fs, path::Path};
use brk_core::{DifficultyEpoch, HalvingEpoch, StoredF64};
use brk_exit::Exit;
use brk_indexer::Indexer;
use brk_vec::{AnyCollectableVec, Compressed, Computation, VecIterator, Version};
use super::{
Indexes,
grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, StorableVecGeneatorOptions},
indexes,
};
#[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,
_computation: Computation,
compressed: Compressed,
) -> color_eyre::Result<Self> {
fs::create_dir_all(path)?;
Ok(Self {
indexes_to_difficulty: ComputedVecsFromHeight::forced_import(
path,
"difficulty",
false,
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_last(),
)?,
indexes_to_difficultyepoch: ComputedVecsFromDateIndex::forced_import(
path,
"difficultyepoch",
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_last(),
)?,
indexes_to_halvingepoch: ComputedVecsFromDateIndex::forced_import(
path,
"halvingepoch",
Version::ZERO,
compressed,
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(
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(
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(),
]
.concat()
}
}
+125
View File
@@ -0,0 +1,125 @@
use std::{fs, path::Path};
use brk_exit::Exit;
use brk_fetcher::Fetcher;
use brk_indexer::Indexer;
use brk_vec::{AnyCollectableVec, Compressed, Computation};
pub mod blocks;
pub mod constants;
pub mod fetched;
pub mod grouped;
pub mod indexes;
pub mod market;
pub mod mining;
pub mod transactions;
pub use indexes::Indexes;
#[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 fetched: Option<fetched::Vecs>,
}
impl Vecs {
pub fn import(
path: &Path,
indexer: &Indexer,
fetch: bool,
computation: Computation,
compressed: Compressed,
) -> color_eyre::Result<Self> {
fs::create_dir_all(path)?;
let indexes = indexes::Vecs::forced_import(path, indexer, computation, compressed)?;
let fetched =
fetch.then(|| fetched::Vecs::forced_import(path, computation, compressed).unwrap());
Ok(Self {
blocks: blocks::Vecs::forced_import(path, computation, compressed)?,
mining: mining::Vecs::forced_import(path, computation, compressed)?,
constants: constants::Vecs::forced_import(path, computation, compressed)?,
market: market::Vecs::forced_import(path, computation, compressed)?,
transactions: transactions::Vecs::forced_import(
path,
indexer,
&indexes,
computation,
compressed,
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)?;
self.constants
.compute(indexer, &self.indexes, &starting_indexes, exit)?;
self.blocks
.compute(indexer, &self.indexes, &starting_indexes, exit)?;
self.mining
.compute(indexer, &self.indexes, &starting_indexes, exit)?;
if let Some(fetched) = self.fetched.as_mut() {
fetched.compute(
indexer,
&self.indexes,
&starting_indexes,
fetcher.unwrap(),
exit,
)?;
}
self.transactions.compute(
indexer,
&self.indexes,
&starting_indexes,
self.fetched.as_ref(),
exit,
)?;
if let Some(fetched) = self.fetched.as_ref() {
self.market.compute(
indexer,
&self.indexes,
fetched,
&mut self.transactions,
&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.fetched.as_ref().map_or(vec![], |v| v.vecs()),
]
.concat()
}
}
File diff suppressed because it is too large Load Diff
+2
View File
@@ -16,8 +16,10 @@ log = { workspace = true }
rapidhash = "1.4.0"
rlimit = "0.10.2"
serde = { workspace = true }
serde_derive = { workspace = true }
serde_bytes = "0.11.17"
zerocopy = { workspace = true }
zerocopy-derive = { workspace = true }
[package.metadata.cargo-machete]
ignored = ["serde_bytes"]
+2 -2
View File
@@ -20,7 +20,7 @@
<a href="https://deps.rs/crate/brk_core">
<img src="https://deps.rs/crate/brk_core/latest/status.svg" alt="Dependency status">
</a>
<a href="https://discord.gg/Cvrwpv3zEG">
<a href="https://discord.gg/HaR3wpH3nr">
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
</a>
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
@@ -29,7 +29,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,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,56 @@ 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 {
impl TryFrom<ByteView> for AddressIndex {
type Error = Error;
fn try_from(value: ByteView) -> Result<Self, Self::Error> {
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,28 @@
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 TryFrom<ByteView> for AddressIndexOutputIndex {
type Error = Error;
fn try_from(value: ByteView) -> Result<Self, Self::Error> {
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!()
}
}
}
}
+129 -76
View File
@@ -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,61 @@
use std::hash::Hasher;
use byteview::ByteView;
use derive_deref::Deref;
use zerocopy::{FromBytes, IntoBytes};
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
use crate::Error;
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 TryFrom<ByteView> for AddressBytesHash {
type Error = Error;
fn try_from(value: ByteView) -> Result<Self, Self::Error> {
Ok(Self::read_from_bytes(&value)?)
}
}
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,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)
}
}
+55 -5
View File
@@ -1,20 +1,49 @@
use std::ops::Mul;
use std::ops::{Add, Div, Mul};
use super::Sats;
use serde::Serialize;
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
#[derive(Debug, Default, Clone, Copy)]
use super::{Sats, StoredF64};
#[derive(
Debug,
Default,
Clone,
Copy,
PartialEq,
PartialOrd,
FromBytes,
Immutable,
IntoBytes,
KnownLayout,
Serialize,
)]
pub struct Bitcoin(f64);
impl Add for Bitcoin {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self::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 Div<usize> for Bitcoin {
type Output = Self;
fn div(self, rhs: usize) -> Self::Output {
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)))
}
}
@@ -24,8 +53,29 @@ 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
}
}
impl From<usize> for Bitcoin {
fn from(value: usize) -> Self {
Self(value as f64)
}
}
impl Eq for Bitcoin {}
#[allow(clippy::derive_ord_xor_partial_ord)]
impl Ord for Bitcoin {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0.partial_cmp(&other.0).unwrap()
}
}
+1 -1
View File
@@ -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,55 @@
use byteview::ByteView;
use derive_deref::Deref;
use zerocopy::{FromBytes, IntoBytes};
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
use crate::{Error, 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 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)
}
}
+59 -2
View File
@@ -1,5 +1,7 @@
use std::ops::{Add, Div, Mul};
use serde::Serialize;
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
use super::Dollars;
@@ -22,7 +24,7 @@ pub struct Cents(u64);
impl From<Dollars> for Cents {
fn from(value: Dollars) -> Self {
Self((*value * 100.0).floor() as u64)
Self((*value * 100.0).round() as u64)
}
}
@@ -31,3 +33,58 @@ impl From<Cents> for f64 {
value.0 as f64
}
}
impl From<u64> for Cents {
fn from(value: u64) -> Self {
Self(value)
}
}
impl From<Cents> for u64 {
fn from(value: Cents) -> Self {
value.0
}
}
impl Add for Cents {
type Output = Self;
fn add(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 u64)
}
}
impl From<u128> for Cents {
fn from(value: u128) -> Self {
if value > u64::MAX as u128 {
panic!("u128 bigger than u64")
}
Self(value as u64)
}
}
impl From<Cents> for u128 {
fn from(value: Cents) -> Self {
value.0 as u128
}
}
impl Mul<Cents> for Cents {
type Output = Cents;
fn mul(self, rhs: Cents) -> Self::Output {
Self(self.0 * rhs.0)
}
}
impl Mul<usize> for Cents {
type Output = Cents;
fn mul(self, rhs: usize) -> Self::Output {
Self(self.0 * rhs as u64)
}
}
-156
View File
@@ -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)
}
+6 -5
View File
@@ -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(
+11 -11
View File
@@ -2,7 +2,7 @@ use std::ops::Add;
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 +23,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,7 +72,7 @@ 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)
}
+14 -14
View File
@@ -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)
+28 -10
View File
@@ -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)
}
+107 -5
View File
@@ -1,10 +1,13 @@
use std::ops::{Add, Div};
use std::{
f64,
ops::{Add, Div, Mul},
};
use derive_deref::Deref;
use serde::Serialize;
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
use super::Cents;
use super::{Bitcoin, Cents, Close, Sats, StoredF32, StoredF64};
#[derive(
Debug,
@@ -22,6 +25,20 @@ use super::Cents;
)]
pub struct Dollars(f64);
impl Dollars {
pub const ZERO: Self = Self(0.0);
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 +51,24 @@ 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<usize> for Dollars {
fn from(value: usize) -> Self {
Self(value as f64)
@@ -49,14 +78,42 @@ 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 {
StoredF64::from(self.0 / rhs.0)
}
}
impl Div<Close<Dollars>> for Dollars {
type Output = StoredF64;
fn div(self, rhs: Close<Dollars>) -> Self::Output {
StoredF64::from(self.0 / rhs.0)
}
}
impl Div<Dollars> for Close<Dollars> {
type Output = StoredF64;
fn div(self, rhs: Dollars) -> Self::Output {
StoredF64::from(self.0 / rhs.0)
}
}
impl Div<usize> for Dollars {
type Output = Self;
fn div(self, rhs: usize) -> Self::Output {
Self(self.0 / rhs as f64)
Self::from(Cents::from(self) / rhs)
}
}
impl Div<Bitcoin> for Dollars {
type Output = Self;
fn div(self, rhs: Bitcoin) -> Self::Output {
Self(f64::from(self) / f64::from(rhs))
}
}
@@ -68,3 +125,48 @@ impl Ord for Dollars {
self.0.partial_cmp(&other.0).unwrap()
}
}
impl Mul<Bitcoin> for Dollars {
type Output = Self;
fn mul(self, rhs: Bitcoin) -> Self::Output {
Self::from(Cents::from(
u128::from(Sats::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.is_nan() {
Self(f64::NAN)
} else {
Self::from(Cents::from(Self::from(self.0 * *rhs as f64)))
}
}
}
impl Mul<usize> for Dollars {
type Output = Self;
fn mul(self, rhs: usize) -> Self::Output {
Self::from(Cents::from(self) * rhs)
}
}
impl From<u128> for Dollars {
fn from(value: u128) -> Self {
Self::from(Cents::from(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))
}
}
+64 -3
View File
@@ -1,5 +1,66 @@
use serde::Serialize;
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
use std::ops::{Add, Div};
#[derive(Debug, Clone, Copy, Serialize, FromBytes, Immutable, IntoBytes, KnownLayout)]
use serde::Serialize;
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
use super::{Sats, StoredUsize};
#[derive(
Debug,
Clone,
Copy,
Serialize,
PartialEq,
PartialOrd,
FromBytes,
Immutable,
IntoBytes,
KnownLayout,
)]
pub struct Feerate(f32);
impl From<(Sats, StoredUsize)> for Feerate {
fn from((sats, vsize): (Sats, StoredUsize)) -> Self {
Self((f64::from(sats) / f64::from(vsize)) as f32)
}
}
impl From<f64> for Feerate {
fn from(value: f64) -> Self {
Self(value as f32)
}
}
impl From<Feerate> for f64 {
fn from(value: Feerate) -> Self {
value.0 as f64
}
}
impl Add for Feerate {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0)
}
}
impl Div<usize> for Feerate {
type Output = Self;
fn div(self, rhs: usize) -> Self::Output {
Self((self.0 as f64 / rhs as f64) as f32)
}
}
impl From<usize> for Feerate {
fn from(value: usize) -> Self {
Self(value as f32)
}
}
impl Eq for Feerate {}
#[allow(clippy::derive_ord_xor_partial_ord)]
impl Ord for Feerate {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0.partial_cmp(&other.0).unwrap()
}
}
+28 -10
View File
@@ -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 Halvingepoch(u8);
pub struct HalvingEpoch(u8);
impl From<u8> for Halvingepoch {
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 +62,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 -9
View File
@@ -5,7 +5,8 @@ use std::{
use bitcoincore_rpc::{Client, RpcApi};
use serde::{Deserialize, Serialize};
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
use zerocopy::{FromBytes, IntoBytes};
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
use crate::CheckedSub;
@@ -28,8 +29,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)
@@ -181,12 +182,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> {
@@ -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
}
}
-30
View File
@@ -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()),
}
}
}
+28 -16
View File
@@ -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,20 +15,25 @@ 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 vin;
@@ -38,14 +43,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,20 +59,25 @@ 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 vin::*;
@@ -75,3 +85,5 @@ pub use vout::*;
pub use weekindex::*;
pub use weight::*;
pub use yearindex::*;
pub use rlimit;
+13 -13
View File
@@ -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)
}
+205 -100
View File
@@ -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 {
@@ -99,6 +113,51 @@ impl From<&OHLCCents> for OHLCDollars {
}
}
#[derive(Debug, Default, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
#[repr(C)]
pub struct OHLCSats {
pub open: Open<Sats>,
pub high: High<Sats>,
pub low: Low<Sats>,
pub close: Close<Sats>,
}
impl Serialize for OHLCSats {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut tup = serializer.serialize_tuple(4)?;
tup.serialize_element(&self.open)?;
tup.serialize_element(&self.high)?;
tup.serialize_element(&self.low)?;
tup.serialize_element(&self.close)?;
tup.end()
}
}
impl From<(Open<Sats>, High<Sats>, Low<Sats>, Close<Sats>)> for OHLCSats {
fn from(value: (Open<Sats>, High<Sats>, Low<Sats>, Close<Sats>)) -> Self {
Self {
open: value.0,
high: value.1,
low: value.2,
close: value.3,
}
}
}
impl From<Close<Sats>> for OHLCSats {
fn from(value: Close<Sats>) -> Self {
Self {
open: Open::from(value),
high: High::from(value),
low: Low::from(value),
close: value,
}
}
}
#[derive(
Debug,
Default,
@@ -117,12 +176,40 @@ impl From<&OHLCCents> for OHLCDollars {
)]
#[repr(C)]
pub struct Open<T>(T);
impl<T> From<T> for Open<T> {
fn from(value: T) -> Self {
impl<T> Open<T> {
pub fn new(value: T) -> Self {
Self(value)
}
}
impl<T> From<usize> for Open<T>
where
T: From<usize>,
{
fn from(value: usize) -> Self {
Self(T::from(value))
}
}
impl<T> From<f64> for Open<T>
where
T: From<f64>,
{
fn from(value: f64) -> Self {
Self(T::from(value))
}
}
impl<T> From<Open<T>> for f64
where
f64: From<T>,
{
fn from(value: Open<T>) -> Self {
Self::from(value.0)
}
}
impl<T> From<Close<T>> for Open<T>
where
T: Copy,
@@ -138,24 +225,6 @@ impl From<Open<Cents>> for Open<Dollars> {
}
}
impl From<usize> for Open<Dollars> {
fn from(value: usize) -> Self {
Self(Dollars::from(value))
}
}
impl From<f64> for Open<Dollars> {
fn from(value: f64) -> Self {
Self(Dollars::from(value))
}
}
impl From<Open<Dollars>> for f64 {
fn from(value: Open<Dollars>) -> Self {
Self::from(value.0)
}
}
impl<T> Add for Open<T>
where
T: Add<Output = T>,
@@ -194,12 +263,40 @@ where
)]
#[repr(C)]
pub struct High<T>(T);
impl<T> From<T> for High<T> {
fn from(value: T) -> Self {
impl<T> High<T> {
pub fn new(value: T) -> Self {
Self(value)
}
}
impl<T> From<usize> for High<T>
where
T: From<usize>,
{
fn from(value: usize) -> Self {
Self(T::from(value))
}
}
impl<T> From<f64> for High<T>
where
T: From<f64>,
{
fn from(value: f64) -> Self {
Self(T::from(value))
}
}
impl<T> From<High<T>> for f64
where
f64: From<T>,
{
fn from(value: High<T>) -> Self {
Self::from(value.0)
}
}
impl<T> From<Close<T>> for High<T>
where
T: Copy,
@@ -215,24 +312,6 @@ impl From<High<Cents>> for High<Dollars> {
}
}
impl From<usize> for High<Dollars> {
fn from(value: usize) -> Self {
Self(Dollars::from(value))
}
}
impl From<f64> for High<Dollars> {
fn from(value: f64) -> Self {
Self(Dollars::from(value))
}
}
impl From<High<Dollars>> for f64 {
fn from(value: High<Dollars>) -> Self {
Self::from(value.0)
}
}
impl<T> Add for High<T>
where
T: Add<Output = T>,
@@ -271,12 +350,40 @@ where
)]
#[repr(C)]
pub struct Low<T>(T);
impl<T> From<T> for Low<T> {
fn from(value: T) -> Self {
impl<T> Low<T> {
pub fn new(value: T) -> Self {
Self(value)
}
}
impl<T> From<usize> for Low<T>
where
T: From<usize>,
{
fn from(value: usize) -> Self {
Self(T::from(value))
}
}
impl<T> From<f64> for Low<T>
where
T: From<f64>,
{
fn from(value: f64) -> Self {
Self(T::from(value))
}
}
impl<T> From<Low<T>> for f64
where
f64: From<T>,
{
fn from(value: Low<T>) -> Self {
Self::from(value.0)
}
}
impl<T> From<Close<T>> for Low<T>
where
T: Copy,
@@ -292,24 +399,6 @@ impl From<Low<Cents>> for Low<Dollars> {
}
}
impl From<usize> for Low<Dollars> {
fn from(value: usize) -> Self {
Self(Dollars::from(value))
}
}
impl From<f64> for Low<Dollars> {
fn from(value: f64) -> Self {
Self(Dollars::from(value))
}
}
impl From<Low<Dollars>> for f64 {
fn from(value: Low<Dollars>) -> Self {
Self::from(value.0)
}
}
impl<T> Add for Low<T>
where
T: Add<Output = T>,
@@ -348,54 +437,70 @@ where
)]
#[repr(C)]
pub struct Close<T>(T);
impl<T> From<T> for Close<T> {
fn from(value: T) -> Self {
impl<T> Close<T> {
pub fn new(value: T) -> Self {
Self(value)
}
}
impl<T> From<usize> for Close<T>
where
T: From<usize>,
{
fn from(value: usize) -> Self {
Self(T::from(value))
}
}
impl<T> From<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>,
{
fn from(value: f64) -> Self {
Self(T::from(value))
}
}
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>,
{
fn from(value: Close<T>) -> Self {
Self::from(value.0)
}
}
// impl<A, B> From<Close<A>> for Close<B>
// where
// B: From<A>,
// {
// fn from(value: Close<A>) -> Self {
// Self(B::from(*value))
impl From<Close<Cents>> for Close<Dollars> {
fn from(value: Close<Cents>) -> Self {
Self(Dollars::from(*value))
}
}
impl From<usize> for Close<Dollars> {
fn from(value: usize) -> Self {
Self(Dollars::from(value))
}
}
impl From<usize> for Close<Sats> {
fn from(value: usize) -> Self {
Self(Sats::from(value))
}
}
impl From<f64> for Close<Dollars> {
fn from(value: f64) -> Self {
Self(Dollars::from(value))
}
}
impl From<f64> for Close<Sats> {
fn from(value: f64) -> Self {
Self(Sats::from(value))
}
}
impl From<Close<Dollars>> for f64 {
fn from(value: Close<Dollars>) -> Self {
Self::from(value.0)
}
}
impl From<Close<Sats>> for f64 {
fn from(value: Close<Sats>) -> Self {
Self::from(value.0)
}
}
impl<T> Add for Close<T>
where
T: Add<Output = T>,
@@ -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
}
}
@@ -1,27 +1,38 @@
use bitcoin::ScriptBuf;
use bitcoin::{ScriptBuf, opcodes::all::OP_PUSHBYTES_2};
use serde::Serialize;
use zerocopy::{Immutable, IntoBytes, KnownLayout, TryFromBytes};
use zerocopy_derive::{Immutable, IntoBytes, KnownLayout, TryFromBytes};
#[derive(
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, TryFromBytes, Immutable, IntoBytes, KnownLayout, Serialize,
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
TryFromBytes,
Immutable,
IntoBytes,
KnownLayout,
Serialize,
)]
#[repr(u8)]
pub enum Addresstype {
pub enum OutputType {
P2PK65,
P2PK33,
P2PKH,
P2MS,
P2SH,
OpReturn,
P2WPKH,
P2WSH,
P2TR,
Multisig = 251,
PushOnly = 252,
OpReturn = 253,
P2A,
Empty = 254,
Unknown = 255,
}
impl From<&ScriptBuf> for Addresstype {
impl From<&ScriptBuf> for OutputType {
fn from(script: &ScriptBuf) -> Self {
if script.is_p2pk() {
let bytes = script.as_bytes();
@@ -36,22 +47,26 @@ impl From<&ScriptBuf> for Addresstype {
}
} 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 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
}
@@ -0,0 +1,635 @@
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, Error};
#[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 TryFrom<ByteView> for OutputTypeIndex {
type Error = Error;
fn try_from(value: ByteView) -> Result<Self, Self::Error> {
Ok(Self::read_from_bytes(&value)?)
}
}
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)
}
}
+11 -11
View File
@@ -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()
}
}
}
+28 -7
View File
@@ -5,11 +5,11 @@ use std::{
use bitcoin::Amount;
use serde::Serialize;
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
use crate::CheckedSub;
use super::{Bitcoin, Dollars, Height};
use super::{Bitcoin, Cents, Dollars, Height};
#[derive(
Debug,
@@ -30,6 +30,7 @@ pub struct Sats(u64);
impl Sats {
pub const ZERO: Self = Self(0);
pub const MAX: Self = Self(u64::MAX);
pub const ONE_BTC: Self = Self(100_000_000);
pub fn is_zero(&self) -> bool {
@@ -39,8 +40,8 @@ impl Sats {
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)
}
}
@@ -93,7 +94,12 @@ 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
}
}
}
@@ -118,7 +124,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)
}
}
@@ -141,7 +147,7 @@ impl From<Sats> for Amount {
impl From<Bitcoin> for Sats {
fn from(value: Bitcoin) -> Self {
Self((f64::from(value) * (u64::from(Sats::ONE_BTC) as f64)) as u64)
Self((f64::from(value) * (Sats::ONE_BTC.0 as f64)).round() as u64)
}
}
@@ -150,3 +156,18 @@ 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
}
}
+112
View File
@@ -0,0 +1,112 @@
use std::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,
PartialEq,
PartialOrd,
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 {
Self(value as f32)
}
}
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 Eq for StoredF32 {}
#[allow(clippy::derive_ord_xor_partial_ord)]
impl Ord for StoredF32 {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0.partial_cmp(&other.0).unwrap()
}
}
impl Div<Dollars> for StoredF32 {
type Output = Self;
fn div(self, rhs: Dollars) -> Self::Output {
Self::from(self.0 as f64 / *rhs)
}
}
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)
}
}
+83
View File
@@ -0,0 +1,83 @@
use std::ops::{Add, Div, Mul};
use derive_deref::Deref;
use serde::Serialize;
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
use crate::CheckedSub;
#[derive(
Debug,
Deref,
Default,
Clone,
Copy,
PartialEq,
PartialOrd,
FromBytes,
Immutable,
IntoBytes,
KnownLayout,
Serialize,
)]
pub struct StoredF64(f64);
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 Eq for StoredF64 {}
#[allow(clippy::derive_ord_xor_partial_ord)]
impl Ord for StoredF64 {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0.partial_cmp(&other.0).unwrap()
}
}
impl CheckedSub<usize> for StoredF64 {
fn checked_sub(self, rhs: usize) -> Option<Self> {
Some(Self(self.0 - rhs as f64))
}
}
+87 -1
View File
@@ -2,10 +2,15 @@ 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,
@@ -39,6 +44,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 +85,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))
}
}
+8 -8
View File
@@ -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)
}
}
+17 -1
View File
@@ -2,11 +2,14 @@ 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;
pub type StoredPhantom = StoredU8;
#[derive(
Default,
Debug,
Deref,
Clone,
@@ -77,3 +80,16 @@ impl From<StoredU8> for f64 {
value.0 as f64
}
}
impl Add<usize> for StoredU8 {
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
Self(self.0.checked_add(rhs as u8).unwrap())
}
}
impl From<StoredU8> for usize {
fn from(value: StoredU8) -> Self {
value.0 as usize
}
}
+122 -1
View File
@@ -2,14 +2,21 @@ 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::{
DateIndex, EmptyOutputIndex, Height, InputIndex, MonthIndex, OpReturnIndex, OutputIndex,
P2AIndex, P2MSIndex, P2PK33Index, P2PK65Index, P2PKHIndex, P2SHIndex, P2TRIndex, P2WPKHIndex,
P2WSHIndex, TxIndex, UnknownOutputIndex, YearIndex,
};
#[derive(
Debug,
Deref,
Clone,
Default,
Copy,
PartialEq,
Eq,
@@ -71,3 +78,117 @@ impl From<StoredUsize> for f64 {
value.0 as f64
}
}
impl From<Height> for StoredUsize {
fn from(value: Height) -> Self {
Self::from(usize::from(value))
}
}
impl From<DateIndex> for StoredUsize {
fn from(value: DateIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<MonthIndex> for StoredUsize {
fn from(value: MonthIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<YearIndex> for StoredUsize {
fn from(value: YearIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<OutputIndex> for StoredUsize {
fn from(value: OutputIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<InputIndex> for StoredUsize {
fn from(value: InputIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<TxIndex> for StoredUsize {
fn from(value: TxIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<P2PK65Index> for StoredUsize {
fn from(value: P2PK65Index) -> Self {
Self::from(usize::from(value))
}
}
impl From<P2PK33Index> for StoredUsize {
fn from(value: P2PK33Index) -> Self {
Self::from(usize::from(value))
}
}
impl From<P2PKHIndex> for StoredUsize {
fn from(value: P2PKHIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<OpReturnIndex> for StoredUsize {
fn from(value: OpReturnIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<P2MSIndex> for StoredUsize {
fn from(value: P2MSIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<P2SHIndex> for StoredUsize {
fn from(value: P2SHIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<P2WSHIndex> for StoredUsize {
fn from(value: P2WSHIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<P2WPKHIndex> for StoredUsize {
fn from(value: P2WPKHIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<P2TRIndex> for StoredUsize {
fn from(value: P2TRIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<P2AIndex> for StoredUsize {
fn from(value: P2AIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<UnknownOutputIndex> for StoredUsize {
fn from(value: UnknownOutputIndex) -> Self {
Self::from(usize::from(value))
}
}
impl From<EmptyOutputIndex> for StoredUsize {
fn from(value: EmptyOutputIndex) -> Self {
Self::from(usize::from(value))
}
}
+1 -7
View File
@@ -3,7 +3,7 @@ use std::ops::{Add, Div};
use derive_deref::Deref;
use jiff::{civil::date, tz::TimeZone};
use serde::Serialize;
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
use crate::CheckedSub;
@@ -65,12 +65,6 @@ impl From<bitcoin::locktime::absolute::Time> for Timestamp {
}
}
impl From<Timestamp> for bitcoin::locktime::absolute::Time {
fn from(value: Timestamp) -> Self {
bitcoin::locktime::absolute::Time::from_consensus(*value).unwrap()
}
}
impl From<usize> for Timestamp {
fn from(value: usize) -> Self {
Self(value as u32)
+1 -1
View File
@@ -3,7 +3,7 @@ use std::{fmt, mem};
use bitcoin::hashes::Hash;
use derive_deref::Deref;
use serde::{Serialize, Serializer};
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
#[derive(Debug, Deref, Clone, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
pub struct Txid([u8; 32]);
+61
View File
@@ -0,0 +1,61 @@
use byteview::ByteView;
use derive_deref::Deref;
use zerocopy::{FromBytes, IntoBytes};
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
use crate::{Error, copy_first_8bytes};
use super::Txid;
#[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)
}
}
+36 -21
View File
@@ -3,10 +3,13 @@ use std::ops::{Add, AddAssign};
use byteview::ByteView;
use derive_deref::{Deref, DerefMut};
use serde::Serialize;
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
use zerocopy::{FromBytes, IntoBytes};
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
use crate::{CheckedSub, Error};
use super::StoredU32;
#[derive(
Debug,
PartialEq,
@@ -24,76 +27,88 @@ use crate::{CheckedSub, Error};
KnownLayout,
Serialize,
)]
pub struct Txindex(u32);
pub struct TxIndex(u32);
impl TxIndex {
pub const ZERO: Self = Self(0);
pub fn new(txindex: u32) -> Self {
Self(txindex)
}
impl Txindex {
pub fn incremented(self) -> Self {
Self(*self + 1)
}
}
impl Add<Txindex> for Txindex {
impl Add<TxIndex> for TxIndex {
type Output = Self;
fn add(self, rhs: Txindex) -> Self::Output {
fn add(self, rhs: TxIndex) -> Self::Output {
Self(self.0 + rhs.0)
}
}
impl Add<usize> for Txindex {
impl Add<usize> for TxIndex {
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
Self(self.0 + rhs as u32)
}
}
impl AddAssign<Txindex> for Txindex {
fn add_assign(&mut self, rhs: Txindex) {
impl AddAssign<TxIndex> for TxIndex {
fn add_assign(&mut self, rhs: TxIndex) {
self.0 += rhs.0
}
}
impl CheckedSub<Txindex> for Txindex {
fn checked_sub(self, rhs: Txindex) -> Option<Self> {
self.0.checked_sub(rhs.0).map(Txindex::from)
impl CheckedSub<TxIndex> for TxIndex {
fn checked_sub(self, rhs: TxIndex) -> Option<Self> {
self.0.checked_sub(rhs.0).map(TxIndex::from)
}
}
impl From<u32> for Txindex {
impl From<u32> for TxIndex {
fn from(value: u32) -> Self {
Self(value)
}
}
impl From<u64> for Txindex {
impl From<u64> for TxIndex {
fn from(value: u64) -> Self {
Self(value as u32)
}
}
impl From<Txindex> for u64 {
fn from(value: Txindex) -> Self {
impl From<TxIndex> for u64 {
fn from(value: TxIndex) -> Self {
value.0 as u64
}
}
impl From<usize> for Txindex {
impl From<usize> for TxIndex {
fn from(value: usize) -> Self {
Self(value as u32)
}
}
impl From<Txindex> for usize {
fn from(value: Txindex) -> Self {
impl From<TxIndex> for usize {
fn from(value: TxIndex) -> Self {
value.0 as usize
}
}
impl TryFrom<ByteView> for Txindex {
impl TryFrom<ByteView> for TxIndex {
type Error = Error;
fn try_from(value: ByteView) -> Result<Self, Self::Error> {
Ok(Self::read_from_bytes(&value)?)
}
}
impl From<Txindex> for ByteView {
fn from(value: Txindex) -> Self {
impl From<TxIndex> for ByteView {
fn from(value: TxIndex) -> Self {
Self::new(value.as_bytes())
}
}
impl From<TxIndex> for StoredU32 {
fn from(value: TxIndex) -> Self {
Self::from(value.0)
}
}
+32 -6
View File
@@ -1,26 +1,52 @@
use derive_deref::Deref;
use serde::Serialize;
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
use super::StoredU8;
#[derive(Debug, Deref, Clone, Copy, Immutable, IntoBytes, KnownLayout, FromBytes, Serialize)]
pub struct TxVersion(i32);
#[derive(
Debug,
Deref,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Immutable,
IntoBytes,
KnownLayout,
FromBytes,
Serialize,
)]
pub struct TxVersion(u8);
impl TxVersion {
pub const ONE: Self = Self(1);
pub const TWO: Self = Self(2);
pub const THREE: Self = Self(3);
pub const NON_STANDARD: Self = Self(u8::MAX);
}
impl From<bitcoin::transaction::Version> for TxVersion {
fn from(value: bitcoin::transaction::Version) -> Self {
Self(value.0)
match value.0 {
1 => Self::ONE,
2 => Self::TWO,
3 => Self::THREE,
_ => Self::NON_STANDARD,
}
}
}
impl From<TxVersion> for bitcoin::transaction::Version {
fn from(value: TxVersion) -> Self {
Self(value.0)
Self(value.0 as i32)
}
}
impl From<TxVersion> for StoredU8 {
fn from(value: TxVersion) -> Self {
Self::from(value.0 as u8)
Self::from(value.0)
}
}
+12 -12
View File
@@ -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};
use super::{Date, DateIndex};
#[derive(
Debug,
@@ -23,27 +23,27 @@ use super::{Date, Dateindex};
IntoBytes,
KnownLayout,
)]
pub struct Weekindex(u16);
pub struct WeekIndex(u16);
impl From<u16> for Weekindex {
impl From<u16> for WeekIndex {
fn from(value: u16) -> Self {
Self(value)
}
}
impl From<usize> for Weekindex {
impl From<usize> for WeekIndex {
fn from(value: usize) -> Self {
Self(value as u16)
}
}
impl From<Weekindex> for usize {
fn from(value: Weekindex) -> Self {
impl From<WeekIndex> for usize {
fn from(value: WeekIndex) -> Self {
value.0 as usize
}
}
impl Add<usize> for Weekindex {
impl Add<usize> for WeekIndex {
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
@@ -51,13 +51,13 @@ impl Add<usize> for Weekindex {
}
}
impl From<Dateindex> for Weekindex {
fn from(value: Dateindex) -> Self {
impl From<DateIndex> for WeekIndex {
fn from(value: DateIndex) -> Self {
Self::from(Date::from(value))
}
}
impl From<Date> for Weekindex {
impl From<Date> for WeekIndex {
fn from(value: Date) -> Self {
let date = jiff::civil::Date::from(value).iso_week_date();
@@ -81,7 +81,7 @@ impl From<Date> for Weekindex {
}
}
impl CheckedSub for Weekindex {
impl CheckedSub for WeekIndex {
fn checked_sub(self, rhs: Self) -> Option<Self> {
self.0.checked_sub(rhs.0).map(Self)
}
+9 -2
View File
@@ -2,7 +2,7 @@ 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};
#[derive(
Debug,
@@ -29,7 +29,7 @@ impl From<bitcoin::Weight> for Weight {
impl From<Weight> for bitcoin::Weight {
fn from(value: Weight) -> Self {
Self::from_wu(*value)
Self::from_wu(value.0)
}
}
@@ -64,3 +64,10 @@ impl Div<usize> for Weight {
Self::from(self.0 as usize / rhs)
}
}
impl Div<Weight> for Weight {
type Output = Self;
fn div(self, rhs: Self) -> Self::Output {
Self(self.0 / rhs.0)
}
}
+16 -16
View File
@@ -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, Monthindex};
use super::{Date, DateIndex, MonthIndex};
#[derive(
Debug,
@@ -23,27 +23,27 @@ use super::{Date, Dateindex, Monthindex};
IntoBytes,
KnownLayout,
)]
pub struct Yearindex(u8);
pub struct YearIndex(u8);
impl From<u8> for Yearindex {
impl From<u8> for YearIndex {
fn from(value: u8) -> Self {
Self(value)
}
}
impl From<usize> for Yearindex {
impl From<usize> for YearIndex {
fn from(value: usize) -> Self {
Self(value as u8)
}
}
impl From<Yearindex> for usize {
fn from(value: Yearindex) -> Self {
impl From<YearIndex> for usize {
fn from(value: YearIndex) -> Self {
value.0 as usize
}
}
impl Add<usize> for Yearindex {
impl Add<usize> for YearIndex {
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
@@ -51,32 +51,32 @@ impl Add<usize> for Yearindex {
}
}
impl From<Dateindex> for Yearindex {
fn from(value: Dateindex) -> Self {
impl From<DateIndex> for YearIndex {
fn from(value: DateIndex) -> Self {
Self::from(Date::from(value))
}
}
impl From<Date> for Yearindex {
impl From<Date> for YearIndex {
fn from(value: Date) -> Self {
Self((value.year() - 2009) as u8)
}
}
impl From<Yearindex> for u16 {
fn from(value: Yearindex) -> Self {
impl From<YearIndex> for u16 {
fn from(value: YearIndex) -> Self {
value.0 as u16
}
}
impl CheckedSub for Yearindex {
impl CheckedSub for YearIndex {
fn checked_sub(self, rhs: Self) -> Option<Self> {
self.0.checked_sub(rhs.0).map(Self)
}
}
impl From<Monthindex> for Yearindex {
fn from(value: Monthindex) -> Self {
impl From<MonthIndex> for YearIndex {
fn from(value: MonthIndex) -> Self {
Self((usize::from(value) / 12) as u8)
}
}
+12
View File
@@ -0,0 +1,12 @@
#[allow(clippy::result_unit_err)]
pub fn copy_first_8bytes(slice: &[u8]) -> Result<[u8; 8], ()> {
let mut buf: [u8; 8] = [0; 8];
let buf_len = buf.len();
if slice.len() < buf_len {
return Err(());
}
slice.iter().take(buf_len).enumerate().for_each(|(i, r)| {
buf[i] = *r;
});
Ok(buf)
}
+2
View File
@@ -1,8 +1,10 @@
mod bytes;
mod checked_sub;
mod paths;
mod pause;
mod rlimit;
pub use bytes::*;
pub use checked_sub::*;
pub use paths::*;
pub use pause::*;
+8 -1
View File
@@ -4,7 +4,14 @@ use rlimit::{Resource, getrlimit};
pub fn setrlimit() -> io::Result<()> {
let no_file_limit = getrlimit(Resource::NOFILE)?;
rlimit::setrlimit(Resource::NOFILE, no_file_limit.0.max(210_000), no_file_limit.1)?;
rlimit::setrlimit(
Resource::NOFILE,
no_file_limit.0.max(210_000),
no_file_limit.1,
)?;
// let no_stack = getrlimit(Resource::STACK)?;
// rlimit::setrlimit(Resource::STACK, no_stack.1, no_stack.1)?;
Ok(())
}
+1 -1
View File
@@ -8,5 +8,5 @@ repository.workspace = true
[dependencies]
brk_logger = { workspace = true }
ctrlc = { version = "3.4.6", features = ["termination"] }
ctrlc = { version = "3.4.7", features = ["termination"] }
log = { workspace = true }
+2 -2
View File
@@ -20,7 +20,7 @@
<a href="https://deps.rs/crate/brk_exit">
<img src="https://deps.rs/crate/brk_exit/latest/status.svg" alt="Dependency status">
</a>
<a href="https://discord.gg/Cvrwpv3zEG">
<a href="https://discord.gg/HaR3wpH3nr">
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
</a>
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
@@ -29,7 +29,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 -2
View File
@@ -20,7 +20,7 @@
<a href="https://deps.rs/crate/brk_fetcher">
<img src="https://deps.rs/crate/brk_fetcher/latest/status.svg" alt="Dependency status">
</a>
<a href="https://discord.gg/Cvrwpv3zEG">
<a href="https://discord.gg/HaR3wpH3nr">
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
</a>
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
@@ -29,7 +29,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>
+4 -4
View File
@@ -223,10 +223,10 @@ impl Binance {
Ok((
timestamp,
OHLCCents::from((
Open::from(get_cents(1)),
High::from(get_cents(2)),
Low::from(get_cents(3)),
Close::from(get_cents(4)),
Open::new(get_cents(1)),
High::new(get_cents(2)),
Low::new(get_cents(3)),
Close::new(get_cents(4)),
)),
))
}

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