Compare commits

...

17 Commits

Author SHA1 Message Date
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
38 changed files with 3064 additions and 1803 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:
Generated
+72 -70
View File
@@ -374,7 +374,7 @@ dependencies = [
[[package]]
name = "brk"
version = "0.0.23"
version = "0.0.27"
dependencies = [
"brk_cli",
"brk_computer",
@@ -391,7 +391,7 @@ dependencies = [
[[package]]
name = "brk_cli"
version = "0.0.23"
version = "0.0.27"
dependencies = [
"brk_computer",
"brk_core",
@@ -412,7 +412,7 @@ dependencies = [
[[package]]
name = "brk_computer"
version = "0.0.23"
version = "0.0.27"
dependencies = [
"brk_core",
"brk_exit",
@@ -427,7 +427,7 @@ dependencies = [
[[package]]
name = "brk_core"
version = "0.0.23"
version = "0.0.27"
dependencies = [
"bitcoin",
"bitcoincore-rpc",
@@ -444,7 +444,7 @@ dependencies = [
[[package]]
name = "brk_exit"
version = "0.0.23"
version = "0.0.27"
dependencies = [
"brk_logger",
"ctrlc",
@@ -453,7 +453,7 @@ dependencies = [
[[package]]
name = "brk_fetcher"
version = "0.0.23"
version = "0.0.27"
dependencies = [
"brk_core",
"brk_logger",
@@ -466,7 +466,7 @@ dependencies = [
[[package]]
name = "brk_indexer"
version = "0.0.23"
version = "0.0.27"
dependencies = [
"bitcoin",
"bitcoincore-rpc",
@@ -485,7 +485,7 @@ dependencies = [
[[package]]
name = "brk_logger"
version = "0.0.23"
version = "0.0.27"
dependencies = [
"color-eyre",
"env_logger",
@@ -495,7 +495,7 @@ dependencies = [
[[package]]
name = "brk_parser"
version = "0.0.23"
version = "0.0.27"
dependencies = [
"bitcoin",
"bitcoincore-rpc",
@@ -510,7 +510,7 @@ dependencies = [
[[package]]
name = "brk_query"
version = "0.0.23"
version = "0.0.27"
dependencies = [
"brk_computer",
"brk_indexer",
@@ -526,7 +526,7 @@ dependencies = [
[[package]]
name = "brk_server"
version = "0.0.23"
version = "0.0.27"
dependencies = [
"axum",
"brk_computer",
@@ -552,7 +552,7 @@ dependencies = [
[[package]]
name = "brk_vec"
version = "0.0.23"
version = "0.0.27"
dependencies = [
"arc-swap",
"axum",
@@ -577,9 +577,9 @@ dependencies = [
[[package]]
name = "brotli-decompressor"
version = "4.0.2"
version = "4.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37"
checksum = "a334ef7c9e23abf0ce748e8cd309037da93e606ad52eb372e4ce327a0dcfbdfd"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
@@ -1138,6 +1138,12 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foldhash"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "form_urlencoded"
version = "1.2.1"
@@ -1252,6 +1258,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
dependencies = [
"allocator-api2",
"equivalent",
"foldhash",
]
[[package]]
@@ -1549,9 +1557,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.171"
version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]]
name = "linux-raw-sys"
@@ -1569,12 +1577,6 @@ dependencies = [
"scopeguard",
]
[[package]]
name = "lockfree-object-pool"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e"
[[package]]
name = "log"
version = "0.4.27"
@@ -1789,9 +1791,9 @@ checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564"
[[package]]
name = "oxc"
version = "0.63.0"
version = "0.64.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa680279066565502d5cc612d82dc2841499518f5430d047aff33869ec5592a5"
checksum = "548086420c5c78546c7417384689af59ed11dbe9462e8bfef42636be0f545b96"
dependencies = [
"oxc_allocator",
"oxc_ast",
@@ -1832,9 +1834,9 @@ dependencies = [
[[package]]
name = "oxc_allocator"
version = "0.63.0"
version = "0.64.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f90c485c4f2781e0c8b4703a5fa205f49ecc6d496d2b88260db27d60f9f1661"
checksum = "acaf33eacde1fca8fdb26655d7486842a8106916bc3855265607db2b4a4eaec4"
dependencies = [
"allocator-api2",
"bumpalo",
@@ -1846,9 +1848,9 @@ dependencies = [
[[package]]
name = "oxc_ast"
version = "0.63.0"
version = "0.64.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2552b2248c0d320c97f865d0620946821e687a0c02200cc6aa08161862447f8d"
checksum = "3044daf0f6b02f27330954141d799f9206e04b9175a3f4fa199f78c5ef46b2b4"
dependencies = [
"bitflags",
"cow-utils",
@@ -1863,9 +1865,9 @@ dependencies = [
[[package]]
name = "oxc_ast_macros"
version = "0.63.0"
version = "0.64.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccd0b70b7752610fc00a22e3cbf92fa2b0a007b022a976fba75a254f6ea21f18"
checksum = "7ee5d1546ecb309530b30b48f1aefefad7e6d53b8502e7b91b20d6a523af270e"
dependencies = [
"proc-macro2",
"quote",
@@ -1874,9 +1876,9 @@ dependencies = [
[[package]]
name = "oxc_ast_visit"
version = "0.63.0"
version = "0.64.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef6a46d3d3158668e5d8a9231bce6f5c8abc4a818a48583a254f4aa4a9682fa0"
checksum = "b29d0e9e05d2638317c39470b5a528e268fc088ae1e3fda26b049661f2de25ad"
dependencies = [
"oxc_allocator",
"oxc_ast",
@@ -1886,9 +1888,9 @@ dependencies = [
[[package]]
name = "oxc_cfg"
version = "0.63.0"
version = "0.64.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e0e5fa83ea1b3bbcc5496cf6acbbc46f7d147cbd342ecf968df500239c73bd"
checksum = "7b3740da43d597136474fa738bafb697c8469b8ecd9c256819ae443ec91a67aa"
dependencies = [
"bitflags",
"itertools",
@@ -1901,9 +1903,9 @@ dependencies = [
[[package]]
name = "oxc_codegen"
version = "0.63.0"
version = "0.64.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "454e75b9152f3aea41e4de64154bcb4a261a50df75746b08136b9994130f3a00"
checksum = "ee5e197f8bed070bcc6e9744a7a5f91bc4ff250543f07849567e6e602383c7db"
dependencies = [
"bitflags",
"cow-utils",
@@ -1922,15 +1924,15 @@ dependencies = [
[[package]]
name = "oxc_data_structures"
version = "0.63.0"
version = "0.64.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c77ea3b4eae572b066a314edd33ccd07e0d0b148bdea635fdd1a44ff97b1a9fb"
checksum = "9ca20f4fc9af4f462bfc6bbca60e3f4c2ca9c4f09e99363c0c85d90bb936641c"
[[package]]
name = "oxc_diagnostics"
version = "0.63.0"
version = "0.64.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5f38bf4f67832d521bcd99a79d4483e9b571d37c81e6b09a0a397b18931df8b"
checksum = "50e5ef1106d01ade76eec600e5b0da38932f555d1cb661f0d5ec7f3d717da22d"
dependencies = [
"cow-utils",
"oxc-miette",
@@ -1938,9 +1940,9 @@ dependencies = [
[[package]]
name = "oxc_ecmascript"
version = "0.63.0"
version = "0.64.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53a754f033637a086a80d7f81620ff1123f20ad70789f37873bc635ec89f0021"
checksum = "76b1ea0ef90fda6b68127181b3b136b21041a595e8c2028c4e08fcf85f99a10c"
dependencies = [
"cow-utils",
"num-bigint",
@@ -1952,9 +1954,9 @@ dependencies = [
[[package]]
name = "oxc_estree"
version = "0.63.0"
version = "0.64.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85b7edeb47c4700027cc113d22ed899df45fda2ed5b29af2e471cad2be09244d"
checksum = "6b9ce9584683d43622ef4b66bd605ce9878f3bf7468b9b59ad041f33af13c34d"
[[package]]
name = "oxc_index"
@@ -1964,9 +1966,9 @@ checksum = "2fa07b0cfa997730afed43705766ef27792873fdf5215b1391949fec678d2392"
[[package]]
name = "oxc_mangler"
version = "0.63.0"
version = "0.64.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a837c659bb2e340f491d2196d4565d8e75ffa19e7a8c6b35eeab67159cda546"
checksum = "20c80a552dc097088d466679bcaba2576bbe88a430ca9c5b0cb67e23787aaa7a"
dependencies = [
"fixedbitset",
"itertools",
@@ -1981,9 +1983,9 @@ dependencies = [
[[package]]
name = "oxc_minifier"
version = "0.63.0"
version = "0.64.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d186a202e49cebf004903e45eccecc3fc8bd10d4f6803ad73eb9eba51b4770b4"
checksum = "e5e504ac83f23ff755eae4ebd6291258b44e05cf58379e1fe1c00b1007e41f29"
dependencies = [
"cow-utils",
"oxc_allocator",
@@ -2003,9 +2005,9 @@ dependencies = [
[[package]]
name = "oxc_parser"
version = "0.63.0"
version = "0.64.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a54ce76e891cdfa2bf1b946492e94f17a5d6a5d9731e59aaa1b4ae435f8439ef"
checksum = "688491b2dfe8049a6410bc6b92f71e75bebfe9a1f352a64084a62069cd644e7f"
dependencies = [
"bitflags",
"cow-utils",
@@ -2026,9 +2028,9 @@ dependencies = [
[[package]]
name = "oxc_regular_expression"
version = "0.63.0"
version = "0.64.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d43967a36f4ce1577099e3d70927845fb9f1cbfdd57298e7fd69897c1f434d"
checksum = "3be6231edf43b8ca0fa8edad93b0b8e9067a3991ea2d8aa9f22a4c8fa464f267"
dependencies = [
"oxc_allocator",
"oxc_ast_macros",
@@ -2042,9 +2044,9 @@ dependencies = [
[[package]]
name = "oxc_semantic"
version = "0.63.0"
version = "0.64.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c8f0eb991e07aa1aab2efd85f61879452374d406145bdc6d32681ddda8d74c8"
checksum = "8f5c80c996fafc27a8444732bbba06f1de3eb488c585d65293a4b40b089ff564"
dependencies = [
"itertools",
"oxc_allocator",
@@ -2078,9 +2080,9 @@ dependencies = [
[[package]]
name = "oxc_span"
version = "0.63.0"
version = "0.64.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cdfaea137d47979b406de82e3b3c13f03b4bda4bc237c1b6fdbb8c46b436e70"
checksum = "bce0a945765d00dd9ee0bfdc38fa265008e66f919157894c0383c525d026511f"
dependencies = [
"compact_str",
"oxc-miette",
@@ -2091,9 +2093,9 @@ dependencies = [
[[package]]
name = "oxc_syntax"
version = "0.63.0"
version = "0.64.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb675497fc1051b3cec9c5cfa224ead942a830c8583394deaadcae5eb54669fa"
checksum = "12b876a00908cb1fc6648823d7d8579a69af1c5a5c6d4cf6135040e09f41d116"
dependencies = [
"bitflags",
"cow-utils",
@@ -2112,9 +2114,9 @@ dependencies = [
[[package]]
name = "oxc_traverse"
version = "0.63.0"
version = "0.64.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f89e6801eb9ef451e1c785fdee237050be91da172b9fbcad849f9703d37a8ae8"
checksum = "a9c25f3da54211abd4b6ff1390a0f28d42b2128cb33f4b38edbdc5cb71bc3d3c"
dependencies = [
"compact_str",
"itoa",
@@ -2199,12 +2201,14 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "petgraph"
version = "0.7.1"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
checksum = "7a98c6720655620a521dcc722d0ad66cd8afd5d86e34a89ef691c50b7b24de06"
dependencies = [
"fixedbitset",
"hashbrown 0.15.2",
"indexmap 2.9.0",
"serde",
]
[[package]]
@@ -2321,18 +2325,18 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.94"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quick_cache"
version = "0.6.12"
version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f8ed0655cbaf18a26966142ad23b95d8ab47221c50c4f73a1db7d0d2d6e3da8"
checksum = "287e56aac5a2b4fb25a6fb050961d157635924c8696305a5c937a76f29841a0f"
dependencies = [
"equivalent",
"hashbrown 0.15.2",
@@ -3505,15 +3509,13 @@ dependencies = [
[[package]]
name = "zopfli"
version = "0.8.1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946"
checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7"
dependencies = [
"bumpalo",
"crc32fast",
"lockfree-object-pool",
"log",
"once_cell",
"simd-adler32",
]
+9 -1
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.23"
package.version = "0.0.27"
package.repository = "https://github.com/bitcoinresearchkit/brk"
[profile.release]
@@ -60,3 +60,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" }
+88 -13
View File
@@ -6,11 +6,10 @@ use std::{
path::{Path, PathBuf},
};
use brk_core::CheckedSub;
use brk_core::{Bitcoin, CheckedSub, Close, Dollars, Height, Sats, Txindex};
use brk_exit::Exit;
use brk_vec::{
Compressed, DynamicVec, Error, GenericVec, Result, StoredIndex, StoredType, StoredVec, Value,
Version,
Compressed, DynamicVec, Error, GenericVec, Result, StoredIndex, StoredType, StoredVec, Version,
};
use log::info;
@@ -120,8 +119,12 @@ where
&mut self.inner
}
pub fn cached_get(&mut self, index: I) -> Result<Option<Value<T>>> {
self.inner.cached_get(index)
pub fn unwrap_cached_get(&mut self, index: I) -> Option<T> {
self.inner.unwrap_cached_get(index)
}
#[inline]
pub fn double_unwrap_cached_get(&mut self, index: I) -> T {
self.inner.double_unwrap_cached_get(index)
}
pub fn collect_inclusive_range(&self, from: I, to: I) -> Result<Vec<T>> {
@@ -196,7 +199,7 @@ where
.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) {
if self.unwrap_cached_get(i).is_none_or(|old_v| old_v > v) {
self.forced_push_at(i, v, exit)
} else {
Ok(())
@@ -224,7 +227,7 @@ where
let index = max_from.min(T::from(self.len()));
first_indexes.iter_from(index, |(value, first_index, ..)| {
let first_index = (first_index).to_usize()?;
let last_index = (last_indexes.cached_get(value)?.unwrap()).to_usize()?;
let last_index = (last_indexes.double_unwrap_cached_get(value)).to_usize()?;
(first_index..last_index)
.try_for_each(|index| self.forced_push_at(I::from(index), value, exit))
})?;
@@ -344,8 +347,8 @@ where
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().into_inner();
let range = first_index.to_usize().unwrap()..=last_index.to_usize().unwrap();
let last_index = last_indexes.double_unwrap_cached_get(i);
let range = first_index.unwrap_to_usize()..=last_index.unwrap_to_usize();
let count = if let Some(filter) = filter.as_mut() {
range.into_iter().filter(|i| filter(T2::from(*i))).count()
} else {
@@ -377,7 +380,7 @@ where
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),
T::from(other_to_self.double_unwrap_cached_get(other) == i),
exit,
)
})?;
@@ -403,11 +406,11 @@ where
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().into_inner();
let range = first_index.to_usize().unwrap()..=last_index.to_usize().unwrap();
let last_index = last_indexes.double_unwrap_cached_get(i);
let range = first_index.unwrap_to_usize()..=last_index.unwrap_to_usize();
let mut sum = T::from(0_usize);
range.into_iter().for_each(|i| {
sum = sum.clone() + source.cached_get_(i).unwrap().unwrap().into_inner();
sum = sum.clone() + source.double_unwrap_cached_get(T2::from(i));
});
self.forced_push_at(i, sum, exit)
})?;
@@ -416,6 +419,78 @@ where
}
}
impl<I> ComputedVec<I, Bitcoin>
where
I: StoredIndex,
{
pub fn compute_from_sats(
&mut self,
max_from: I,
sats: &mut StoredVec<I, Sats>,
exit: &Exit,
) -> Result<()> {
self.validate_computed_version_or_reset_file(
Version::ZERO + self.version() + sats.version(),
)?;
let index = max_from.min(I::from(self.len()));
sats.iter_from(index, |(i, sats, ..)| {
let (i, v) = (i, Bitcoin::from(sats));
self.forced_push_at(i, v, exit)
})?;
self.safe_flush(exit)
}
}
impl ComputedVec<Height, Dollars> {
pub fn compute_from_bitcoin(
&mut self,
max_from: Height,
bitcoin: &mut StoredVec<Height, Bitcoin>,
price: &mut StoredVec<Height, Close<Dollars>>,
exit: &Exit,
) -> Result<()> {
self.validate_computed_version_or_reset_file(
Version::ZERO + self.version() + bitcoin.version(),
)?;
let index = max_from.min(Height::from(self.len()));
bitcoin.iter_from(index, |(i, bitcoin, ..)| {
let dollars = price.double_unwrap_cached_get(i);
let (i, v) = (i, *dollars * bitcoin);
self.forced_push_at(i, v, exit)
})?;
self.safe_flush(exit)
}
}
impl ComputedVec<Txindex, Dollars> {
pub fn compute_from_bitcoin(
&mut self,
max_from: Txindex,
bitcoin: &mut StoredVec<Txindex, Bitcoin>,
i_to_height: &mut StoredVec<Txindex, Height>,
price: &mut StoredVec<Height, Close<Dollars>>,
exit: &Exit,
) -> Result<()> {
self.validate_computed_version_or_reset_file(
Version::ZERO + self.version() + bitcoin.version(),
)?;
let index = max_from.min(Txindex::from(self.len()));
bitcoin.iter_from(index, |(i, bitcoin, ..)| {
let height = i_to_height.double_unwrap_cached_get(i);
let dollars = price.double_unwrap_cached_get(height);
let (i, v) = (i, *dollars * bitcoin);
self.forced_push_at(i, v, exit)
})?;
self.safe_flush(exit)
}
}
impl<I, T> Clone for ComputedVec<I, T>
where
I: StoredIndex,
@@ -97,7 +97,7 @@ impl Vecs {
indexer.mut_vecs().height_to_timestamp.mut_vec(),
|(height, timestamp, _, height_to_timestamp)| {
let interval = height.decremented().map_or(Timestamp::ZERO, |prev_h| {
let prev_timestamp = *height_to_timestamp.cached_get(prev_h).unwrap().unwrap();
let prev_timestamp = height_to_timestamp.double_unwrap_cached_get(prev_h);
timestamp
.checked_sub(prev_timestamp)
.unwrap_or(Timestamp::ZERO)
@@ -16,20 +16,22 @@ 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>>,
first: Option<ComputedVec<I, T>>,
average: Option<ComputedVec<I, T>>,
sum: Option<ComputedVec<I, T>>,
max: Option<ComputedVec<I, T>>,
_90p: Option<ComputedVec<I, T>>,
_75p: Option<ComputedVec<I, T>>,
median: Option<ComputedVec<I, T>>,
_25p: Option<ComputedVec<I, T>>,
_10p: Option<ComputedVec<I, T>>,
min: Option<ComputedVec<I, T>>,
last: Option<ComputedVec<I, T>>,
total: Option<ComputedVec<I, T>>,
}
const VERSION: Version = Version::ZERO;
impl<I, T> ComputedVecBuilder<I, T>
where
I: StoredIndex,
@@ -38,6 +40,7 @@ where
pub fn forced_import(
path: &Path,
name: &str,
version: Version,
compressed: Compressed,
options: StorableVecGeneatorOptions,
) -> color_eyre::Result<Self> {
@@ -67,50 +70,100 @@ where
}
};
let version = VERSION + version;
let s = Self {
first: options.first.then(|| {
ComputedVec::forced_import(&maybe_prefix("first"), Version::ZERO, compressed)
.unwrap()
ComputedVec::forced_import(
&maybe_prefix("first"),
version + Version::ZERO,
compressed,
)
.unwrap()
}),
last: options.last.then(|| {
ComputedVec::forced_import(
&path.join(format!("{key}_to_{name}")),
Version::ZERO,
version + Version::ZERO,
compressed,
)
.unwrap()
}),
min: options.min.then(|| {
ComputedVec::forced_import(&maybe_suffix("min"), Version::ZERO, compressed).unwrap()
ComputedVec::forced_import(
&maybe_suffix("min"),
version + Version::ZERO,
compressed,
)
.unwrap()
}),
max: options.max.then(|| {
ComputedVec::forced_import(&maybe_suffix("max"), Version::ZERO, compressed).unwrap()
ComputedVec::forced_import(
&maybe_suffix("max"),
version + Version::ZERO,
compressed,
)
.unwrap()
}),
median: options.median.then(|| {
ComputedVec::forced_import(&maybe_suffix("median"), Version::ZERO, compressed)
.unwrap()
ComputedVec::forced_import(
&maybe_suffix("median"),
version + Version::ZERO,
compressed,
)
.unwrap()
}),
average: options.average.then(|| {
ComputedVec::forced_import(&maybe_suffix("average"), Version::ZERO, compressed)
.unwrap()
ComputedVec::forced_import(
&maybe_suffix("average"),
version + Version::ZERO,
compressed,
)
.unwrap()
}),
sum: options.sum.then(|| {
ComputedVec::forced_import(&maybe_suffix("sum"), Version::ZERO, compressed).unwrap()
ComputedVec::forced_import(
&maybe_suffix("sum"),
version + Version::ZERO,
compressed,
)
.unwrap()
}),
total: options.total.then(|| {
ComputedVec::forced_import(&prefix("total"), Version::ZERO, compressed).unwrap()
ComputedVec::forced_import(&prefix("total"), version + Version::ZERO, compressed)
.unwrap()
}),
_90p: options._90p.then(|| {
ComputedVec::forced_import(&maybe_suffix("90p"), Version::ZERO, compressed).unwrap()
ComputedVec::forced_import(
&maybe_suffix("90p"),
version + Version::ZERO,
compressed,
)
.unwrap()
}),
_75p: options._75p.then(|| {
ComputedVec::forced_import(&maybe_suffix("75p"), Version::ZERO, compressed).unwrap()
ComputedVec::forced_import(
&maybe_suffix("75p"),
version + Version::ZERO,
compressed,
)
.unwrap()
}),
_25p: options._25p.then(|| {
ComputedVec::forced_import(&maybe_suffix("25p"), Version::ZERO, compressed).unwrap()
ComputedVec::forced_import(
&maybe_suffix("25p"),
version + Version::ZERO,
compressed,
)
.unwrap()
}),
_10p: options._10p.then(|| {
ComputedVec::forced_import(&maybe_suffix("10p"), Version::ZERO, compressed).unwrap()
ComputedVec::forced_import(
&maybe_suffix("10p"),
version + Version::ZERO,
compressed,
)
.unwrap()
}),
};
@@ -128,14 +181,12 @@ where
source.iter_from(index, |(i, v, ..)| {
let prev = i
.to_usize()
.unwrap()
.unwrap_to_usize()
.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())
.unwrap_cached_get(I::from(prev_i))
.unwrap_or(T::from(0_usize))
});
let value = v.clone() + prev;
total_vec.forced_push_at(i, value, exit)?;
@@ -164,21 +215,15 @@ where
let index = self.starting_index(max_from);
first_indexes.iter_from(index, |(i, first_index, first_indexes)| {
let last_index = last_indexes.cached_get(i)?.unwrap().into_inner();
let last_index = last_indexes.double_unwrap_cached_get(i);
if let Some(first) = self.first.as_mut() {
let v = source.cached_get(first_index)?.unwrap().into_inner();
let v = source.double_unwrap_cached_get(first_index);
first.forced_push_at(index, v, exit)?;
}
if let Some(last) = self.last.as_mut() {
let v = source
.cached_get(last_index)
.inspect_err(|_| {
dbg!(last.path(), last_index);
})?
.unwrap()
.into_inner();
let v = source.double_unwrap_cached_get(last_index);
last.forced_push_at(index, v, exit)?;
}
@@ -269,17 +314,12 @@ where
}
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()
},
);
let prev = i
.unwrap_to_usize()
.checked_sub(1)
.map_or(T::from(0_usize), |prev_i| {
total_vec.double_unwrap_cached_get(I::from(prev_i))
});
total_vec.forced_push_at(i, prev + sum, exit)?;
}
}
@@ -320,17 +360,14 @@ where
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();
let last_index = last_indexes.double_unwrap_cached_get(i);
if let Some(first) = self.first.as_mut() {
let v = source
.first
.as_mut()
.unwrap()
.cached_get(first_index)
.unwrap()
.unwrap()
.into_inner();
.double_unwrap_cached_get(first_index);
first.forced_push_at(index, v, exit)?;
}
@@ -339,10 +376,7 @@ where
.last
.as_mut()
.unwrap()
.cached_get(last_index)
.unwrap()
.unwrap()
.into_inner();
.double_unwrap_cached_get(last_index);
last.forced_push_at(index, v, exit)?;
}
@@ -405,16 +439,12 @@ where
}
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()
},
);
let prev = i
.unwrap_to_usize()
.checked_sub(1)
.map_or(T::from(0_usize), |prev_i| {
total_vec.double_unwrap_cached_get(I::from(prev_i))
});
total_vec.forced_push_at(i, prev + sum, exit)?;
}
}
@@ -457,6 +487,43 @@ where
))
}
pub fn unwrap_first(&mut self) -> &mut ComputedVec<I, T> {
self.first.as_mut().unwrap()
}
pub fn unwrap_average(&mut self) -> &mut ComputedVec<I, T> {
self.average.as_mut().unwrap()
}
pub fn unwrap_sum(&mut self) -> &mut ComputedVec<I, T> {
self.sum.as_mut().unwrap()
}
pub fn unwrap_max(&mut self) -> &mut ComputedVec<I, T> {
self.max.as_mut().unwrap()
}
pub fn unwrap_90p(&mut self) -> &mut ComputedVec<I, T> {
self._90p.as_mut().unwrap()
}
pub fn unwrap_75p(&mut self) -> &mut ComputedVec<I, T> {
self._75p.as_mut().unwrap()
}
pub fn unwrap_median(&mut self) -> &mut ComputedVec<I, T> {
self.median.as_mut().unwrap()
}
pub fn unwrap_25p(&mut self) -> &mut ComputedVec<I, T> {
self._25p.as_mut().unwrap()
}
pub fn unwrap_10p(&mut self) -> &mut ComputedVec<I, T> {
self._10p.as_mut().unwrap()
}
pub fn unwrap_min(&mut self) -> &mut ComputedVec<I, T> {
self.min.as_mut().unwrap()
}
pub fn unwrap_last(&mut self) -> &mut ComputedVec<I, T> {
self.last.as_mut().unwrap()
}
pub fn unwrap_total(&mut self) -> &mut ComputedVec<I, T> {
self.total.as_mut().unwrap()
}
pub fn any_vecs(&self) -> Vec<&dyn brk_vec::AnyStoredVec> {
let mut v: Vec<&dyn brk_vec::AnyStoredVec> = vec![];
@@ -23,6 +23,8 @@ where
pub decadeindex: ComputedVecBuilder<Decadeindex, T>,
}
const VERSION: Version = Version::ZERO;
impl<T> ComputedVecsFromDateindex<T>
where
T: ComputedType + Ord + From<f64>,
@@ -35,8 +37,15 @@ where
compressed: Compressed,
options: StorableVecGeneatorOptions,
) -> color_eyre::Result<Self> {
let dateindex_extra =
ComputedVecBuilder::forced_import(path, name, compressed, options.copy_self_extra())?;
let version = VERSION + version;
let dateindex_extra = ComputedVecBuilder::forced_import(
path,
name,
version,
compressed,
options.copy_self_extra(),
)?;
let options = options.remove_percentiles();
@@ -47,11 +56,17 @@ where
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)?,
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,
)?,
})
}
@@ -28,6 +28,8 @@ where
pub decadeindex: ComputedVecBuilder<Decadeindex, T>,
}
const VERSION: Version = Version::ZERO;
impl<T> ComputedVecsFromHeight<T>
where
T: ComputedType + Ord + From<f64>,
@@ -41,15 +43,23 @@ where
compressed: Compressed,
options: StorableVecGeneatorOptions,
) -> color_eyre::Result<Self> {
let version = VERSION + version;
let height = compute_source.then(|| {
ComputedVec::forced_import(&path.join(format!("height_to_{name}")), version, compressed)
.unwrap()
});
let height_extra =
ComputedVecBuilder::forced_import(path, name, compressed, options.copy_self_extra())?;
let height_extra = ComputedVecBuilder::forced_import(
path,
name,
version,
compressed,
options.copy_self_extra(),
)?;
let dateindex = ComputedVecBuilder::forced_import(path, name, compressed, options)?;
let dateindex =
ComputedVecBuilder::forced_import(path, name, version, compressed, options)?;
let options = options.remove_percentiles();
@@ -57,13 +67,21 @@ where
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)?,
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,
)?,
})
}
@@ -20,6 +20,8 @@ where
// TODO: pub halvingepoch: StorableVecGeneator<Halvingepoch, T>,
}
const VERSION: Version = Version::ZERO;
impl<T> ComputedVecsFromHeightStrict<T>
where
T: ComputedType + Ord + From<f64>,
@@ -32,22 +34,31 @@ where
compressed: Compressed,
options: StorableVecGeneatorOptions,
) -> color_eyre::Result<Self> {
let version = VERSION + version;
let height = ComputedVec::forced_import(
&path.join(format!("height_to_{name}")),
version,
compressed,
)?;
let height_extra =
ComputedVecBuilder::forced_import(path, name, compressed, options.copy_self_extra())?;
let height_extra = ComputedVecBuilder::forced_import(
path,
name,
version,
compressed,
options.copy_self_extra(),
)?;
let options = options.remove_percentiles();
Ok(Self {
height,
height_extra,
difficultyepoch: ComputedVecBuilder::forced_import(path, name, 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)?,
})
}
@@ -29,6 +29,8 @@ where
pub decadeindex: ComputedVecBuilder<Decadeindex, T>,
}
const VERSION: Version = Version::ZERO;
impl<T> ComputedVecsFromTxindex<T>
where
T: ComputedType + Ord + From<f64>,
@@ -42,6 +44,8 @@ where
compressed: Compressed,
options: StorableVecGeneatorOptions,
) -> color_eyre::Result<Self> {
let version = VERSION + version;
let txindex = compute_source.then(|| {
ComputedVec::forced_import(
&path.join(format!("txindex_to_{name}")),
@@ -51,21 +55,29 @@ where
.unwrap()
});
let height = ComputedVecBuilder::forced_import(path, name, compressed, options)?;
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, compressed, options)?,
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)?,
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,
)?,
})
}
@@ -4,6 +4,8 @@ mod from_height;
mod from_height_strict;
mod from_txindex;
mod stored_type;
mod value_from_height;
mod value_from_txindex;
pub use builder::*;
pub use from_dateindex::*;
@@ -11,3 +13,5 @@ pub use from_height::*;
pub use from_height_strict::*;
pub use from_txindex::*;
pub use stored_type::*;
pub use value_from_height::*;
pub use value_from_txindex::*;
@@ -0,0 +1,157 @@
use std::path::Path;
use brk_core::{Bitcoin, Dollars, Height, Sats};
use brk_exit::Exit;
use brk_indexer::Indexer;
use brk_vec::{AnyStoredVec, Compressed, Result, StoredVec, Version};
use crate::storage::{
base::ComputedVec,
marketprice,
vecs::{Indexes, indexes},
};
use super::{ComputedVecsFromHeight, StorableVecGeneatorOptions};
#[derive(Clone)]
pub struct ComputedValueVecsFromHeight {
pub sats: ComputedVecsFromHeight<Sats>,
pub bitcoin: ComputedVecsFromHeight<Bitcoin>,
pub dollars: Option<ComputedVecsFromHeight<Dollars>>,
}
const VERSION: Version = Version::ONE;
impl ComputedValueVecsFromHeight {
pub fn forced_import(
path: &Path,
name: &str,
compute_source: bool,
version: Version,
compressed: Compressed,
options: StorableVecGeneatorOptions,
compute_dollars: bool,
) -> color_eyre::Result<Self> {
Ok(Self {
sats: ComputedVecsFromHeight::forced_import(
path,
name,
compute_source,
VERSION + version,
compressed,
options,
)?,
bitcoin: ComputedVecsFromHeight::forced_import(
path,
&format!("{name}_in_btc"),
true,
VERSION + version,
compressed,
options,
)?,
dollars: compute_dollars.then(|| {
ComputedVecsFromHeight::forced_import(
path,
&format!("{name}_in_usd"),
true,
VERSION + version,
compressed,
options,
)
.unwrap()
}),
})
}
pub fn compute_all<F>(
&mut self,
indexer: &mut Indexer,
indexes: &mut indexes::Vecs,
marketprices: &mut Option<&mut marketprice::Vecs>,
starting_indexes: &Indexes,
exit: &Exit,
mut compute: F,
) -> color_eyre::Result<()>
where
F: FnMut(
&mut ComputedVec<Height, Sats>,
&mut Indexer,
&mut indexes::Vecs,
&Indexes,
&Exit,
) -> Result<()>,
{
compute(
self.sats.height.as_mut().unwrap(),
indexer,
indexes,
starting_indexes,
exit,
)?;
self.compute_rest(indexer, indexes, marketprices, starting_indexes, exit, None)?;
Ok(())
}
pub fn compute_rest(
&mut self,
indexer: &mut Indexer,
indexes: &mut indexes::Vecs,
marketprices: &mut Option<&mut marketprice::Vecs>,
starting_indexes: &Indexes,
exit: &Exit,
mut height: Option<&mut StoredVec<Height, Sats>>,
) -> color_eyre::Result<()> {
if let Some(height) = height.as_mut() {
self.sats
.compute_rest(indexes, starting_indexes, exit, Some(height))?;
} else {
self.sats
.compute_rest(indexes, starting_indexes, exit, None)?;
}
let height = height.unwrap_or_else(|| self.sats.height.as_mut().unwrap().mut_vec());
self.bitcoin.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_from_sats(starting_indexes.height, height, exit)
},
)?;
let txindex = self.bitcoin.height.as_mut().unwrap().mut_vec();
let price = marketprices
.as_mut()
.unwrap()
.chainindexes_to_close
.height
.mut_vec();
if let Some(dollars) = self.dollars.as_mut() {
dollars.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_from_bitcoin(starting_indexes.height, txindex, price, exit)
},
)?;
}
Ok(())
}
pub fn any_vecs(&self) -> Vec<&dyn AnyStoredVec> {
[
self.sats.any_vecs(),
self.bitcoin.any_vecs(),
self.dollars.as_ref().map_or(vec![], |v| v.any_vecs()),
]
.concat()
}
}
@@ -0,0 +1,163 @@
use std::path::Path;
use brk_core::{Bitcoin, Dollars, Sats, Txindex};
use brk_exit::Exit;
use brk_indexer::Indexer;
use brk_vec::{AnyStoredVec, Compressed, Result, StoredVec, Version};
use crate::storage::{
base::ComputedVec,
marketprice,
vecs::{Indexes, indexes},
};
use super::{ComputedVecsFromTxindex, StorableVecGeneatorOptions};
#[derive(Clone)]
pub struct ComputedValueVecsFromTxindex {
pub sats: ComputedVecsFromTxindex<Sats>,
pub bitcoin: ComputedVecsFromTxindex<Bitcoin>,
pub dollars: Option<ComputedVecsFromTxindex<Dollars>>,
}
const VERSION: Version = Version::ONE;
impl ComputedValueVecsFromTxindex {
pub fn forced_import(
path: &Path,
name: &str,
compute_source: bool,
version: Version,
compressed: Compressed,
options: StorableVecGeneatorOptions,
compute_dollars: bool,
) -> color_eyre::Result<Self> {
Ok(Self {
sats: ComputedVecsFromTxindex::forced_import(
path,
name,
compute_source,
VERSION + version,
compressed,
options,
)?,
bitcoin: ComputedVecsFromTxindex::forced_import(
path,
&format!("{name}_in_btc"),
true,
VERSION + version,
compressed,
options,
)?,
dollars: compute_dollars.then(|| {
ComputedVecsFromTxindex::forced_import(
path,
&format!("{name}_in_usd"),
true,
VERSION + version,
compressed,
options,
)
.unwrap()
}),
})
}
pub fn compute_all<F>(
&mut self,
indexer: &mut Indexer,
indexes: &mut indexes::Vecs,
marketprices: &mut Option<&mut marketprice::Vecs>,
starting_indexes: &Indexes,
exit: &Exit,
mut compute: F,
) -> color_eyre::Result<()>
where
F: FnMut(
&mut ComputedVec<Txindex, Sats>,
&mut Indexer,
&mut indexes::Vecs,
&Indexes,
&Exit,
) -> Result<()>,
{
compute(
self.sats.txindex.as_mut().unwrap(),
indexer,
indexes,
starting_indexes,
exit,
)?;
self.compute_rest(indexer, indexes, marketprices, starting_indexes, exit, None)?;
Ok(())
}
pub fn compute_rest(
&mut self,
indexer: &mut Indexer,
indexes: &mut indexes::Vecs,
marketprices: &mut Option<&mut marketprice::Vecs>,
starting_indexes: &Indexes,
exit: &Exit,
mut txindex: Option<&mut StoredVec<Txindex, Sats>>,
) -> color_eyre::Result<()> {
if let Some(txindex) = txindex.as_mut() {
self.sats
.compute_rest(indexer, indexes, starting_indexes, exit, Some(txindex))?;
} else {
self.sats
.compute_rest(indexer, indexes, starting_indexes, exit, None)?;
}
let txindex = txindex.unwrap_or_else(|| self.sats.txindex.as_mut().unwrap().mut_vec());
self.bitcoin.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_from_sats(starting_indexes.txindex, txindex, exit)
},
)?;
let txindex = self.bitcoin.txindex.as_mut().unwrap().mut_vec();
let price = marketprices
.as_mut()
.unwrap()
.chainindexes_to_close
.height
.mut_vec();
if let Some(dollars) = self.dollars.as_mut() {
dollars.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|v, indexer, _, starting_indexes, exit| {
v.compute_from_bitcoin(
starting_indexes.txindex,
txindex,
indexer.mut_vecs().txindex_to_height.mut_vec(),
price,
exit,
)
},
)?;
}
Ok(())
}
pub fn any_vecs(&self) -> Vec<&dyn AnyStoredVec> {
[
self.sats.any_vecs(),
self.bitcoin.any_vecs(),
self.dollars.as_ref().map_or(vec![], |v| v.any_vecs()),
]
.concat()
}
}
+26 -60
View File
@@ -343,12 +343,8 @@ impl Vecs {
|(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 }
});
.and_then(|h| s.unwrap_cached_get(h))
.map_or(d, |prev_d| prev_d.max(d));
(h, d)
},
exit,
@@ -365,8 +361,8 @@ impl Vecs {
let starting_dateindex = self
.height_to_dateindex
.cached_get(decremented_starting_height)?
.map_or_else(Default::default, |v| v.into_inner());
.unwrap_cached_get(decremented_starting_height)
.unwrap_or_default();
self.height_to_dateindex.compute_transform(
starting_indexes.height,
@@ -377,8 +373,7 @@ impl Vecs {
let starting_dateindex = if let Some(dateindex) = self
.height_to_dateindex
.cached_get(decremented_starting_height)?
.map(|v| v.into_inner())
.unwrap_cached_get(decremented_starting_height)
{
starting_dateindex.min(dateindex)
} else {
@@ -450,8 +445,8 @@ impl Vecs {
let starting_weekindex = self
.dateindex_to_weekindex
.cached_get(starting_dateindex)?
.map_or_else(Default::default, |v| v.into_inner());
.unwrap_cached_get(starting_dateindex)
.unwrap_or_default();
self.dateindex_to_weekindex.compute_transform(
starting_dateindex,
@@ -485,12 +480,7 @@ impl Vecs {
self.weekindex_to_timestamp.compute_transform(
starting_weekindex,
self.weekindex_to_first_dateindex.mut_vec(),
|(i, d, ..)| {
(
i,
*self.dateindex_to_timestamp.cached_get(d).unwrap().unwrap(),
)
},
|(i, d, ..)| (i, self.dateindex_to_timestamp.double_unwrap_cached_get(d)),
exit,
)?;
@@ -498,8 +488,8 @@ impl Vecs {
let starting_monthindex = self
.dateindex_to_monthindex
.cached_get(starting_dateindex)?
.map_or_else(Default::default, |v| v.into_inner());
.unwrap_cached_get(starting_dateindex)
.unwrap_or_default();
self.dateindex_to_monthindex.compute_transform(
starting_dateindex,
@@ -535,12 +525,7 @@ impl Vecs {
self.monthindex_to_timestamp.compute_transform(
starting_monthindex,
self.monthindex_to_first_dateindex.mut_vec(),
|(i, d, ..)| {
(
i,
*self.dateindex_to_timestamp.cached_get(d).unwrap().unwrap(),
)
},
|(i, d, ..)| (i, self.dateindex_to_timestamp.double_unwrap_cached_get(d)),
exit,
)?;
@@ -548,8 +533,8 @@ impl Vecs {
let starting_quarterindex = self
.monthindex_to_quarterindex
.cached_get(starting_monthindex)?
.map_or_else(Default::default, |v| v.into_inner());
.unwrap_cached_get(starting_monthindex)
.unwrap_or_default();
self.monthindex_to_quarterindex.compute_transform(
starting_monthindex,
@@ -585,12 +570,7 @@ impl Vecs {
self.quarterindex_to_timestamp.compute_transform(
starting_quarterindex,
self.quarterindex_to_first_monthindex.mut_vec(),
|(i, m, ..)| {
(
i,
*self.monthindex_to_timestamp.cached_get(m).unwrap().unwrap(),
)
},
|(i, m, ..)| (i, self.monthindex_to_timestamp.double_unwrap_cached_get(m)),
exit,
)?;
@@ -598,8 +578,8 @@ impl Vecs {
let starting_yearindex = self
.monthindex_to_yearindex
.cached_get(starting_monthindex)?
.map_or_else(Default::default, |v| v.into_inner());
.unwrap_cached_get(starting_monthindex)
.unwrap_or_default();
self.monthindex_to_yearindex.compute_transform(
starting_monthindex,
@@ -635,12 +615,7 @@ impl Vecs {
self.yearindex_to_timestamp.compute_transform(
starting_yearindex,
self.yearindex_to_first_monthindex.mut_vec(),
|(i, m, ..)| {
(
i,
*self.monthindex_to_timestamp.cached_get(m).unwrap().unwrap(),
)
},
|(i, m, ..)| (i, self.monthindex_to_timestamp.double_unwrap_cached_get(m)),
exit,
)?;
@@ -648,8 +623,8 @@ impl Vecs {
let starting_decadeindex = self
.yearindex_to_decadeindex
.cached_get(starting_yearindex)?
.map_or_else(Default::default, |v| v.into_inner());
.unwrap_cached_get(starting_yearindex)
.unwrap_or_default();
self.yearindex_to_decadeindex.compute_transform(
starting_yearindex,
@@ -683,12 +658,7 @@ impl Vecs {
self.decadeindex_to_timestamp.compute_transform(
starting_decadeindex,
self.decadeindex_to_first_yearindex.mut_vec(),
|(i, y, ..)| {
(
i,
*self.yearindex_to_timestamp.cached_get(y).unwrap().unwrap(),
)
},
|(i, y, ..)| (i, self.yearindex_to_timestamp.double_unwrap_cached_get(y)),
exit,
)?;
@@ -696,8 +666,8 @@ impl Vecs {
let starting_difficultyepoch = self
.height_to_difficultyepoch
.cached_get(decremented_starting_height)?
.map_or_else(Default::default, |v| v.into_inner());
.unwrap_cached_get(decremented_starting_height)
.unwrap_or_default();
self.height_to_difficultyepoch.compute_transform(
starting_indexes.height,
@@ -734,11 +704,7 @@ impl Vecs {
|(i, h, ..)| {
(
i,
*indexer_vecs
.height_to_timestamp
.cached_get(h)
.unwrap()
.unwrap(),
indexer_vecs.height_to_timestamp.double_unwrap_cached_get(h),
)
},
exit,
@@ -748,8 +714,8 @@ impl Vecs {
let starting_halvingepoch = self
.height_to_halvingepoch
.cached_get(decremented_starting_height)?
.map_or_else(Default::default, |v| v.into_inner());
.unwrap_cached_get(decremented_starting_height)
.unwrap_or_default();
self.height_to_halvingepoch.compute_transform(
starting_indexes.height,
@@ -786,7 +752,7 @@ impl Vecs {
// |(i, h, ..)| {
// (
// i,
// *indexer_vecs.height_to_timestamp.cached_get(h).unwrap().unwrap(),
// *indexer_vecs.height_to_timestamp.unwraped_cached_get(h).unwrap().unwrap(),
// )
// },
// exit,
@@ -2,7 +2,7 @@ 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,
OHLCCents, OHLCDollars, OHLCSats, Open, Quarterindex, Sats, Weekindex, Yearindex,
};
use brk_exit::Exit;
use brk_fetcher::Fetcher;
@@ -23,31 +23,46 @@ pub struct Vecs {
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_sats: ComputedVec<Dateindex, OHLCSats>,
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_sats: ComputedVec<Height, OHLCSats>,
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 timeindexes_to_open_in_sats: ComputedVecsFromDateindex<Open<Sats>>,
pub timeindexes_to_high_in_sats: ComputedVecsFromDateindex<High<Sats>>,
pub timeindexes_to_low_in_sats: ComputedVecsFromDateindex<Low<Sats>>,
pub timeindexes_to_close_in_sats: 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 chainindexes_to_open_in_sats: ComputedVecsFromHeightStrict<Open<Sats>>,
pub chainindexes_to_high_in_sats: ComputedVecsFromHeightStrict<High<Sats>>,
pub chainindexes_to_low_in_sats: ComputedVecsFromHeightStrict<Low<Sats>>,
pub chainindexes_to_close_in_sats: ComputedVecsFromHeightStrict<Close<Sats>>,
pub weekindex_to_ohlc: ComputedVec<Weekindex, OHLCDollars>,
pub weekindex_to_ohlc_in_sats: ComputedVec<Weekindex, OHLCSats>,
pub difficultyepoch_to_ohlc: ComputedVec<Difficultyepoch, OHLCDollars>,
pub difficultyepoch_to_ohlc_in_sats: ComputedVec<Difficultyepoch, OHLCSats>,
pub monthindex_to_ohlc: ComputedVec<Monthindex, OHLCDollars>,
pub monthindex_to_ohlc_in_sats: ComputedVec<Monthindex, OHLCSats>,
pub quarterindex_to_ohlc: ComputedVec<Quarterindex, OHLCDollars>,
pub quarterindex_to_ohlc_in_sats: ComputedVec<Quarterindex, OHLCSats>,
pub yearindex_to_ohlc: ComputedVec<Yearindex, OHLCDollars>,
pub yearindex_to_ohlc_in_sats: ComputedVec<Yearindex, OHLCSats>,
// pub halvingepoch_to_ohlc: StorableVec<Halvingepoch, OHLCDollars>,
// pub halvingepoch_to_ohlc_in_sats: StorableVec<Halvingepoch, OHLCSats>,
pub decadeindex_to_ohlc: ComputedVec<Decadeindex, OHLCDollars>,
pub decadeindex_to_ohlc_in_sats: ComputedVec<Decadeindex, OHLCSats>,
}
impl Vecs {
@@ -70,6 +85,11 @@ impl Vecs {
Version::ZERO,
compressed,
)?,
dateindex_to_ohlc_in_sats: ComputedVec::forced_import(
&path.join("dateindex_to_ohlc_in_sats"),
Version::ZERO,
compressed,
)?,
dateindex_to_close_in_cents: ComputedVec::forced_import(
&path.join("dateindex_to_close_in_cents"),
Version::ZERO,
@@ -100,6 +120,11 @@ impl Vecs {
Version::ZERO,
compressed,
)?,
height_to_ohlc_in_sats: ComputedVec::forced_import(
&path.join("height_to_ohlc_in_sats"),
Version::ZERO,
compressed,
)?,
height_to_close_in_cents: ComputedVec::forced_import(
&path.join("height_to_close_in_cents"),
Version::ZERO,
@@ -148,9 +173,30 @@ impl Vecs {
compressed,
StorableVecGeneatorOptions::default().add_last(),
)?,
timeindexes_to_sats_per_dollar: ComputedVecsFromDateindex::forced_import(
timeindexes_to_open_in_sats: ComputedVecsFromDateindex::forced_import(
path,
"sats_per_dollar",
"open_in_sats",
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_first(),
)?,
timeindexes_to_high_in_sats: ComputedVecsFromDateindex::forced_import(
path,
"high_in_sats",
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_max(),
)?,
timeindexes_to_low_in_sats: ComputedVecsFromDateindex::forced_import(
path,
"low_in_sats",
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_min(),
)?,
timeindexes_to_close_in_sats: ComputedVecsFromDateindex::forced_import(
path,
"close_in_sats",
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_last(),
@@ -183,9 +229,30 @@ impl Vecs {
compressed,
StorableVecGeneatorOptions::default().add_last(),
)?,
chainindexes_to_sats_per_dollar: ComputedVecsFromHeightStrict::forced_import(
chainindexes_to_open_in_sats: ComputedVecsFromHeightStrict::forced_import(
path,
"sats_per_dollar",
"open_in_sats",
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_first(),
)?,
chainindexes_to_high_in_sats: ComputedVecsFromHeightStrict::forced_import(
path,
"high_in_sats",
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_max(),
)?,
chainindexes_to_low_in_sats: ComputedVecsFromHeightStrict::forced_import(
path,
"low_in_sats",
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_min(),
)?,
chainindexes_to_close_in_sats: ComputedVecsFromHeightStrict::forced_import(
path,
"close_in_sats",
Version::ZERO,
compressed,
StorableVecGeneatorOptions::default().add_last(),
@@ -195,32 +262,62 @@ impl Vecs {
Version::ZERO,
compressed,
)?,
weekindex_to_ohlc_in_sats: ComputedVec::forced_import(
&path.join("weekindex_to_ohlc_in_sats"),
Version::ZERO,
compressed,
)?,
difficultyepoch_to_ohlc: ComputedVec::forced_import(
&path.join("difficultyepoch_to_ohlc"),
Version::ZERO,
compressed,
)?,
difficultyepoch_to_ohlc_in_sats: ComputedVec::forced_import(
&path.join("difficultyepoch_to_ohlc_in_sats"),
Version::ZERO,
compressed,
)?,
monthindex_to_ohlc: ComputedVec::forced_import(
&path.join("monthindex_to_ohlc"),
Version::ZERO,
compressed,
)?,
monthindex_to_ohlc_in_sats: ComputedVec::forced_import(
&path.join("monthindex_to_ohlc_in_sats"),
Version::ZERO,
compressed,
)?,
quarterindex_to_ohlc: ComputedVec::forced_import(
&path.join("quarterindex_to_ohlc"),
Version::ZERO,
compressed,
)?,
quarterindex_to_ohlc_in_sats: ComputedVec::forced_import(
&path.join("quarterindex_to_ohlc_in_sats"),
Version::ZERO,
compressed,
)?,
yearindex_to_ohlc: ComputedVec::forced_import(
&path.join("yearindex_to_ohlc"),
Version::ZERO,
compressed,
)?,
yearindex_to_ohlc_in_sats: ComputedVec::forced_import(
&path.join("yearindex_to_ohlc_in_sats"),
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,
)?,
decadeindex_to_ohlc_in_sats: ComputedVec::forced_import(
&path.join("decadeindex_to_ohlc_in_sats"),
Version::ZERO,
compressed,
)?,
})
}
@@ -242,9 +339,8 @@ impl Vecs {
.get_height(
h,
t,
h.decremented().map(|prev_h| {
*height_to_timestamp.cached_get(prev_h).unwrap().unwrap()
}),
h.decremented()
.map(|prev_h| height_to_timestamp.double_unwrap_cached_get(prev_h)),
)
.unwrap();
(h, ohlc)
@@ -454,43 +550,26 @@ impl Vecs {
self.weekindex_to_ohlc.compute_transform(
starting_indexes.weekindex,
self.timeindexes_to_close
.weekindex
.last
.as_mut()
.unwrap()
.mut_vec(),
self.timeindexes_to_close.weekindex.unwrap_last().mut_vec(),
|(i, close, ..)| {
(
i,
OHLCDollars {
open: *self
open: self
.timeindexes_to_open
.weekindex
.first
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
high: *self
.unwrap_first()
.double_unwrap_cached_get(i),
high: self
.timeindexes_to_high
.weekindex
.max
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
low: *self
.unwrap_max()
.double_unwrap_cached_get(i),
low: self
.timeindexes_to_low
.weekindex
.min
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
.unwrap_min()
.double_unwrap_cached_get(i),
close,
},
)
@@ -502,41 +581,27 @@ impl Vecs {
starting_indexes.difficultyepoch,
self.chainindexes_to_close
.difficultyepoch
.last
.as_mut()
.unwrap()
.unwrap_last()
.mut_vec(),
|(i, close, ..)| {
(
i,
OHLCDollars {
open: *self
open: self
.chainindexes_to_open
.difficultyepoch
.first
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
high: *self
.unwrap_first()
.double_unwrap_cached_get(i),
high: self
.chainindexes_to_high
.difficultyepoch
.max
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
low: *self
.unwrap_max()
.double_unwrap_cached_get(i),
low: self
.chainindexes_to_low
.difficultyepoch
.min
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
.unwrap_min()
.double_unwrap_cached_get(i),
close,
},
)
@@ -546,43 +611,26 @@ impl Vecs {
self.monthindex_to_ohlc.compute_transform(
starting_indexes.monthindex,
self.timeindexes_to_close
.monthindex
.last
.as_mut()
.unwrap()
.mut_vec(),
self.timeindexes_to_close.monthindex.unwrap_last().mut_vec(),
|(i, close, ..)| {
(
i,
OHLCDollars {
open: *self
open: self
.timeindexes_to_open
.monthindex
.first
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
high: *self
.unwrap_first()
.double_unwrap_cached_get(i),
high: self
.timeindexes_to_high
.monthindex
.max
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
low: *self
.unwrap_max()
.double_unwrap_cached_get(i),
low: self
.timeindexes_to_low
.monthindex
.min
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
.unwrap_min()
.double_unwrap_cached_get(i),
close,
},
)
@@ -594,41 +642,27 @@ impl Vecs {
starting_indexes.quarterindex,
self.timeindexes_to_close
.quarterindex
.last
.as_mut()
.unwrap()
.unwrap_last()
.mut_vec(),
|(i, close, ..)| {
(
i,
OHLCDollars {
open: *self
open: self
.timeindexes_to_open
.quarterindex
.first
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
high: *self
.unwrap_first()
.double_unwrap_cached_get(i),
high: self
.timeindexes_to_high
.quarterindex
.max
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
low: *self
.unwrap_max()
.double_unwrap_cached_get(i),
low: self
.timeindexes_to_low
.quarterindex
.min
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
.unwrap_min()
.double_unwrap_cached_get(i),
close,
},
)
@@ -638,43 +672,26 @@ impl Vecs {
self.yearindex_to_ohlc.compute_transform(
starting_indexes.yearindex,
self.timeindexes_to_close
.yearindex
.last
.as_mut()
.unwrap()
.mut_vec(),
self.timeindexes_to_close.yearindex.unwrap_last().mut_vec(),
|(i, close, ..)| {
(
i,
OHLCDollars {
open: *self
open: self
.timeindexes_to_open
.yearindex
.first
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
high: *self
.unwrap_first()
.double_unwrap_cached_get(i),
high: self
.timeindexes_to_high
.yearindex
.max
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
low: *self
.unwrap_max()
.double_unwrap_cached_get(i),
low: self
.timeindexes_to_low
.yearindex
.min
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
.unwrap_min()
.double_unwrap_cached_get(i),
close,
},
)
@@ -689,42 +706,27 @@ impl Vecs {
starting_indexes.decadeindex,
self.timeindexes_to_close
.decadeindex
.last
.as_mut()
.as_mut()
.unwrap()
.unwrap_last()
.mut_vec(),
|(i, close, ..)| {
(
i,
OHLCDollars {
open: *self
open: self
.timeindexes_to_open
.decadeindex
.first
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
high: *self
.unwrap_first()
.double_unwrap_cached_get(i),
high: self
.timeindexes_to_high
.decadeindex
.max
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
low: *self
.unwrap_max()
.double_unwrap_cached_get(i),
low: self
.timeindexes_to_low
.decadeindex
.min
.as_mut()
.unwrap()
.cached_get(i)
.unwrap()
.unwrap(),
.unwrap_min()
.double_unwrap_cached_get(i),
close,
},
)
@@ -732,7 +734,52 @@ impl Vecs {
exit,
)?;
self.chainindexes_to_sats_per_dollar.compute(
self.chainindexes_to_open_in_sats.compute(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_transform(
starting_indexes.height,
self.chainindexes_to_open.height.mut_vec(),
|(i, open, ..)| (i, Open::new(Sats::ONE_BTC / *open)),
exit,
)
},
)?;
self.chainindexes_to_high_in_sats.compute(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_transform(
starting_indexes.height,
self.chainindexes_to_low.height.mut_vec(),
|(i, low, ..)| (i, High::new(Sats::ONE_BTC / *low)),
exit,
)
},
)?;
self.chainindexes_to_low_in_sats.compute(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_transform(
starting_indexes.height,
self.chainindexes_to_high.height.mut_vec(),
|(i, high, ..)| (i, Low::new(Sats::ONE_BTC / *high)),
exit,
)
},
)?;
self.chainindexes_to_close_in_sats.compute(
indexer,
indexes,
starting_indexes,
@@ -741,13 +788,58 @@ impl Vecs {
v.compute_transform(
starting_indexes.height,
self.chainindexes_to_close.height.mut_vec(),
|(i, close, ..)| (i, Close::from(Sats::ONE_BTC / *close)),
|(i, close, ..)| (i, Close::new(Sats::ONE_BTC / *close)),
exit,
)
},
)?;
self.timeindexes_to_sats_per_dollar.compute(
self.timeindexes_to_open_in_sats.compute(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_transform(
starting_indexes.dateindex,
self.timeindexes_to_open.dateindex.mut_vec(),
|(i, open, ..)| (i, Open::new(Sats::ONE_BTC / *open)),
exit,
)
},
)?;
self.timeindexes_to_high_in_sats.compute(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_transform(
starting_indexes.dateindex,
self.timeindexes_to_low.dateindex.mut_vec(),
|(i, low, ..)| (i, High::new(Sats::ONE_BTC / *low)),
exit,
)
},
)?;
self.timeindexes_to_low_in_sats.compute(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_transform(
starting_indexes.dateindex,
self.timeindexes_to_high.dateindex.mut_vec(),
|(i, high, ..)| (i, Low::new(Sats::ONE_BTC / *high)),
exit,
)
},
)?;
self.timeindexes_to_close_in_sats.compute(
indexer,
indexes,
starting_indexes,
@@ -756,12 +848,259 @@ impl Vecs {
v.compute_transform(
starting_indexes.dateindex,
self.timeindexes_to_close.dateindex.mut_vec(),
|(i, close, ..)| (i, Close::from(Sats::ONE_BTC / *close)),
|(i, close, ..)| (i, Close::new(Sats::ONE_BTC / *close)),
exit,
)
},
)?;
self.height_to_ohlc_in_sats.compute_transform(
starting_indexes.height,
self.chainindexes_to_close_in_sats.height.mut_vec(),
|(i, close, ..)| {
(
i,
OHLCSats {
open: self
.chainindexes_to_open_in_sats
.height
.double_unwrap_cached_get(i),
high: self
.chainindexes_to_high_in_sats
.height
.double_unwrap_cached_get(i),
low: self
.chainindexes_to_low_in_sats
.height
.double_unwrap_cached_get(i),
close,
},
)
},
exit,
)?;
self.dateindex_to_ohlc_in_sats.compute_transform(
starting_indexes.dateindex,
self.timeindexes_to_close_in_sats.dateindex.mut_vec(),
|(i, close, ..)| {
(
i,
OHLCSats {
open: self
.timeindexes_to_open_in_sats
.dateindex
.double_unwrap_cached_get(i),
high: self
.timeindexes_to_high_in_sats
.dateindex
.double_unwrap_cached_get(i),
low: self
.timeindexes_to_low_in_sats
.dateindex
.double_unwrap_cached_get(i),
close,
},
)
},
exit,
)?;
self.weekindex_to_ohlc_in_sats.compute_transform(
starting_indexes.weekindex,
self.timeindexes_to_close_in_sats
.weekindex
.unwrap_last()
.mut_vec(),
|(i, close, ..)| {
(
i,
OHLCSats {
open: self
.timeindexes_to_open_in_sats
.weekindex
.unwrap_first()
.double_unwrap_cached_get(i),
high: self
.timeindexes_to_high_in_sats
.weekindex
.unwrap_max()
.double_unwrap_cached_get(i),
low: self
.timeindexes_to_low_in_sats
.weekindex
.unwrap_min()
.double_unwrap_cached_get(i),
close,
},
)
},
exit,
)?;
self.difficultyepoch_to_ohlc_in_sats.compute_transform(
starting_indexes.difficultyepoch,
self.chainindexes_to_close_in_sats
.difficultyepoch
.unwrap_last()
.mut_vec(),
|(i, close, ..)| {
(
i,
OHLCSats {
open: self
.chainindexes_to_open_in_sats
.difficultyepoch
.unwrap_first()
.double_unwrap_cached_get(i),
high: self
.chainindexes_to_high_in_sats
.difficultyepoch
.unwrap_max()
.double_unwrap_cached_get(i),
low: self
.chainindexes_to_low_in_sats
.difficultyepoch
.unwrap_min()
.double_unwrap_cached_get(i),
close,
},
)
},
exit,
)?;
self.monthindex_to_ohlc_in_sats.compute_transform(
starting_indexes.monthindex,
self.timeindexes_to_close_in_sats
.monthindex
.unwrap_last()
.mut_vec(),
|(i, close, ..)| {
(
i,
OHLCSats {
open: self
.timeindexes_to_open_in_sats
.monthindex
.unwrap_first()
.double_unwrap_cached_get(i),
high: self
.timeindexes_to_high_in_sats
.monthindex
.unwrap_max()
.double_unwrap_cached_get(i),
low: self
.timeindexes_to_low_in_sats
.monthindex
.unwrap_min()
.double_unwrap_cached_get(i),
close,
},
)
},
exit,
)?;
self.quarterindex_to_ohlc_in_sats.compute_transform(
starting_indexes.quarterindex,
self.timeindexes_to_close_in_sats
.quarterindex
.unwrap_last()
.mut_vec(),
|(i, close, ..)| {
(
i,
OHLCSats {
open: self
.timeindexes_to_open_in_sats
.quarterindex
.unwrap_first()
.double_unwrap_cached_get(i),
high: self
.timeindexes_to_high_in_sats
.quarterindex
.unwrap_max()
.double_unwrap_cached_get(i),
low: self
.timeindexes_to_low_in_sats
.quarterindex
.unwrap_min()
.double_unwrap_cached_get(i),
close,
},
)
},
exit,
)?;
self.yearindex_to_ohlc_in_sats.compute_transform(
starting_indexes.yearindex,
self.timeindexes_to_close_in_sats
.yearindex
.unwrap_last()
.mut_vec(),
|(i, close, ..)| {
(
i,
OHLCSats {
open: self
.timeindexes_to_open_in_sats
.yearindex
.unwrap_first()
.double_unwrap_cached_get(i),
high: self
.timeindexes_to_high_in_sats
.yearindex
.unwrap_max()
.double_unwrap_cached_get(i),
low: self
.timeindexes_to_low_in_sats
.yearindex
.unwrap_min()
.double_unwrap_cached_get(i),
close,
},
)
},
exit,
)?;
// self.halvingepoch_to_ohlc
// _in_sats.compute_transform(starting_indexes.halvingepoch, other, t, exit)?;
self.decadeindex_to_ohlc_in_sats.compute_transform(
starting_indexes.decadeindex,
self.timeindexes_to_close_in_sats
.decadeindex
.unwrap_last()
.mut_vec(),
|(i, close, ..)| {
(
i,
OHLCSats {
open: self
.timeindexes_to_open_in_sats
.decadeindex
.unwrap_first()
.double_unwrap_cached_get(i),
high: self
.timeindexes_to_high_in_sats
.decadeindex
.unwrap_max()
.double_unwrap_cached_get(i),
low: self
.timeindexes_to_low_in_sats
.decadeindex
.unwrap_min()
.double_unwrap_cached_get(i),
close,
},
)
},
exit,
)?;
Ok(())
}
@@ -787,9 +1126,16 @@ impl Vecs {
self.yearindex_to_ohlc.any_vec(),
// self.halvingepoch_to_ohlc.any_vec(),
self.decadeindex_to_ohlc.any_vec(),
self.height_to_ohlc_in_sats.any_vec(),
self.dateindex_to_ohlc_in_sats.any_vec(),
self.weekindex_to_ohlc_in_sats.any_vec(),
self.difficultyepoch_to_ohlc_in_sats.any_vec(),
self.monthindex_to_ohlc_in_sats.any_vec(),
self.quarterindex_to_ohlc_in_sats.any_vec(),
self.yearindex_to_ohlc_in_sats.any_vec(),
// self.halvingepoch_to_ohlc_in_sats.any_vec(),
self.decadeindex_to_ohlc_in_sats.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(),
@@ -798,6 +1144,14 @@ impl Vecs {
self.chainindexes_to_high.any_vecs(),
self.chainindexes_to_low.any_vecs(),
self.chainindexes_to_open.any_vecs(),
self.timeindexes_to_close_in_sats.any_vecs(),
self.timeindexes_to_high_in_sats.any_vecs(),
self.timeindexes_to_low_in_sats.any_vecs(),
self.timeindexes_to_open_in_sats.any_vecs(),
self.chainindexes_to_close_in_sats.any_vecs(),
self.chainindexes_to_high_in_sats.any_vecs(),
self.chainindexes_to_low_in_sats.any_vecs(),
self.chainindexes_to_open_in_sats.any_vecs(),
]
.concat()
}
+15 -10
View File
@@ -5,12 +5,12 @@ 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;
pub mod base;
pub mod blocks;
pub mod grouped;
pub mod indexes;
pub mod marketprice;
pub mod transactions;
use base::*;
use indexes::*;
@@ -30,7 +30,7 @@ impl Vecs {
Ok(Self {
blocks: blocks::Vecs::forced_import(path, compressed)?,
indexes: indexes::Vecs::forced_import(path, compressed)?,
transactions: transactions::Vecs::forced_import(path, compressed)?,
transactions: transactions::Vecs::forced_import(path, compressed, fetch)?,
marketprice: fetch.then(|| marketprice::Vecs::forced_import(path, compressed).unwrap()),
})
}
@@ -47,9 +47,6 @@ impl Vecs {
self.blocks
.compute(indexer, &mut self.indexes, &starting_indexes, exit)?;
self.transactions
.compute(indexer, &mut self.indexes, &starting_indexes, exit)?;
if let Some(marketprice) = self.marketprice.as_mut() {
marketprice.compute(
indexer,
@@ -60,6 +57,14 @@ impl Vecs {
)?;
}
self.transactions.compute(
indexer,
&mut self.indexes,
&starting_indexes,
&mut self.marketprice.as_mut(),
exit,
)?;
Ok(())
}
@@ -11,14 +11,17 @@ use brk_vec::{Compressed, DynamicVec, StoredIndex, Version};
use super::{
ComputedVec, Indexes,
grouped::{ComputedVecsFromHeight, ComputedVecsFromTxindex, StorableVecGeneatorOptions},
indexes,
grouped::{
ComputedValueVecsFromHeight, ComputedValueVecsFromTxindex, ComputedVecsFromHeight,
ComputedVecsFromTxindex, StorableVecGeneatorOptions,
},
indexes, marketprice,
};
#[derive(Clone)]
pub struct Vecs {
pub indexes_to_tx_count: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_fee: ComputedVecsFromTxindex<Sats>,
pub indexes_to_fee: ComputedValueVecsFromTxindex,
pub indexes_to_feerate: ComputedVecsFromTxindex<Feerate>,
pub indexes_to_input_value: ComputedVecsFromTxindex<Sats>,
pub indexes_to_output_value: ComputedVecsFromTxindex<Sats>,
@@ -37,12 +40,16 @@ pub struct Vecs {
pub txindex_to_weight: ComputedVec<Txindex, Weight>,
/// Value == 0 when Coinbase
pub txinindex_to_value: ComputedVec<Txinindex, Sats>,
pub indexes_to_subsidy: ComputedVecsFromHeight<Sats>,
pub indexes_to_coinbase: ComputedVecsFromHeight<Sats>,
pub indexes_to_subsidy: ComputedValueVecsFromHeight,
pub indexes_to_coinbase: ComputedValueVecsFromHeight,
}
impl Vecs {
pub fn forced_import(path: &Path, compressed: Compressed) -> color_eyre::Result<Self> {
pub fn forced_import(
path: &Path,
compressed: Compressed,
compute_dollars: bool,
) -> color_eyre::Result<Self> {
fs::create_dir_all(path)?;
Ok(Self {
@@ -142,7 +149,7 @@ impl Vecs {
.add_sum()
.add_total(),
)?,
indexes_to_fee: ComputedVecsFromTxindex::forced_import(
indexes_to_fee: ComputedValueVecsFromTxindex::forced_import(
path,
"fee",
true,
@@ -154,6 +161,7 @@ impl Vecs {
.add_percentiles()
.add_minmax()
.add_average(),
compute_dollars,
)?,
indexes_to_feerate: ComputedVecsFromTxindex::forced_import(
path,
@@ -198,7 +206,7 @@ impl Vecs {
.add_minmax()
.add_average(),
)?,
indexes_to_subsidy: ComputedVecsFromHeight::forced_import(
indexes_to_subsidy: ComputedValueVecsFromHeight::forced_import(
path,
"subsidy",
true,
@@ -210,8 +218,9 @@ impl Vecs {
.add_total()
.add_minmax()
.add_average(),
compute_dollars,
)?,
indexes_to_coinbase: ComputedVecsFromHeight::forced_import(
indexes_to_coinbase: ComputedValueVecsFromHeight::forced_import(
path,
"coinbase",
true,
@@ -223,6 +232,7 @@ impl Vecs {
.add_percentiles()
.add_minmax()
.add_average(),
compute_dollars,
)?,
})
}
@@ -232,6 +242,7 @@ impl Vecs {
indexer: &mut Indexer,
indexes: &mut indexes::Vecs,
starting_indexes: &Indexes,
marketprices: &mut Option<&mut marketprice::Vecs>,
exit: &Exit,
) -> color_eyre::Result<()> {
self.indexes_to_tx_count.compute_all(
@@ -295,10 +306,7 @@ impl Vecs {
|txindex| {
let v = indexer_vecs
.txindex_to_txversion
.cached_get(txindex)
.unwrap()
.unwrap()
.into_inner();
.double_unwrap_cached_get(txindex);
v == txversion
},
exit,
@@ -326,10 +334,7 @@ impl Vecs {
let total_size = indexer_vecs
.txindex_to_total_size
.mut_vec()
.cached_get(txindex)
.unwrap()
.unwrap()
.into_inner();
.double_unwrap_cached_get(txindex);
// This is the exact definition of a weight unit, as defined by BIP-141 (quote above).
let wu = base_size * 3 + total_size;
@@ -357,12 +362,12 @@ impl Vecs {
|(txinindex, txoutindex, slf, other)| {
let value = if txoutindex == Txoutindex::COINBASE {
Sats::ZERO
} else if let Ok(Some(value)) = indexer_vecs
} else if let Some(value) = indexer_vecs
.txoutindex_to_value
.mut_vec()
.cached_get(txoutindex)
.unwrap_cached_get(txoutindex)
{
*value
value
} else {
dbg!(txinindex, txoutindex, slf.len(), other.len());
panic!()
@@ -409,6 +414,7 @@ impl Vecs {
self.indexes_to_fee.compute_all(
indexer,
indexes,
marketprices,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
@@ -429,11 +435,8 @@ impl Vecs {
if input_value.is_zero() {
(txindex, input_value)
} else {
let output_value = txindex_to_output_value
.cached_get(txindex)
.unwrap()
.unwrap()
.into_inner();
let output_value =
txindex_to_output_value.double_unwrap_cached_get(txindex);
(txindex, input_value.checked_sub(output_value).unwrap())
}
},
@@ -450,15 +453,12 @@ impl Vecs {
|vec, _, _, starting_indexes, exit| {
vec.compute_transform(
starting_indexes.txindex,
self.indexes_to_fee.txindex.as_mut().unwrap().mut_vec(),
self.indexes_to_fee.sats.txindex.as_mut().unwrap().mut_vec(),
|(txindex, fee, ..)| {
let vsize = self
.txindex_to_vsize
.mut_vec()
.cached_get(txindex)
.unwrap()
.unwrap()
.into_inner();
.double_unwrap_cached_get(txindex);
(txindex, Feerate::from((fee, vsize)))
},
@@ -486,6 +486,7 @@ impl Vecs {
self.indexes_to_subsidy.compute_all(
indexer,
indexes,
marketprices,
starting_indexes,
exit,
|vec, indexer, indexes, starting_indexes, exit| {
@@ -496,29 +497,18 @@ impl Vecs {
|(height, txindex, ..)| {
let first_txoutindex = indexer_vecs
.txindex_to_first_txoutindex
.cached_get(txindex)
.unwrap()
.unwrap()
.into_inner()
.to_usize()
.unwrap();
.double_unwrap_cached_get(txindex)
.unwrap_to_usize();
let last_txoutindex = indexes
.txindex_to_last_txoutindex
.mut_vec()
.cached_get(txindex)
.unwrap()
.unwrap()
.into_inner()
.to_usize()
.unwrap();
.double_unwrap_cached_get(txindex)
.unwrap_to_usize();
let mut sats = Sats::ZERO;
(first_txoutindex..=last_txoutindex).for_each(|txoutindex| {
sats += indexer_vecs
.txoutindex_to_value
.cached_get_(txoutindex)
.unwrap()
.unwrap()
.into_inner();
.double_unwrap_cached_get(Txoutindex::from(txoutindex));
});
(height, sats)
},
@@ -530,24 +520,26 @@ impl Vecs {
self.indexes_to_coinbase.compute_all(
indexer,
indexes,
marketprices,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
vec.compute_transform(
starting_indexes.height,
self.indexes_to_subsidy.height.as_mut().unwrap().mut_vec(),
self.indexes_to_subsidy
.sats
.height
.as_mut()
.unwrap()
.mut_vec(),
|(height, subsidy, ..)| {
let fees = self
.indexes_to_fee
.sats
.height
.sum
.as_mut()
.unwrap()
.unwrap_sum()
.mut_vec()
.cached_get(height)
.unwrap()
.unwrap()
.into_inner();
.double_unwrap_cached_get(height);
(height, subsidy.checked_sub(fees).unwrap())
},
exit,
+46 -2
View File
@@ -1,10 +1,32 @@
use std::ops::Mul;
use std::ops::{Add, Div, Mul};
use serde::Serialize;
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
use super::Sats;
#[derive(Debug, Default, Clone, Copy)]
#[derive(
Debug,
Default,
Clone,
Copy,
PartialEq,
PartialOrd,
FromBytes,
Immutable,
IntoBytes,
KnownLayout,
Serialize,
)]
pub struct Bitcoin(f64);
impl Add for Bitcoin {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0)
}
}
impl Mul for Bitcoin {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
@@ -12,6 +34,13 @@ impl Mul for Bitcoin {
}
}
impl Div<usize> for Bitcoin {
type Output = Self;
fn div(self, rhs: usize) -> Self::Output {
Self(self.0 / rhs as f64)
}
}
impl From<Sats> for Bitcoin {
fn from(value: Sats) -> Self {
Self(u64::from(value) as f64 / (u64::from(Sats::ONE_BTC) as f64))
@@ -29,3 +58,18 @@ impl From<Bitcoin> for f64 {
value.0
}
}
impl From<usize> for Bitcoin {
fn from(value: usize) -> Self {
Self(value as f64)
}
}
impl Eq for Bitcoin {}
#[allow(clippy::derive_ord_xor_partial_ord)]
impl Ord for Bitcoin {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0.partial_cmp(&other.0).unwrap()
}
}
+13 -1
View File
@@ -22,7 +22,7 @@ pub struct Cents(u64);
impl From<Dollars> for Cents {
fn from(value: Dollars) -> Self {
Self((*value * 100.0).floor() as u64)
Self((*value * 100.0).round() as u64)
}
}
@@ -31,3 +31,15 @@ impl From<Cents> for f64 {
value.0 as f64
}
}
impl From<u64> for Cents {
fn from(value: u64) -> Self {
Self(value)
}
}
impl From<Cents> for u64 {
fn from(value: Cents) -> Self {
value.0
}
}
+11 -2
View File
@@ -1,10 +1,10 @@
use std::ops::{Add, Div};
use std::ops::{Add, Div, Mul};
use derive_deref::Deref;
use serde::Serialize;
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
use super::Cents;
use super::{Bitcoin, Cents, Sats};
#[derive(
Debug,
@@ -68,3 +68,12 @@ impl Ord for Dollars {
self.0.partial_cmp(&other.0).unwrap()
}
}
impl Mul<Bitcoin> for Dollars {
type Output = Dollars;
fn mul(self, rhs: Bitcoin) -> Self::Output {
Self::from(Cents::from(
u64::from(Sats::from(rhs)) * u64::from(Cents::from(self)) / u64::from(Sats::ONE_BTC),
))
}
}
+171 -98
View File
@@ -99,6 +99,51 @@ impl From<&OHLCCents> for OHLCDollars {
}
}
#[derive(Debug, Default, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
#[repr(C)]
pub struct OHLCSats {
pub open: Open<Sats>,
pub high: High<Sats>,
pub low: Low<Sats>,
pub close: Close<Sats>,
}
impl Serialize for OHLCSats {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut tup = serializer.serialize_tuple(4)?;
tup.serialize_element(&self.open)?;
tup.serialize_element(&self.high)?;
tup.serialize_element(&self.low)?;
tup.serialize_element(&self.close)?;
tup.end()
}
}
impl From<(Open<Sats>, High<Sats>, Low<Sats>, Close<Sats>)> for OHLCSats {
fn from(value: (Open<Sats>, High<Sats>, Low<Sats>, Close<Sats>)) -> Self {
Self {
open: value.0,
high: value.1,
low: value.2,
close: value.3,
}
}
}
impl From<Close<Sats>> for OHLCSats {
fn from(value: Close<Sats>) -> Self {
Self {
open: Open::from(value),
high: High::from(value),
low: Low::from(value),
close: value,
}
}
}
#[derive(
Debug,
Default,
@@ -117,12 +162,40 @@ impl From<&OHLCCents> for OHLCDollars {
)]
#[repr(C)]
pub struct Open<T>(T);
impl<T> From<T> for Open<T> {
fn from(value: T) -> Self {
impl<T> Open<T> {
pub fn new(value: T) -> Self {
Self(value)
}
}
impl<T> From<usize> for Open<T>
where
T: From<usize>,
{
fn from(value: usize) -> Self {
Self(T::from(value))
}
}
impl<T> From<f64> for Open<T>
where
T: From<f64>,
{
fn from(value: f64) -> Self {
Self(T::from(value))
}
}
impl<T> From<Open<T>> for f64
where
f64: From<T>,
{
fn from(value: Open<T>) -> Self {
Self::from(value.0)
}
}
impl<T> From<Close<T>> for Open<T>
where
T: Copy,
@@ -138,24 +211,6 @@ impl From<Open<Cents>> for Open<Dollars> {
}
}
impl From<usize> for Open<Dollars> {
fn from(value: usize) -> Self {
Self(Dollars::from(value))
}
}
impl From<f64> for Open<Dollars> {
fn from(value: f64) -> Self {
Self(Dollars::from(value))
}
}
impl From<Open<Dollars>> for f64 {
fn from(value: Open<Dollars>) -> Self {
Self::from(value.0)
}
}
impl<T> Add for Open<T>
where
T: Add<Output = T>,
@@ -194,12 +249,40 @@ where
)]
#[repr(C)]
pub struct High<T>(T);
impl<T> From<T> for High<T> {
fn from(value: T) -> Self {
impl<T> High<T> {
pub fn new(value: T) -> Self {
Self(value)
}
}
impl<T> From<usize> for High<T>
where
T: From<usize>,
{
fn from(value: usize) -> Self {
Self(T::from(value))
}
}
impl<T> From<f64> for High<T>
where
T: From<f64>,
{
fn from(value: f64) -> Self {
Self(T::from(value))
}
}
impl<T> From<High<T>> for f64
where
f64: From<T>,
{
fn from(value: High<T>) -> Self {
Self::from(value.0)
}
}
impl<T> From<Close<T>> for High<T>
where
T: Copy,
@@ -215,24 +298,6 @@ impl From<High<Cents>> for High<Dollars> {
}
}
impl From<usize> for High<Dollars> {
fn from(value: usize) -> Self {
Self(Dollars::from(value))
}
}
impl From<f64> for High<Dollars> {
fn from(value: f64) -> Self {
Self(Dollars::from(value))
}
}
impl From<High<Dollars>> for f64 {
fn from(value: High<Dollars>) -> Self {
Self::from(value.0)
}
}
impl<T> Add for High<T>
where
T: Add<Output = T>,
@@ -271,12 +336,40 @@ where
)]
#[repr(C)]
pub struct Low<T>(T);
impl<T> From<T> for Low<T> {
fn from(value: T) -> Self {
impl<T> Low<T> {
pub fn new(value: T) -> Self {
Self(value)
}
}
impl<T> From<usize> for Low<T>
where
T: From<usize>,
{
fn from(value: usize) -> Self {
Self(T::from(value))
}
}
impl<T> From<f64> for Low<T>
where
T: From<f64>,
{
fn from(value: f64) -> Self {
Self(T::from(value))
}
}
impl<T> From<Low<T>> for f64
where
f64: From<T>,
{
fn from(value: Low<T>) -> Self {
Self::from(value.0)
}
}
impl<T> From<Close<T>> for Low<T>
where
T: Copy,
@@ -292,24 +385,6 @@ impl From<Low<Cents>> for Low<Dollars> {
}
}
impl From<usize> for Low<Dollars> {
fn from(value: usize) -> Self {
Self(Dollars::from(value))
}
}
impl From<f64> for Low<Dollars> {
fn from(value: f64) -> Self {
Self(Dollars::from(value))
}
}
impl From<Low<Dollars>> for f64 {
fn from(value: Low<Dollars>) -> Self {
Self::from(value.0)
}
}
impl<T> Add for Low<T>
where
T: Add<Output = T>,
@@ -348,54 +423,52 @@ where
)]
#[repr(C)]
pub struct Close<T>(T);
impl<T> From<T> for Close<T> {
fn from(value: T) -> Self {
impl<T> Close<T> {
pub fn new(value: T) -> Self {
Self(value)
}
}
impl<T> From<usize> for Close<T>
where
T: From<usize>,
{
fn from(value: usize) -> Self {
Self(T::from(value))
}
}
impl<T> From<f64> for Close<T>
where
T: From<f64>,
{
fn from(value: f64) -> Self {
Self(T::from(value))
}
}
impl<T> From<Close<T>> for f64
where
f64: From<T>,
{
fn from(value: Close<T>) -> Self {
Self::from(value.0)
}
}
// impl<A, B> From<Close<A>> for Close<B>
// where
// B: From<A>,
// {
// fn from(value: Close<A>) -> Self {
// Self(B::from(*value))
impl From<Close<Cents>> for Close<Dollars> {
fn from(value: Close<Cents>) -> Self {
Self(Dollars::from(*value))
}
}
impl From<usize> for Close<Dollars> {
fn from(value: usize) -> Self {
Self(Dollars::from(value))
}
}
impl From<usize> for Close<Sats> {
fn from(value: usize) -> Self {
Self(Sats::from(value))
}
}
impl From<f64> for Close<Dollars> {
fn from(value: f64) -> Self {
Self(Dollars::from(value))
}
}
impl From<f64> for Close<Sats> {
fn from(value: f64) -> Self {
Self(Sats::from(value))
}
}
impl From<Close<Dollars>> for f64 {
fn from(value: Close<Dollars>) -> Self {
Self::from(value.0)
}
}
impl From<Close<Sats>> for f64 {
fn from(value: Close<Sats>) -> Self {
Self::from(value.0)
}
}
impl<T> Add for Close<T>
where
T: Add<Output = T>,
+1 -1
View File
@@ -141,7 +141,7 @@ impl From<Sats> for Amount {
impl From<Bitcoin> for Sats {
fn from(value: Bitcoin) -> Self {
Self((f64::from(value) * (u64::from(Sats::ONE_BTC) as f64)) as u64)
Self((f64::from(value) * (u64::from(Sats::ONE_BTC) as f64)).round() as u64)
}
}
+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)),
)),
))
}
+4 -4
View File
@@ -141,10 +141,10 @@ impl Kibo {
};
Ok(OHLCCents::from((
Open::from(get_value("open")?),
High::from(get_value("high")?),
Low::from(get_value("low")?),
Close::from(get_value("close")?),
Open::new(get_value("open")?),
High::new(get_value("high")?),
Low::new(get_value("low")?),
Close::new(get_value("close")?),
)))
}
}
+4 -4
View File
@@ -114,10 +114,10 @@ impl Kraken {
Ok((
timestamp,
OHLCCents::from((
Open::from(get_cents(1)),
High::from(get_cents(2)),
Low::from(get_cents(3)),
Close::from(get_cents(4)),
Open::new(get_cents(1)),
High::new(get_cents(2)),
Low::new(get_cents(3)),
Close::new(get_cents(4)),
)),
))
}
+2 -2
View File
@@ -60,9 +60,9 @@ impl Fetcher {
self.binance
.get_from_1mn(timestamp, previous_timestamp)
.unwrap_or_else(|_| {
self.kibo.get_from_height(height).unwrap_or_else(|_| {
self.kibo.get_from_height(height).unwrap_or_else(|e| {
let date = Date::from(timestamp);
eprintln!("{e}");
panic!(
"
Can't find the price for: height: {height} - date: {date}
+4 -4
View File
@@ -46,12 +46,12 @@ where
self.inner.get(index)
}
#[inline]
pub fn cached_get(&mut self, index: I) -> Result<Option<Value<'_, T>>> {
self.inner.cached_get(index)
pub fn unwrap_cached_get(&mut self, index: I) -> Option<T> {
self.inner.unwrap_cached_get(index)
}
#[inline]
pub fn cached_get_(&mut self, index: usize) -> Result<Option<Value<'_, T>>> {
self.inner.cached_get_(index)
pub fn double_unwrap_cached_get(&mut self, index: I) -> T {
self.inner.double_unwrap_cached_get(index)
}
pub fn iter_from<F>(&mut self, index: I, f: F) -> Result<()>
+12 -6
View File
@@ -41,23 +41,29 @@ The element returned by the iterator is a tuple which includes the:
- Block: `Block` (from `bitcoin-rust`)
- Block's Hash: `BlockHash` (also from `bitcoin-rust`)
## Example
`src/main.rs`
Tested with Bitcoin Core `v25.0..=v28.1`
## Requirements
Even though it reads *blkXXXXX.dat* files, it **needs** `bitcoind` to run with the RPC server to filter out block forks.
Even though it reads *blkXXXXX.dat* files, it **needs** `bitcoind` (with no particular parameters) to run with the RPC server to filter out forks.
Peak memory should be around 500MB.
## Comparaison
XOR-ed blocks are supported.
| | [brk_parser](https://crates.io/crates/brk_parser) | [bitcoin-explorer (deprecated)](https://crates.io/crates/bitcoin-explorer) | [blocks_iterator](https://crates.io/crates/blocks_iterator) |
## Disclaimer
A state of the local chain is saved in `{bitcoindir}/blocks/blk_index_to_blk_recap.json` to allow for faster starts (see benchmark below) but doesn't yet support locking. Thus, it is highly recommended to run one instance of `brk_parser` at a time.
## Benchmark
| | [brk_parser](https://crates.io/crates/brk_parser) | [bitcoin-explorer (deprecated)](https://crates.io/crates/bitcoin-explorer) | [blocks_iterator](https://crates.io/crates/blocks_iterator)* |
| --- | --- | --- | --- |
| Runs **with** `bitcoind` | Yes ✅ | No ❌ | Yes ✅ |
| Runs **without** `bitcoind` | No ❌ | Yes ✅ | Yes ✅ |
| `0..=855_000` | 4mn 10s | 4mn 45s | > 2h |
| `800_000..=855_000` | 0mn 52s (4mn 10s if first run) | 0mn 55s | > 2h |
\* `blocks_iterator` is with the default config (and thus with `skip_prevout = false` which does a lot more than just iterate over blocks) so it isn't an apples to apples comparaison and the numbers are misleading. You should expect much closer times. Will update the benchmark with `skip_prevout = true` as soon as possible.
*Benchmarked on a Macbook Pro M3 Pro*
+1 -1
View File
@@ -21,7 +21,7 @@ color-eyre = { workspace = true }
jiff = { workspace = true }
log = { workspace = true }
minreq = { workspace = true }
oxc = { version = "0.63.0", features = ["codegen", "minifier"] }
oxc = { version = "0.64.0", features = ["codegen", "minifier"] }
serde = { workspace = true }
tokio = { version = "1.44.2", features = ["full"] }
tower-http = { version = "0.6.2", features = ["compression-full", "trace"] }
+1 -1
View File
@@ -32,7 +32,7 @@ impl DTS for Query<'static> {
let indexes = Index::all();
let mut contents = "//
// File auto-generated, any modification will be overwritten
// File auto-generated, any modifications will be overwritten
//\n\n"
.to_string();
+9 -1
View File
@@ -17,7 +17,15 @@ pub trait DynamicVec: Send + Sync {
}
#[inline]
fn cached_get(&mut self, index: Self::I) -> Result<Option<Value<Self::T>>> {
self.get_(index.to_usize()?)
self.cached_get_(index.to_usize()?)
}
#[inline]
fn unwrap_cached_get(&mut self, index: Self::I) -> Option<Self::T> {
self.cached_get(index).unwrap().map(Value::into_inner)
}
#[inline]
fn double_unwrap_cached_get(&mut self, index: Self::I) -> Self::T {
self.unwrap_cached_get(index).unwrap()
}
#[inline]
fn get_(&self, index: usize) -> Result<Option<Value<Self::T>>> {
+7 -1
View File
@@ -18,6 +18,7 @@ where
+ Send
+ Sync,
{
fn unwrap_to_usize(self) -> usize;
fn to_usize(self) -> Result<usize>;
fn to_string<'a>() -> &'a str;
}
@@ -37,7 +38,12 @@ where
+ Send
+ Sync,
{
#[inline(always)]
#[inline]
fn unwrap_to_usize(self) -> usize {
self.to_usize().unwrap()
}
#[inline]
fn to_usize(self) -> Result<usize> {
self.try_into().map_err(|_| Error::FailedKeyTryIntoUsize)
}
+24 -4
View File
@@ -1051,12 +1051,32 @@
margin-left: var(--negative-main-padding);
fieldset {
padding-left: var(--main-padding);
padding-top: 0.5rem;
padding: 0.5rem;
z-index: 10;
position: absolute;
left: 0;
top: 0;
&[data-position="nw"] {
padding-left: var(--main-padding);
top: 0;
left: 0;
}
&[data-position="ne"] {
top: 0;
right: 0;
}
&[data-position="se"] {
bottom: 0;
right: 0;
}
&[data-position="sw"] {
padding-left: var(--main-padding);
bottom: 0;
left: 0;
}
gap: 0;
}
}
@@ -1,6 +1,6 @@
// @ts-check
/** @import {IChartApi, ISeriesApi, SeriesDefinition, SingleValueData as _SingleValueData, CandlestickData as _CandlestickData, BaselineData, SeriesType} from './v5.0.5-treeshaked/types' */
/** @import {IChartApi, ISeriesApi, SeriesDefinition, SingleValueData as _SingleValueData, CandlestickData as _CandlestickData, BaselineData, SeriesType, IPaneApi, LineSeriesOptions} from './v5.0.5-treeshaked/types' */
/**
* @typedef {[number, number, number, number]} OHLCTuple
@@ -47,7 +47,7 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
autoSize: true,
layout: {
fontFamily: "Geist mono",
fontSize: 13,
// fontSize: 13,
background: { color: "transparent" },
attributionLogo: false,
colorSpace: "display-p3",
@@ -98,6 +98,16 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
index === /** @satisfies {Height} */ (0) ||
index === /** @satisfies {Difficultyepoch} */ (3) ||
index === /** @satisfies {Halvingepoch} */ (8),
minBarSpacing:
index === /** @satisfies {Monthindex} */ (4)
? 1
: index === /** @satisfies {Quarterindex} */ (5)
? 3
: index === /** @satisfies {Yearindex} */ (6)
? 12
: index === /** @satisfies {Decadeindex} */ (7)
? 120
: undefined,
},
crosshair: {
horzLine: {
@@ -291,6 +301,7 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
* @param {Accessor<CandlestickData[]>} [args.data]
* @param {number} [args.paneIndex]
* @param {boolean} [args.defaultActive]
* @param {boolean} [args.inverse]
*/
addCandlestickSeries({
vecId,
@@ -299,13 +310,14 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
paneIndex: _paneIndex,
defaultActive,
data,
inverse,
}) {
const paneIndex = _paneIndex ?? 0;
if (!ichart || !timeResource) throw Error("Chart not fully set");
const green = colors.green();
const red = colors.red();
const green = inverse ? colors.red() : colors.green();
const red = inverse ? colors.green() : colors.red();
const series = ichart.addSeries(
/** @type {SeriesDefinition<'Candlestick'>} */ (lc.CandlestickSeries),
{
@@ -351,14 +363,11 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
utils,
});
createPriceScaleSelectorIfNeeded({
ichart,
this.addPriceScaleSelectorIfNeeded({
paneIndex,
seriesType: "Candlestick",
signals,
id,
unit,
utils,
});
return series;
@@ -372,6 +381,7 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
* @param {Color} [args.color]
* @param {number} [args.paneIndex]
* @param {boolean} [args.defaultActive]
* @param {DeepPartial<LineStyleOptions & SeriesOptionsCommon>} [args.options]
*/
addLineSeries({
vecId,
@@ -381,12 +391,13 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
paneIndex: _paneIndex,
defaultActive,
data,
options,
}) {
if (!ichart || !timeResource) throw Error("Chart not fully set");
const paneIndex = _paneIndex ?? 0;
color ||= colors.orange;
color ||= unit === "USD" ? colors.dollars : colors.bitcoin;
const series = ichart.addSeries(
/** @type {SeriesDefinition<'Line'>} */ (lc.LineSeries),
@@ -395,6 +406,7 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
visible: defaultActive !== false,
priceLineVisible: false,
color: color(),
...options,
},
paneIndex,
);
@@ -434,14 +446,11 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
utils,
});
createPriceScaleSelectorIfNeeded({
ichart,
this.addPriceScaleSelectorIfNeeded({
paneIndex,
signals,
seriesType: "Line",
id,
unit,
utils,
});
return series;
@@ -520,18 +529,99 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => {
utils,
});
createPriceScaleSelectorIfNeeded({
ichart,
this.addPriceScaleSelectorIfNeeded({
paneIndex,
signals,
seriesType: "Baseline",
id,
unit,
utils,
});
return series;
},
/**
* @param {Object} args
* @param {Unit} args.unit
* @param {string} args.id
* @param {SeriesType} args.seriesType
* @param {number} args.paneIndex
*/
addPriceScaleSelectorIfNeeded({ unit, paneIndex, id, seriesType }) {
id = `${id}-scale`;
this.addFieldsetIfNeeded({
id,
paneIndex,
position: "sw",
createChild({ owner, pane }) {
const { field, selected } = utils.dom.createHorizontalChoiceField({
choices: /** @type {const} */ (["lin", "log"]),
id: utils.stringToId(`${id} ${unit}`),
defaultValue:
unit === "USD" && seriesType !== "Baseline" ? "log" : "lin",
key: `${id}-price-scale-${paneIndex}`,
signals,
});
signals.runWithOwner(owner, () => {
signals.createEffect(selected, (selected) => {
try {
pane.priceScale("right").applyOptions({
mode: selected === "lin" ? 0 : 1,
});
} catch {}
});
});
return field;
},
});
},
/**
* @param {Object} args
* @param {string} args.id
* @param {number} args.paneIndex
* @param {"nw" | "ne" | "se" | "sw"} args.position
* @param {number} [args.timeout]
* @param {(args: {owner: Owner | null, pane: IPaneApi<Time>}) => HTMLElement} args.createChild
*/
addFieldsetIfNeeded({ paneIndex, id, position, createChild }) {
const owner = signals.getOwner();
setTimeout(
() => {
const parent = ichart
?.panes()
.at(paneIndex)
?.getHTMLElement()
.children?.item(1)?.firstChild;
if (!parent) throw Error("Parent should exist");
if (
Array.from(parent.childNodes).filter(
(element) =>
/** @type {HTMLElement} */ (element).dataset.position ===
position,
).length
) {
return;
}
const fieldset = window.document.createElement("fieldset");
fieldset.dataset.size = "xs";
fieldset.dataset.position = position;
fieldset.id = `${id}-${paneIndex}`;
const pane = ichart?.panes().at(paneIndex);
if (!pane) throw Error("Expect pane");
pane
.getHTMLElement()
.children?.item(1)
?.firstChild?.appendChild(fieldset);
fieldset.append(createChild({ owner, pane }));
},
paneIndex ? 50 : 0,
);
},
/**
*
* @param {Object} args
@@ -894,106 +984,3 @@ function createPaneHeightObserver({ ichart, paneIndex, signals, utils }) {
callback();
}
/**
* @param {Object} args
* @param {IChartApi} args.ichart
* @param {Unit} args.unit
* @param {string} args.id
* @param {SeriesType} args.seriesType
* @param {number} args.paneIndex
* @param {Signals} args.signals
* @param {Utilities} args.utils
*/
function createPriceScaleSelectorIfNeeded({
ichart,
unit,
paneIndex,
id,
seriesType,
signals,
utils,
}) {
const owner = signals.getOwner();
setTimeout(
() => {
const parent = ichart
?.panes()
.at(paneIndex)
?.getHTMLElement()
.children?.item(1)?.firstChild;
if (!parent) throw Error("Parent should exist");
const tagName = "fieldset";
if (parent.lastChild?.nodeName.toLowerCase() === tagName) {
return;
}
console.log(id);
const choices = /**@type {const} */ (["lin", "log"]);
/** @typedef {(typeof choices)[number]} Choices */
const serializedValue = signals.createSignal(
/** @satisfies {Choices} */ (
unit === "USD" && seriesType !== "Baseline" ? "log" : "lin"
),
{
save: {
...utils.serde.string,
keyPrefix: "",
key: `${id}-price-scale-${paneIndex}`,
},
},
);
const field = utils.dom.createHorizontalChoiceField({
title: unit,
selected: serializedValue(),
choices: choices,
id: `${id}-${unit.replace(" ", "-")}`,
signals,
});
field.addEventListener("change", (event) => {
// @ts-ignore
const value = event.target.value;
serializedValue.set(value);
});
const element = window.document.createElement(tagName);
element.dataset.size = "xs";
element.id = `${id}-price-scale-${paneIndex}`;
element.append(field);
const mode = signals.createMemo(() => {
switch (serializedValue()) {
case "lin":
return 0;
case "log":
return 1;
}
});
const pane = ichart?.panes().at(paneIndex);
if (!pane) throw Error("Expect pane");
signals.runWithOwner(owner, () => {
signals.createEffect(mode, (mode) => {
try {
pane.priceScale("right").applyOptions({
mode,
});
} catch {}
});
});
pane.getHTMLElement().children?.item(1)?.firstChild?.appendChild(element);
},
paneIndex ? 10 : 0,
);
}
+218 -110
View File
@@ -40,96 +40,218 @@ export function init({
vecsResources,
});
const index_ = createIndexSelector({ elements, signals, utils });
const index = createIndexSelector({ elements, signals, utils });
let firstRun = true;
signals.createEffect(selected, (option) => {
headingElement.innerHTML = option.title;
signals.createEffect(index_, (index) => {
chart.reset({ owner: signals.getOwner() });
signals.createEffect(index, (index) => {
const { field: topUnitField, selected: topUnit } =
utils.dom.createHorizontalChoiceField({
defaultValue: "USD",
keyPrefix: "charts",
key: "unit-0",
choices: /** @type {const} */ ([
/** @satisfies {Unit} */ ("USD"),
/** @satisfies {Unit} */ ("Sats"),
]),
signals,
});
const TIMERANGE_LS_KEY = `chart-timerange-${index}`;
signals.createEffect(topUnit, (topUnit) => {
const { field: seriesTypeField, selected: topSeriesType } =
utils.dom.createHorizontalChoiceField({
defaultValue: "Candles",
keyPrefix: "charts",
key: "seriestype-0",
choices: /** @type {const} */ (["Candles", "Line"]),
signals,
});
const from = signals.createSignal(/** @type {number | null} */ (null), {
save: {
...utils.serde.optNumber,
keyPrefix: TIMERANGE_LS_KEY,
key: "from",
serializeParam: firstRun,
},
});
const to = signals.createSignal(/** @type {number | null} */ (null), {
save: {
...utils.serde.optNumber,
keyPrefix: TIMERANGE_LS_KEY,
key: "to",
serializeParam: firstRun,
},
});
chart.create({
index,
timeScaleSetCallback: (unknownTimeScaleCallback) => {
const from_ = from();
const to_ = to();
if (from_ !== null && to_ !== null) {
chart.inner()?.timeScale().setVisibleLogicalRange({
from: from_,
to: to_,
});
} else {
unknownTimeScaleCallback();
}
},
});
const candles = chart.addCandlestickSeries({
vecId: "ohlc",
name: "Price",
unit: "USD",
});
signals.createEffect(webSockets.kraken1dCandle.latest, (latest) => {
if (!latest) return;
const last = /** @type { CandlestickData | undefined} */ (
candles.data().at(-1)
);
if (!last) return;
candles?.update({ ...last, close: latest.close });
});
[
{ blueprints: option.top, paneIndex: 0 },
{ blueprints: option.bottom, paneIndex: 1 },
].forEach(({ blueprints, paneIndex }) => {
blueprints?.forEach((blueprint) => {
const indexes = /** @type {readonly number[]} */ (
vecIdToIndexes[blueprint.key]
signals.createEffect(topSeriesType, (topSeriesType) => {
const bottomUnits = /** @type {readonly Unit[]} */ (
Object.keys(option.bottom)
);
if (indexes.includes(index)) {
chart.addLineSeries({
vecId: blueprint.key,
color: blueprint.color,
name: blueprint.title,
unit: option.unit,
defaultActive: blueprint.defaultActive,
paneIndex,
const { field: bottomUnitField, selected: bottomUnit } =
utils.dom.createHorizontalChoiceField({
defaultValue: bottomUnits.at(0) || "",
keyPrefix: "charts",
key: "unit-1",
choices: bottomUnits,
signals,
});
}
signals.createEffect(bottomUnit, (bottomUnit) => {
chart.reset({ owner: signals.getOwner() });
chart.addFieldsetIfNeeded({
id: "charts-unit-0",
paneIndex: 0,
position: "nw",
createChild() {
return topUnitField;
},
});
if (bottomUnits.length) {
chart.addFieldsetIfNeeded({
id: "charts-unit-1",
paneIndex: 1,
position: "nw",
createChild() {
return bottomUnitField;
},
});
}
chart.addFieldsetIfNeeded({
id: "charts-seriestype-0",
paneIndex: 0,
position: "ne",
createChild() {
return seriesTypeField;
},
});
const TIMERANGE_LS_KEY = `chart-timerange-${index}`;
const from = signals.createSignal(
/** @type {number | null} */ (null),
{
save: {
...utils.serde.optNumber,
keyPrefix: TIMERANGE_LS_KEY,
key: "from",
serializeParam: firstRun,
},
},
);
const to = signals.createSignal(
/** @type {number | null} */ (null),
{
save: {
...utils.serde.optNumber,
keyPrefix: TIMERANGE_LS_KEY,
key: "to",
serializeParam: firstRun,
},
},
);
chart.create({
index,
timeScaleSetCallback: (unknownTimeScaleCallback) => {
const from_ = from();
const to_ = to();
if (from_ !== null && to_ !== null) {
chart.inner()?.timeScale().setVisibleLogicalRange({
from: from_,
to: to_,
});
} else {
unknownTimeScaleCallback();
}
},
});
switch (topUnit) {
case "USD": {
switch (topSeriesType) {
case "Candles": {
const candles = chart.addCandlestickSeries({
vecId: "ohlc",
name: "Price",
unit: topUnit,
});
break;
}
case "Line": {
const line = chart.addLineSeries({
vecId: "close",
name: "Price",
unit: topUnit,
color: colors.default,
options: {
priceLineVisible: true,
},
});
}
}
// signals.createEffect(webSockets.kraken1dCandle.latest, (latest) => {
// if (!latest) return;
// const last = /** @type { CandlestickData | undefined} */ (
// candles.data().at(-1)
// );
// if (!last) return;
// candles?.update({ ...last, close: latest.close });
// });
break;
}
case "Sats": {
switch (topSeriesType) {
case "Candles": {
const candles = chart.addCandlestickSeries({
vecId: "ohlc-in-sats",
name: "Price",
unit: topUnit,
inverse: true,
});
break;
}
case "Line": {
const line = chart.addLineSeries({
vecId: "close-in-sats",
name: "Price",
unit: topUnit,
color: colors.default,
options: {
priceLineVisible: true,
},
});
}
}
break;
}
}
[
{ blueprints: option.top, paneIndex: 0 },
{ blueprints: option.bottom, paneIndex: 1 },
].forEach(({ blueprints, paneIndex }) => {
const unit = paneIndex ? bottomUnit : topUnit;
console.log({ unit });
blueprints[unit]?.forEach((blueprint) => {
const indexes = /** @type {readonly number[]} */ (
vecIdToIndexes[blueprint.key]
);
if (indexes.includes(index)) {
chart.addLineSeries({
vecId: blueprint.key,
color: blueprint.color,
name: blueprint.title,
unit,
defaultActive: blueprint.defaultActive,
paneIndex,
});
}
});
});
chart
.inner()
?.timeScale()
.subscribeVisibleLogicalRangeChange(
utils.debounce((t) => {
from.set(t.from);
to.set(t.to);
}),
);
firstRun = false;
});
});
});
chart
.inner()
?.timeScale()
.subscribeVisibleLogicalRangeChange(
utils.debounce((t) => {
from.set(t.from);
to.set(t.to);
}),
);
firstRun = false;
});
});
}
@@ -141,48 +263,34 @@ export function init({
* @param {Utilities} args.utils
*/
function createIndexSelector({ elements, signals, utils }) {
const indexChoices = /**@type {const} */ ([
"timestamp",
"date",
"week",
// "difficulty epoch",
"month",
"quarter",
"year",
// "halving epoch",
"decade",
]);
/** @typedef {(typeof indexChoices)[number]} SerializedIndex */
const serializedIndex = /** @type {Signal<SerializedIndex>} */ (
signals.createSignal("date", {
save: {
keyPrefix: "charts",
key: "index",
...utils.serde.string,
},
})
);
const indexesField = utils.dom.createHorizontalChoiceField({
const { field, selected } = utils.dom.createHorizontalChoiceField({
title: "Index",
selected: serializedIndex(),
choices: indexChoices,
defaultValue: "date",
keyPrefix: "charts",
key: "index",
choices: /**@type {const} */ ([
"timestamp",
"date",
"week",
// "difficulty epoch",
"month",
"quarter",
"year",
// "halving epoch",
"decade",
]),
id: "index",
signals,
});
indexesField.addEventListener("change", (event) => {
// @ts-ignore
const value = event.target.value;
serializedIndex.set(value);
});
const fieldset = window.document.createElement("fieldset");
fieldset.append(indexesField);
fieldset.append(field);
fieldset.dataset.size = "sm";
elements.charts.append(fieldset);
const index = signals.createMemo(
/** @returns {ChartableIndex} */ () => {
switch (serializedIndex()) {
switch (selected()) {
case "timestamp":
return /** @satisfies {Height} */ (0);
case "date":
+51 -23
View File
@@ -6,9 +6,9 @@
* @import * as _ from "../packages/ufuzzy/v1.0.14/types"
* @import { createChart as CreateClassicChart, LineStyleOptions, DeepPartial, ChartOptions, IChartApi, IHorzScaleBehavior, WhitespaceData, ISeriesApi, Time, LineData, LogicalRange, SeriesType, BaselineStyleOptions, SeriesOptionsCommon, BaselineData, CandlestickStyleOptions } from "../packages/lightweight-charts/v5.0.5-treeshaked/types"
* @import { SignalOptions } from "../packages/solid-signals/v0.2.4-treeshaked/types/core/core"
* @import { getOwner as GetOwner, onCleanup as OnCleanup, Owner } from "../packages/solid-signals/v0.2.4-treeshaked/types/core/owner"
* @import { createSignal as CreateSignal, createEffect as CreateEffect, Accessor, Setter, createMemo as CreateMemo } from "../packages/solid-signals/v0.2.4-treeshaked/types/signals";
* @import {Signal, Signals} from "../packages/solid-signals/types";
* @import { getOwner as GetOwner, onCleanup as OnCleanup, Owner } from "../packages/solid-signals/v0.2.4-treeshaked/types/core/owner"
* @import { createEffect as CreateEffect, Accessor, Setter, createMemo as CreateMemo } from "../packages/solid-signals/v0.2.4-treeshaked/types/signals";
* @import {Addressindex, Dateindex, Decadeindex, Difficultyepoch, Index, Halvingepoch, Height, Monthindex, P2PK33index, P2PK65index, P2PKHindex, P2SHindex, P2TRindex, P2WPKHindex, P2WSHindex, Txindex, Txinindex, Txoutindex, VecId, Weekindex, Yearindex, VecIdToIndexes, Quarterindex} from "./vecid-to-indexes"
*/
@@ -322,40 +322,62 @@ function createUtils() {
this.importStyle(href).addEventListener("load", callback);
},
/**
* @template {Readonly<string[]>} T
* @param {Object} args
* @param {string | Accessor<string>} args.title
* @param {string} args.id
* @param {Readonly<string[]>} args.choices
* @param {string} args.selected
* @param {{createEffect: CreateEffect}} args.signals
* @param {string | Accessor<string>} [args.title]
* @param {T[number]} args.defaultValue
* @param {string} [args.id]
* @param {T} args.choices
* @param {string} [args.keyPrefix]
* @param {string} args.key
* @param {{createEffect: CreateEffect, createSignal: Signals["createSignal"]}} args.signals
*/
createHorizontalChoiceField({ title, id, choices, selected, signals }) {
createHorizontalChoiceField({
title,
id,
choices,
defaultValue,
keyPrefix,
key,
signals,
}) {
/** @type {Signal<T[number]>} */
const selected = signals.createSignal(defaultValue, {
save: {
...serde.string,
keyPrefix: keyPrefix ?? "",
key,
},
});
const field = window.document.createElement("div");
field.classList.add("field");
const legend = window.document.createElement("legend");
if (typeof title === "string") {
legend.innerHTML = title;
} else {
signals.createEffect(title, (title) => {
if (title) {
const legend = window.document.createElement("legend");
if (typeof title === "string") {
legend.innerHTML = title;
});
}
field.append(legend);
} else {
signals.createEffect(title, (title) => {
legend.innerHTML = title;
});
}
field.append(legend);
const hr = window.document.createElement("hr");
field.append(hr);
const hr = window.document.createElement("hr");
field.append(hr);
}
const div = window.document.createElement("div");
field.append(div);
choices.forEach((choice) => {
const inputValue = choice.toLowerCase();
const inputValue = choice;
const { label } = this.createLabeledInput({
inputId: `${id}-${choice.toLowerCase()}`,
inputName: id,
inputId: `${id ?? key}-${choice.toLowerCase()}`,
inputName: id ?? key,
inputValue,
inputChecked: inputValue === selected,
inputChecked: inputValue === selected(),
labelTitle: choice,
type: "radio",
});
@@ -365,7 +387,13 @@ function createUtils() {
div.append(label);
});
return field;
field.addEventListener("change", (event) => {
// @ts-ignore
const value = event.target.value;
selected.set(value);
});
return { field, selected };
},
/**
* @param {Object} args
File diff suppressed because it is too large Load Diff
@@ -1,5 +1,5 @@
//
// File auto-generated, any modification will be overwritten
// File auto-generated, any modifications will be overwritten
//
/** @typedef {0} Height */
@@ -78,12 +78,33 @@ export function createVecIdToIndexes() {
blockhash: [Height],
close: [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"close-in-cents": [Dateindex, Height],
"close-in-sats": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
coinbase: [Height],
"coinbase-10p": [Dateindex],
"coinbase-25p": [Dateindex],
"coinbase-75p": [Dateindex],
"coinbase-90p": [Dateindex],
"coinbase-average": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"coinbase-in-btc": [Height],
"coinbase-in-btc-10p": [Dateindex],
"coinbase-in-btc-25p": [Dateindex],
"coinbase-in-btc-75p": [Dateindex],
"coinbase-in-btc-90p": [Dateindex],
"coinbase-in-btc-average": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"coinbase-in-btc-max": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"coinbase-in-btc-median": [Dateindex],
"coinbase-in-btc-min": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"coinbase-in-btc-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"coinbase-in-usd": [Height],
"coinbase-in-usd-10p": [Dateindex],
"coinbase-in-usd-25p": [Dateindex],
"coinbase-in-usd-75p": [Dateindex],
"coinbase-in-usd-90p": [Dateindex],
"coinbase-in-usd-average": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"coinbase-in-usd-max": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"coinbase-in-usd-median": [Dateindex],
"coinbase-in-usd-min": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"coinbase-in-usd-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"coinbase-max": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"coinbase-median": [Dateindex],
"coinbase-min": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
@@ -99,6 +120,26 @@ export function createVecIdToIndexes() {
"fee-75p": [Height],
"fee-90p": [Height],
"fee-average": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"fee-in-btc": [Txindex],
"fee-in-btc-10p": [Height],
"fee-in-btc-25p": [Height],
"fee-in-btc-75p": [Height],
"fee-in-btc-90p": [Height],
"fee-in-btc-average": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"fee-in-btc-max": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"fee-in-btc-median": [Height],
"fee-in-btc-min": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"fee-in-btc-sum": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"fee-in-usd": [Txindex],
"fee-in-usd-10p": [Height],
"fee-in-usd-25p": [Height],
"fee-in-usd-75p": [Height],
"fee-in-usd-90p": [Height],
"fee-in-usd-average": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"fee-in-usd-max": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"fee-in-usd-median": [Height],
"fee-in-usd-min": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"fee-in-usd-sum": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"fee-max": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"fee-median": [Height],
"fee-min": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
@@ -138,6 +179,7 @@ export function createVecIdToIndexes() {
height: [Addressindex, Height, P2PK33index, P2PK65index, P2PKHindex, P2SHindex, P2TRindex, P2WPKHindex, P2WSHindex, Txindex, Txinindex, Txoutindex, Emptyindex, Multisigindex, Opreturnindex, Pushonlyindex, Unknownindex],
high: [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"high-in-cents": [Dateindex, Height],
"high-in-sats": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"input-count": [Txindex],
"input-count-10p": [Height],
"input-count-25p": [Height],
@@ -164,11 +206,14 @@ export function createVecIdToIndexes() {
locktime: [Txindex],
low: [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"low-in-cents": [Dateindex, Height],
"low-in-sats": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
monthindex: [Dateindex, Monthindex],
ohlc: [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"ohlc-in-cents": [Dateindex, Height],
"ohlc-in-sats": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
open: [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"open-in-cents": [Dateindex, Height],
"open-in-sats": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"output-count": [Txindex],
"output-count-10p": [Height],
"output-count-25p": [Height],
@@ -191,13 +236,32 @@ export function createVecIdToIndexes() {
p2wshaddressbytes: [P2WSHindex],
quarterindex: [Monthindex, Quarterindex],
"real-date": [Height],
"sats-per-dollar": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
subsidy: [Height],
"subsidy-10p": [Dateindex],
"subsidy-25p": [Dateindex],
"subsidy-75p": [Dateindex],
"subsidy-90p": [Dateindex],
"subsidy-average": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"subsidy-in-btc": [Height],
"subsidy-in-btc-10p": [Dateindex],
"subsidy-in-btc-25p": [Dateindex],
"subsidy-in-btc-75p": [Dateindex],
"subsidy-in-btc-90p": [Dateindex],
"subsidy-in-btc-average": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"subsidy-in-btc-max": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"subsidy-in-btc-median": [Dateindex],
"subsidy-in-btc-min": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"subsidy-in-btc-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"subsidy-in-usd": [Height],
"subsidy-in-usd-10p": [Dateindex],
"subsidy-in-usd-25p": [Dateindex],
"subsidy-in-usd-75p": [Dateindex],
"subsidy-in-usd-90p": [Dateindex],
"subsidy-in-usd-average": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"subsidy-in-usd-max": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"subsidy-in-usd-median": [Dateindex],
"subsidy-in-usd-min": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"subsidy-in-usd-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"subsidy-max": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"subsidy-median": [Dateindex],
"subsidy-min": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
@@ -208,13 +272,19 @@ export function createVecIdToIndexes() {
"total-block-vbytes": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"total-block-weight": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"total-coinbase": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"total-coinbase-in-btc": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"total-coinbase-in-usd": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"total-fee": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"total-fee-in-btc": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"total-fee-in-usd": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"total-input-count": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"total-input-value": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"total-output-count": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"total-output-value": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"total-size": [Height, Txindex],
"total-subsidy": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"total-subsidy-in-btc": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"total-subsidy-in-usd": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"total-tx-count": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"total-tx-v1": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],
"total-tx-v2": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch],