mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-27 06:34:30 -07:00
Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 664b125ce2 | |||
| 5f4b1c9e32 | |||
| d11d3f19bd | |||
| f34f4f2738 | |||
| 15db7c2310 | |||
| f9257ed04d | |||
| 15e6ef8488 | |||
| 9ae0a57f22 | |||
| 1e38c21f8e | |||
| bdc3c19163 | |||
| d55478da54 | |||
| 82bcc55645 | |||
| 07618ebe43 | |||
| 1492834d1e | |||
| 5ab6197356 | |||
| 0a789fe551 | |||
| caa8ff23ed | |||
| ee30d1d36d | |||
| 0d9415db9d | |||
| 8020e1126f | |||
| 3439422057 | |||
| 68d2bf736f | |||
| d78c39fd8c | |||
| b1dcad86b4 | |||
| 9b6124074d | |||
| 02cbaa1e80 | |||
| a12f1321c7 | |||
| 8b67f592ac | |||
| 319d17b337 | |||
| 476eaa85da | |||
| d26099855c | |||
| e47456da17 | |||
| a464d5d0b6 | |||
| 1cfb7b5615 | |||
| ac7c2f3d03 | |||
| 638d9e6e01 | |||
| 8b9df2a396 | |||
| d7fe911bde | |||
| 0acc3d511b | |||
| 4cf465f419 | |||
| b686d317a9 | |||
| dcef541852 | |||
| abdd733f11 | |||
| 942431e882 | |||
| 1c75ea046c | |||
| f32b6daa51 | |||
| 3736d6ba5e | |||
| 9788b01f35 | |||
| 9aec991da6 | |||
| 910701ce04 | |||
| 34b462d511 | |||
| 139e93b2f0 | |||
| 0dd7e9359e | |||
| 41cf0225e3 | |||
| 962254e511 | |||
| a7f2b24bac | |||
| 1323d988af | |||
| 7c49e5c749 | |||
| cd69ec4fa3 | |||
| 4c7e9fbee2 | |||
| 1639df5616 | |||
| 810cdbd790 | |||
| 0d4f4aec4e |
@@ -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:
|
||||
|
||||
+7
-7
@@ -36,7 +36,7 @@ Added git tags for each version though Markdown won't display formatted on Githu
|
||||
Moved Sanakirja database wrapper to its own crate (`snkrj`) and added a robust auto defragmentation to improve disk usage without the need for user's intervention.
|
||||
Since it's not used anymore it will moved out of the repository relatively soon.
|
||||
|
||||
# [v0.5.0](https://github.com/kibo-money/kibo/tree/eea56d394bf92c62c81da8b78b8c47ea730683f5) | [873199](https://mempool.space/block/0000000000000000000270925aa6a565be92e13164565a3f7994ca1966e48050) - 2024/12/04
|
||||
# [kibo-v0.5.0](https://github.com/kibo-money/kibo/tree/eea56d394bf92c62c81da8b78b8c47ea730683f5) | [873199](https://mempool.space/block/0000000000000000000270925aa6a565be92e13164565a3f7994ca1966e48050) - 2024/12/04
|
||||
|
||||

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

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

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

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

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

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

|
||||
|
||||
Generated
+194
-193
@@ -34,6 +34,19 @@ dependencies = [
|
||||
"cpufeatures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"getrandom 0.2.16",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy 0.7.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
@@ -138,6 +151,12 @@ dependencies = [
|
||||
"derive_arbitrary",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.6"
|
||||
@@ -146,9 +165,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "async-compression"
|
||||
version = "0.4.22"
|
||||
version = "0.4.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59a194f9d963d8099596278594b3107448656ba73831c9d8c783e613ce86da64"
|
||||
checksum = "b37fc50485c4f3f736a4fb14199f6d5f5ba008d7f28fe710306c92780f004c07"
|
||||
dependencies = [
|
||||
"brotli",
|
||||
"flate2",
|
||||
@@ -368,7 +387,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk"
|
||||
version = "0.0.17"
|
||||
version = "0.0.31"
|
||||
dependencies = [
|
||||
"brk_cli",
|
||||
"brk_computer",
|
||||
@@ -385,7 +404,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_cli"
|
||||
version = "0.0.17"
|
||||
version = "0.0.31"
|
||||
dependencies = [
|
||||
"brk_computer",
|
||||
"brk_core",
|
||||
@@ -406,7 +425,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_computer"
|
||||
version = "0.0.17"
|
||||
version = "0.0.31"
|
||||
dependencies = [
|
||||
"brk_core",
|
||||
"brk_exit",
|
||||
@@ -416,12 +435,13 @@ dependencies = [
|
||||
"brk_parser",
|
||||
"brk_vec",
|
||||
"color-eyre",
|
||||
"fjall",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brk_core"
|
||||
version = "0.0.17"
|
||||
version = "0.0.31"
|
||||
dependencies = [
|
||||
"bitcoin",
|
||||
"bitcoincore-rpc",
|
||||
@@ -433,12 +453,12 @@ dependencies = [
|
||||
"rlimit",
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
"zerocopy",
|
||||
"zerocopy 0.8.24",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brk_exit"
|
||||
version = "0.0.17"
|
||||
version = "0.0.31"
|
||||
dependencies = [
|
||||
"brk_logger",
|
||||
"ctrlc",
|
||||
@@ -447,7 +467,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_fetcher"
|
||||
version = "0.0.17"
|
||||
version = "0.0.31"
|
||||
dependencies = [
|
||||
"brk_core",
|
||||
"brk_logger",
|
||||
@@ -460,7 +480,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_indexer"
|
||||
version = "0.0.17"
|
||||
version = "0.0.31"
|
||||
dependencies = [
|
||||
"bitcoin",
|
||||
"bitcoincore-rpc",
|
||||
@@ -474,12 +494,12 @@ dependencies = [
|
||||
"fjall",
|
||||
"log",
|
||||
"rayon",
|
||||
"zerocopy",
|
||||
"zerocopy 0.8.24",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brk_logger"
|
||||
version = "0.0.17"
|
||||
version = "0.0.31"
|
||||
dependencies = [
|
||||
"color-eyre",
|
||||
"env_logger",
|
||||
@@ -489,7 +509,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_parser"
|
||||
version = "0.0.17"
|
||||
version = "0.0.31"
|
||||
dependencies = [
|
||||
"bitcoin",
|
||||
"bitcoincore-rpc",
|
||||
@@ -499,12 +519,12 @@ dependencies = [
|
||||
"rayon",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"zerocopy",
|
||||
"zerocopy 0.8.24",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brk_query"
|
||||
version = "0.0.17"
|
||||
version = "0.0.31"
|
||||
dependencies = [
|
||||
"brk_computer",
|
||||
"brk_indexer",
|
||||
@@ -520,7 +540,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_server"
|
||||
version = "0.0.17"
|
||||
version = "0.0.31"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"brk_computer",
|
||||
@@ -541,27 +561,28 @@ dependencies = [
|
||||
"tokio",
|
||||
"tower-http",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brk_vec"
|
||||
version = "0.0.17"
|
||||
version = "0.0.31"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"axum",
|
||||
"memmap2",
|
||||
"rayon",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"zerocopy",
|
||||
"zerocopy 0.8.24",
|
||||
"zstd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brotli"
|
||||
version = "7.0.0"
|
||||
version = "8.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd"
|
||||
checksum = "cf19e729cdbd51af9a397fb9ef8ac8378007b797f8273cfbfdf45dcaa316167b"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
@@ -570,9 +591,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brotli-decompressor"
|
||||
version = "4.0.2"
|
||||
version = "5.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37"
|
||||
checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
@@ -641,9 +662,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.18"
|
||||
version = "1.2.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
|
||||
checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
@@ -687,9 +708,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.35"
|
||||
version = "4.5.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944"
|
||||
checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -697,9 +718,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.35"
|
||||
version = "4.5.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9"
|
||||
checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -844,9 +865,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.14"
|
||||
version = "0.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471"
|
||||
checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
@@ -972,9 +993,9 @@ checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b"
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.4.1"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28cfac68e08048ae1883171632c2aef3ebc555621ae56fbccce1cbf22dd7f058"
|
||||
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
"serde",
|
||||
@@ -1100,9 +1121,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
||||
|
||||
[[package]]
|
||||
name = "fjall"
|
||||
version = "2.8.0"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26b2ced3483989a62b3533c9f99054d73b527c6c0045cf22b00fe87956f1a46f"
|
||||
checksum = "958511f67d1f80e6bff9ffac05c626bb340d4602ca6ea5617d9901c218c894f0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"byteview",
|
||||
@@ -1122,7 +1143,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide 0.8.7",
|
||||
"miniz_oxide 0.8.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1131,6 +1152,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"
|
||||
@@ -1191,9 +1218,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
@@ -1245,6 +1272,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1413,9 +1442,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.8.0"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
|
||||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.15.2",
|
||||
@@ -1463,9 +1492,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||
|
||||
[[package]]
|
||||
name = "jiff"
|
||||
version = "0.2.5"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c102670231191d07d37a35af3eb77f1f0dbf7a71be51a962dcd57ea607be7260"
|
||||
checksum = "5a064218214dc6a10fbae5ec5fa888d80c45d611aba169222fc272072bf7aef6"
|
||||
dependencies = [
|
||||
"jiff-static",
|
||||
"jiff-tzdb-platform",
|
||||
@@ -1478,9 +1507,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "jiff-static"
|
||||
version = "0.2.5"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cdde31a9d349f1b1f51a0b3714a5940ac022976f4b49485fc04be052b183b4c"
|
||||
checksum = "199b7932d97e325aff3a7030e141eafe7f2c6268e1d1b24859b753a627f45254"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1542,15 +1571,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.171"
|
||||
version = "0.2.172"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.9.3"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
|
||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
@@ -1562,12 +1591,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"
|
||||
@@ -1576,9 +1599,9 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
|
||||
[[package]]
|
||||
name = "lsm-tree"
|
||||
version = "2.8.0"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a63a5e98a38b51765274137d8aedfbd848da5f4d016867e186b673fcc06a8c"
|
||||
checksum = "87d58bdef2dcbf50fce9f343265bdbd7fb08a458d241eb837ce426be22d674b4"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"crossbeam-skiplist",
|
||||
@@ -1663,18 +1686,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.7"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430"
|
||||
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minreq"
|
||||
version = "2.13.3"
|
||||
version = "2.13.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567496f13503d6cae8c9f961f34536850275f396307d7a6b981eef1464032f53"
|
||||
checksum = "f0d2aaba477837b46ec1289588180fabfccf0c3b1d1a0c6b1866240cd6cd5ce9"
|
||||
dependencies = [
|
||||
"log",
|
||||
"rustls",
|
||||
@@ -1713,16 +1736,6 @@ version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51"
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
|
||||
dependencies = [
|
||||
"overload",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
@@ -1778,12 +1791,6 @@ version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e"
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "owo-colors"
|
||||
version = "3.5.0"
|
||||
@@ -1798,9 +1805,9 @@ checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564"
|
||||
|
||||
[[package]]
|
||||
name = "oxc"
|
||||
version = "0.62.0"
|
||||
version = "0.66.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c274a11ab2471eea5f970d943ecb7b64dc9fa21d89ac5c968fc0f48ca9971196"
|
||||
checksum = "409ba57c4752b7fab9609af78790aadeb541316933d1525484dad877988622f6"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
@@ -1841,9 +1848,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_allocator"
|
||||
version = "0.62.0"
|
||||
version = "0.66.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fef6db9c542af8b1b0889c4fdbc4dfd0a13c5bec0f94ef39bb826084465d6b1e"
|
||||
checksum = "43fe5f8d34c351e3c90b512046dbfff2ff87c8a1927ebe6945f1cdefcc3219d0"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"bumpalo",
|
||||
@@ -1855,9 +1862,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_ast"
|
||||
version = "0.62.0"
|
||||
version = "0.66.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c269cf713bed18d74e957045d2b1cf57827333a66aad2b2c136c9f8b79940bd2"
|
||||
checksum = "5ad2e9c3fb4b409b14fd791fbbf6ced9a81363364beedd48059bbb8f42bf4987"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cow-utils",
|
||||
@@ -1872,9 +1879,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_ast_macros"
|
||||
version = "0.62.0"
|
||||
version = "0.66.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1d8afe9d7e4aed37d6e8906250db4872f514c15a244268ce3da09ccb4017900"
|
||||
checksum = "578b69ed39d814cb8396674e17a0f94f1c02bc25d226b265c2913bd6e84afffb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1883,9 +1890,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_ast_visit"
|
||||
version = "0.62.0"
|
||||
version = "0.66.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d360f012f970b3e79f8f9863abb83b373014eb9d1a23fecd7ce33e555cc3151"
|
||||
checksum = "f437ca959bf931d5facbc6df77c7491a4aec32df5b9f647ffa19c52055a7dc56"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
@@ -1895,9 +1902,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_cfg"
|
||||
version = "0.62.0"
|
||||
version = "0.66.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17a48085dd0ca7e8f3ad946a131d8229af783be65cbf4965ff6379e432f6b625"
|
||||
checksum = "ccecf0bce4034ebf17e7edb6f214fa0e6f8d134d1a3fb98408d6bcbef024a3a1"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"itertools",
|
||||
@@ -1910,9 +1917,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_codegen"
|
||||
version = "0.62.0"
|
||||
version = "0.66.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1e6d4e1c953205c62effeb61c1da684dd1668feaf21b4fe15c2b603526355f6"
|
||||
checksum = "e3361ed40dd6b4b6a7a4b44c175aa6beea68eefed68bc32a28684a0d1a00bc39"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cow-utils",
|
||||
@@ -1931,15 +1938,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_data_structures"
|
||||
version = "0.62.0"
|
||||
version = "0.66.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e2866696e6bb90151c5687a961c3ff1fa2726436869d42eea14cf2d5c663590"
|
||||
checksum = "0d2d64d2e627796f73e37ccb51f1f87cd9de612245ef3f790051855587d3734e"
|
||||
|
||||
[[package]]
|
||||
name = "oxc_diagnostics"
|
||||
version = "0.62.0"
|
||||
version = "0.66.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d7800336d376a2baeafb9d2bcdc9fbef254863c33810e6d1cc4a431cd0048ef"
|
||||
checksum = "96ece1486240cfeec516eaaa7332c96decb3a756d72e504bb63393507996c39d"
|
||||
dependencies = [
|
||||
"cow-utils",
|
||||
"oxc-miette",
|
||||
@@ -1947,9 +1954,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_ecmascript"
|
||||
version = "0.62.0"
|
||||
version = "0.66.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0edf650adfacf84768cdfeca874d8f5ffebfd108ee8a44959c0eca82b04321c6"
|
||||
checksum = "0d7d5ddf1cd783ed1a930ac6eedd4f73c6a5359beaabad7ee8333e366816291c"
|
||||
dependencies = [
|
||||
"cow-utils",
|
||||
"num-bigint",
|
||||
@@ -1961,9 +1968,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_estree"
|
||||
version = "0.62.0"
|
||||
version = "0.66.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd77f6588d373c1b753588b784de380a7418f8e46776e25c4564739994b9a5a6"
|
||||
checksum = "62de94b10df7ab86a379f01b75076f6a762fc91a001678108318203fc0805ad9"
|
||||
|
||||
[[package]]
|
||||
name = "oxc_index"
|
||||
@@ -1973,9 +1980,9 @@ checksum = "2fa07b0cfa997730afed43705766ef27792873fdf5215b1391949fec678d2392"
|
||||
|
||||
[[package]]
|
||||
name = "oxc_mangler"
|
||||
version = "0.62.0"
|
||||
version = "0.66.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02f00ca9e544230f01d37de50ba710136763a13804303bcf70cf22d8155f9db5"
|
||||
checksum = "8d691c6609bca852ae1e0571de564de3b4d110a46c9877aa029e9dba56b76d1c"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"itertools",
|
||||
@@ -1990,9 +1997,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_minifier"
|
||||
version = "0.62.0"
|
||||
version = "0.66.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8670c4452b9f78012b9ede921e40f91686ad9a1af1c40aab8ee3a5f4ef8380ef"
|
||||
checksum = "294aa5790cc0beae7018d99dc5b389d373725ef7ea7ecef5d0ed18794b3414b3"
|
||||
dependencies = [
|
||||
"cow-utils",
|
||||
"oxc_allocator",
|
||||
@@ -2012,9 +2019,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_parser"
|
||||
version = "0.62.0"
|
||||
version = "0.66.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8eaebe1ac01073b2a43a8848ae7ec24fdad3813855d72bb1942908632654f94"
|
||||
checksum = "5b7defa49cc20f9e3c346674b06752cacaacce053cde69a04f0f85f31e00820f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cow-utils",
|
||||
@@ -2035,9 +2042,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_regular_expression"
|
||||
version = "0.62.0"
|
||||
version = "0.66.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9ad8833ffba010e9f4cced1482297282728b0dc1c410cd716f206d214250f3f"
|
||||
checksum = "14d37e8585630a167c4a2b121dcdab52bf13b71a6bd64260efe797956bd4f6d0"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast_macros",
|
||||
@@ -2051,9 +2058,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_semantic"
|
||||
version = "0.62.0"
|
||||
version = "0.66.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0523c9521e3ee63d6e0b463941e030b482977d7c323ee802eebacac8e5227bc8"
|
||||
checksum = "895130e4f197b77d9b54deffccc2ce8a9d977435c022a49ddecb1f467b946854"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"oxc_allocator",
|
||||
@@ -2087,9 +2094,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_span"
|
||||
version = "0.62.0"
|
||||
version = "0.66.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bcfa55b4e3de93d39528b4ac616c00918dc73b6f6828403b3c56a7dde7af23b"
|
||||
checksum = "8350c982e6284f41668ebd3c714de22280a19f617c3cb6117bbc4e16afc6b13a"
|
||||
dependencies = [
|
||||
"compact_str",
|
||||
"oxc-miette",
|
||||
@@ -2100,9 +2107,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_syntax"
|
||||
version = "0.62.0"
|
||||
version = "0.66.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7bc0d1f63b254791867280db5e582d7411c112f0798eee50bfdb8cdd2ef80c93"
|
||||
checksum = "7e85d9197e08e176d6f58a3885d125738c46a69145410e82b3a32f676ddd5546"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cow-utils",
|
||||
@@ -2121,9 +2128,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_traverse"
|
||||
version = "0.62.0"
|
||||
version = "0.66.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a1f5183b3db89b3b3c7621741d5e2b9c13996dec5be4ad5e7adf86fdcfd24f0"
|
||||
checksum = "ac43e668dcd3a0b17cf4f889feac5321e56430a0550205df2e85b3e9314f6caa"
|
||||
dependencies = [
|
||||
"compact_str",
|
||||
"itoa",
|
||||
@@ -2140,12 +2147,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "papergrid"
|
||||
version = "0.14.0"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b915f831b85d984193fdc3d3611505871dc139b2534530fa01c1a6a6707b6723"
|
||||
checksum = "30268a8d20c2c0d126b2b6610ab405f16517f6ba9f244d8c59ac2c512a8a1ce7"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"bytecount",
|
||||
"fnv",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
@@ -2208,12 +2215,14 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.7.1"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
|
||||
checksum = "7a98c6720655620a521dcc722d0ad66cd8afd5d86e34a89ef691c50b7b24de06"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"indexmap 2.8.0",
|
||||
"hashbrown 0.15.2",
|
||||
"indexmap 2.9.0",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2303,7 +2312,7 @@ version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
"zerocopy 0.8.24",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2330,18 +2339,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",
|
||||
@@ -2389,7 +2398,7 @@ version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
"getrandom 0.2.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2420,9 +2429,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.10"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1"
|
||||
checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
@@ -2464,7 +2473,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"getrandom 0.2.15",
|
||||
"getrandom 0.2.16",
|
||||
"libc",
|
||||
"untrusted",
|
||||
"windows-sys 0.52.0",
|
||||
@@ -2583,9 +2592,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "self_cell"
|
||||
version = "1.1.0"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2fdfc24bc566f839a2da4c4295b82db7d25a24253867d5c64355abb5799bdbe"
|
||||
checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749"
|
||||
|
||||
[[package]]
|
||||
name = "seq-macro"
|
||||
@@ -2675,7 +2684,7 @@ dependencies = [
|
||||
"chrono",
|
||||
"hex",
|
||||
"indexmap 1.9.3",
|
||||
"indexmap 2.8.0",
|
||||
"indexmap 2.9.0",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
@@ -2723,9 +2732,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.2"
|
||||
version = "1.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
|
||||
checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -2750,9 +2759,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.14.0"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
|
||||
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
||||
|
||||
[[package]]
|
||||
name = "smawk"
|
||||
@@ -2824,19 +2833,20 @@ checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
|
||||
|
||||
[[package]]
|
||||
name = "tabled"
|
||||
version = "0.18.0"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "121d8171ee5687a4978d1b244f7d99c43e7385a272185a2f1e1fa4dc0979d444"
|
||||
checksum = "228d124371171cd39f0f454b58f73ddebeeef3cef3207a82ffea1c29465aea43"
|
||||
dependencies = [
|
||||
"papergrid",
|
||||
"tabled_derive",
|
||||
"testing_table",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tabled_derive"
|
||||
version = "0.10.0"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52d9946811baad81710ec921809e2af67ad77719418673b2a3794932d57b7538"
|
||||
checksum = "0ea5d1b13ca6cff1f9231ffd62f15eefd72543dab5e468735f1a456728a02846"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error2",
|
||||
@@ -2858,6 +2868,15 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "testing_table"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f8daae29995a24f65619e19d8d31dea5b389f3d853d8bf297bbf607cd0014cc"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.16.2"
|
||||
@@ -2932,9 +2951,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.44.1"
|
||||
version = "1.44.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a"
|
||||
checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
@@ -2961,9 +2980,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.14"
|
||||
version = "0.7.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034"
|
||||
checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
@@ -2999,7 +3018,7 @@ version = "0.22.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
|
||||
dependencies = [
|
||||
"indexmap 2.8.0",
|
||||
"indexmap 2.9.0",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
@@ -3097,29 +3116,15 @@ dependencies = [
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
|
||||
dependencies = [
|
||||
"nu-ansi-term",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3172,9 +3177,9 @@ checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
||||
|
||||
[[package]]
|
||||
name = "value-log"
|
||||
version = "1.8.0"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd29b17c041f94e0885179637289815cd038f0c9fc19c4549d5a97017404fb7d"
|
||||
checksum = "62fc7c4ce161f049607ecea654dca3f2d727da5371ae85e2e4f14ce2b98ed67c"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"byteview",
|
||||
@@ -3284,28 +3289,6 @@ version = "0.25.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.61.0"
|
||||
@@ -3449,9 +3432,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.4"
|
||||
version = "0.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36"
|
||||
checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -3480,13 +3463,33 @@ dependencies = [
|
||||
"lzma-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"zerocopy-derive 0.7.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
"zerocopy-derive 0.8.24",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3522,9 +3525,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "2.6.0"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "febbe83a485467affa75a75d28dc7494acd2f819e549536c47d46b3089b56164"
|
||||
checksum = "1dcb24d0152526ae49b9b96c1dcf71850ca1e0b882e4e28ed898a93c41334744"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"arbitrary",
|
||||
@@ -3536,7 +3539,7 @@ dependencies = [
|
||||
"flate2",
|
||||
"getrandom 0.3.2",
|
||||
"hmac",
|
||||
"indexmap 2.8.0",
|
||||
"indexmap 2.9.0",
|
||||
"lzma-rs",
|
||||
"memchr",
|
||||
"pbkdf2",
|
||||
@@ -3550,15 +3553,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",
|
||||
]
|
||||
|
||||
|
||||
+17
-11
@@ -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.17"
|
||||
package.version = "0.0.31"
|
||||
package.repository = "https://github.com/bitcoinresearchkit/brk"
|
||||
|
||||
[profile.release]
|
||||
@@ -16,6 +16,7 @@ panic = "abort"
|
||||
inherits = "release"
|
||||
|
||||
[workspace.dependencies]
|
||||
axum = "0.8.3"
|
||||
bitcoin = { version = "0.32.5", features = ["serde"] }
|
||||
bitcoincore-rpc = "0.19.0"
|
||||
brk_cli = { version = "0", path = "crates/brk_cli" }
|
||||
@@ -30,35 +31,40 @@ brk_query = { version = "0", path = "crates/brk_query" }
|
||||
brk_server = { version = "0", path = "crates/brk_server" }
|
||||
brk_vec = { version = "0", path = "crates/brk_vec" }
|
||||
byteview = "0.6.1"
|
||||
clap = { version = "4.5.35", features = ["derive", "string"] }
|
||||
clap = { version = "4.5.37", features = ["derive", "string"] }
|
||||
color-eyre = "0.6.3"
|
||||
derive_deref = "1.1.1"
|
||||
fjall = "2.8.0"
|
||||
jiff = "0.2.5"
|
||||
fjall = "2.9.0"
|
||||
jiff = "0.2.10"
|
||||
log = { version = "0.4.27" }
|
||||
minreq = { version = "2.13.3", features = ["https", "serde_json"] }
|
||||
minreq = { version = "2.13.4", features = ["https", "serde_json"] }
|
||||
rayon = "1.10.0"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
serde_json = { version = "1.0.140", features = ["float_roundtrip"] }
|
||||
tabled = "0.18.0"
|
||||
tabled = "0.19.0"
|
||||
zerocopy = { version = "0.8.24", features = ["derive"] }
|
||||
|
||||
[workspace.metadata.release]
|
||||
shared-version = true
|
||||
tag-name = "v{{version}}"
|
||||
pre-release-commit-message = "release: v{{version}}"
|
||||
tag-message = "release: v{{version}}"
|
||||
|
||||
[workspace.metadata.dist]
|
||||
# The preferred dist version to use in CI (Cargo.toml SemVer syntax)
|
||||
cargo-dist-version = "0.28.0"
|
||||
# CI backends to support
|
||||
ci = "github"
|
||||
# The installers to generate for each app
|
||||
installers = []
|
||||
# Target platforms to build apps for (Rust target-triple syntax)
|
||||
targets = [
|
||||
"aarch64-apple-darwin",
|
||||
"aarch64-unknown-linux-gnu",
|
||||
"x86_64-apple-darwin",
|
||||
"x86_64-unknown-linux-gnu",
|
||||
"x86_64-pc-windows-msvc",
|
||||
]
|
||||
|
||||
[workspace.metadata.dist.github-custom-runners]
|
||||
global = "ubuntu-latest"
|
||||
aarch64-apple-darwin.runner = "macos-14"
|
||||
x86_64-unknown-linux-gnu.runner = "ubuntu-latest"
|
||||
x86_64-unknown-linux-gnu.container = { image = "quay.io/pypa/manylinux_2_28_x86_64", host = "x86_64-unknown-linux-musl" }
|
||||
aarch64-unknown-linux-gnu.runner = "ubuntu-latest"
|
||||
aarch64-unknown-linux-gnu.container = { image = "quay.io/pypa/manylinux_2_28_x86_64", host = "x86_64-unknown-linux-musl" }
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<a href="https://deps.rs/crate/brk">
|
||||
<img src="https://deps.rs/crate/brk/latest/status.svg" alt="Dependency status">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cvrwpv3zEG">
|
||||
<a href="https://discord.gg/HaR3wpH3nr">
|
||||
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
|
||||
@@ -29,13 +29,13 @@
|
||||
<a href="https://bsky.app/profile/bitcoinresearchkit.org">
|
||||
<img src="https://img.shields.io/badge/bluesky-blue?link=https%3A%2F%2Fbsky.app%2Fprofile%2Fbitcoinresearchkit.org" alt="Bluesky" />
|
||||
</a>
|
||||
<a href="https://x.com/0xbrk">
|
||||
<a href="https://x.com/brkdotorg">
|
||||
<img src="https://img.shields.io/badge/x.com-black" alt="X" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
> **WARNING**
|
||||
>
|
||||
>
|
||||
> This project is still a work in progress and while it's much better in many ways than its previous version ([kibo v0.5](https://github.com/kibo-money/kibo)), it doesn't yet include all of those datasets. If you're interested in having everything right now, please use the latter until feature parity is achieved.
|
||||
>
|
||||
> The explorer part (mempool.space/electrs) is also not viable just yet.
|
||||
@@ -58,6 +58,7 @@ The toolkit can be used in various ways to accommodate as many needs as possible
|
||||
For more information visit: [`brk_cli`](https://crates.io/crates/brk_cli)
|
||||
- **[Crates](https://crates.io/crates/brk)** \
|
||||
Rust developers have access to a wide range crates, each built upon one another with its own specific purpose, enabling independent use and offering great flexibility.
|
||||
PRs are welcome, especially if their goal is to introduce additional datasets.
|
||||
|
||||
The primary goal of this project is to be fully-featured and accessible for everyone, regardless of their background or financial situation - whether that person is an enthusiast, researcher, miner, analyst, or simply curious.
|
||||
|
||||
@@ -76,7 +77,7 @@ In contrast, existing alternatives tend to be either [very costly](https://studi
|
||||
- [`brk_parser`](https://crates.io/crates/brk_parser): A very fast Bitcoin Core block parser and iterator built on top of bitcoin-rust
|
||||
- [`brk_query`](https://crates.io/crates/brk_query): A library that finds requested datasets.
|
||||
- [`brk_server`](https://crates.io/crates/brk_server): A server that serves Bitcoin data and swappable front-ends, built on top of `brk_indexer`, `brk_fetcher` and `brk_computer`
|
||||
- [`brk_vec`](https://crates.io/crates/brk_vec): A very small, fast, efficient and simple storable Vec.
|
||||
- [`brk_vec`](https://crates.io/crates/brk_vec): A push-only, truncable, compressable, saveable Vec
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
@@ -91,6 +92,7 @@ Heartfelt thanks go out to every donor on [Nostr](https://primal.net/p/npub1jagm
|
||||
If you'd like to have your own instance hosted for you please contact [hosting@bitcoinresearchkit.org](mailto:hosting@bitcoinresearchkit.org).
|
||||
|
||||
- 2 separate dedicated servers (1 GB/s each) with different ISPs and Cloudflare integration for enhanced performance and optimal availability
|
||||
- 99.9% SLA
|
||||
- Direct communication for feature requests and support
|
||||
- Updates delivered at your convenience
|
||||
- Optional subdomains: `*.bitcoinresearchkit.org`, `*.kibo.money` and `*.satonomics.xyz`
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<a href="https://deps.rs/crate/brk_cli">
|
||||
<img src="https://deps.rs/crate/brk_cli/latest/status.svg" alt="Dependency status">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cvrwpv3zEG">
|
||||
<a href="https://discord.gg/HaR3wpH3nr">
|
||||
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
|
||||
@@ -29,7 +29,7 @@
|
||||
<a href="https://bsky.app/profile/bitcoinresearchkit.org">
|
||||
<img src="https://img.shields.io/badge/bluesky-blue?link=https%3A%2F%2Fbsky.app%2Fprofile%2Fbitcoinresearchkit.org" alt="Bluesky" />
|
||||
</a>
|
||||
<a href="https://x.com/0xbrk">
|
||||
<a href="https://x.com/brkdotorg">
|
||||
<img src="https://img.shields.io/badge/x.com-black" alt="X" />
|
||||
</a>
|
||||
</p>
|
||||
@@ -59,16 +59,28 @@ To be determined
|
||||
- Unix based operating system (Mac OS or Linux)
|
||||
- Ubuntu users need to install `open-ssl` via `sudo apt install libssl-dev pkg-config`
|
||||
|
||||
## Install
|
||||
## Download
|
||||
|
||||
### Binaries
|
||||
|
||||
You can find a pre-built binary for your operating system on the releases page ([link](https://github.com/bitcoinresearchkit/brk/releases/latest)).
|
||||
|
||||
### Cargo
|
||||
|
||||
```bash
|
||||
# Install
|
||||
cargo install brk # or `cargo install brk_cli`, the result is the same
|
||||
|
||||
# Update
|
||||
cargo install brk # or `cargo install-update -a` if you have `cargo-update` installed
|
||||
```
|
||||
|
||||
## Update
|
||||
### Source
|
||||
|
||||
```bash
|
||||
cargo install brk # or `cargo install-update -a` if you have `cargo-update` installed
|
||||
git clone https://github.com/bitcoinresearchkit/brk.git
|
||||
cd brk/crates/brk
|
||||
cargo run -r
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -10,10 +10,10 @@ pub fn query(params: QueryParams) -> color_eyre::Result<()> {
|
||||
|
||||
let compressed = config.compressed();
|
||||
|
||||
let mut indexer = Indexer::new(config.indexeddir(), compressed, config.check_collisions())?;
|
||||
let mut indexer = Indexer::new(&config.outputsdir(), compressed, config.check_collisions())?;
|
||||
indexer.import_vecs()?;
|
||||
|
||||
let mut computer = Computer::new(config.computeddir(), config.fetcher(), compressed);
|
||||
let mut computer = Computer::new(&config.outputsdir(), config.fetcher(), compressed);
|
||||
computer.import_vecs()?;
|
||||
|
||||
let query = Query::build(&indexer, &computer);
|
||||
|
||||
+27
-16
@@ -28,12 +28,12 @@ pub fn run(config: RunConfig) -> color_eyre::Result<()> {
|
||||
|
||||
let compressed = config.compressed();
|
||||
|
||||
let mut indexer = Indexer::new(config.indexeddir(), compressed, config.check_collisions())?;
|
||||
let mut indexer = Indexer::new(&config.outputsdir(), compressed, config.check_collisions())?;
|
||||
indexer.import_stores()?;
|
||||
indexer.import_vecs()?;
|
||||
|
||||
let mut computer = Computer::new(config.computeddir(), config.fetcher(), compressed);
|
||||
computer.import_stores()?;
|
||||
let mut computer = Computer::new(&config.outputsdir(), config.fetcher(), compressed);
|
||||
computer.import_stores(&indexer)?;
|
||||
computer.import_vecs()?;
|
||||
|
||||
tokio::runtime::Builder::new_multi_thread()
|
||||
@@ -58,10 +58,28 @@ pub fn run(config: RunConfig) -> color_eyre::Result<()> {
|
||||
};
|
||||
|
||||
if config.process() {
|
||||
let wait_for_synced_node = || -> color_eyre::Result<()> {
|
||||
let is_synced = || -> color_eyre::Result<bool> {
|
||||
let info = rpc.get_blockchain_info()?;
|
||||
Ok(info.headers == info.blocks)
|
||||
};
|
||||
|
||||
if !is_synced()? {
|
||||
info!("Waiting for node to be synced...");
|
||||
while !is_synced()? {
|
||||
sleep(Duration::from_secs(1))
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
};
|
||||
|
||||
loop {
|
||||
wait_for_synced_node()?;
|
||||
|
||||
let block_count = rpc.get_block_count()?;
|
||||
|
||||
info!("{block_count} blocks found.");
|
||||
info!("{} blocks found.", block_count + 1);
|
||||
|
||||
let starting_indexes = indexer.index(&parser, rpc, &exit)?;
|
||||
|
||||
@@ -272,9 +290,10 @@ impl RunConfig {
|
||||
}
|
||||
|
||||
fn read(path: &Path) -> Self {
|
||||
fs::read_to_string(path).map_or(RunConfig::default(), |contents| {
|
||||
toml::from_str(&contents).unwrap_or_default()
|
||||
})
|
||||
fs::read_to_string(path).map_or_else(
|
||||
|_| RunConfig::default(),
|
||||
|contents| toml::from_str(&contents).unwrap_or_default(),
|
||||
)
|
||||
}
|
||||
|
||||
fn write(&self, path: &Path) -> std::io::Result<()> {
|
||||
@@ -338,18 +357,10 @@ impl RunConfig {
|
||||
.map_or_else(default_brk_path, |s| Self::fix_user_path(s.as_ref()))
|
||||
}
|
||||
|
||||
fn outputsdir(&self) -> PathBuf {
|
||||
pub fn outputsdir(&self) -> PathBuf {
|
||||
self.brkdir().join("outputs")
|
||||
}
|
||||
|
||||
pub fn indexeddir(&self) -> PathBuf {
|
||||
self.outputsdir().join("indexed")
|
||||
}
|
||||
|
||||
pub fn computeddir(&self) -> PathBuf {
|
||||
self.outputsdir().join("computed")
|
||||
}
|
||||
|
||||
pub fn harsdir(&self) -> PathBuf {
|
||||
self.outputsdir().join("hars")
|
||||
}
|
||||
|
||||
@@ -15,4 +15,5 @@ brk_logger = { workspace = true }
|
||||
brk_parser = { workspace = true }
|
||||
brk_vec = { workspace = true }
|
||||
color-eyre = { workspace = true }
|
||||
fjall = { workspace = true }
|
||||
log = { workspace = true }
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<a href="https://deps.rs/crate/brk_computer">
|
||||
<img src="https://deps.rs/crate/brk_computer/latest/status.svg" alt="Dependency status">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cvrwpv3zEG">
|
||||
<a href="https://discord.gg/HaR3wpH3nr">
|
||||
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
|
||||
@@ -29,7 +29,7 @@
|
||||
<a href="https://bsky.app/profile/bitcoinresearchkit.org">
|
||||
<img src="https://img.shields.io/badge/bluesky-blue?link=https%3A%2F%2Fbsky.app%2Fprofile%2Fbitcoinresearchkit.org" alt="Bluesky" />
|
||||
</a>
|
||||
<a href="https://x.com/0xbrk">
|
||||
<a href="https://x.com/brkdotorg">
|
||||
<img src="https://img.shields.io/badge/x.com-black" alt="X" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::dot_brk_path;
|
||||
use brk_indexer::Indexer;
|
||||
|
||||
pub fn main() -> color_eyre::Result<()> {
|
||||
color_eyre::install()?;
|
||||
|
||||
brk_logger::init(Some(Path::new(".log")));
|
||||
|
||||
let outputs_dir = dot_brk_path().join("outputs");
|
||||
// let outputs_dir = Path::new("../../_outputs");
|
||||
|
||||
let compressed = false;
|
||||
|
||||
let mut indexer = Indexer::new(outputs_dir.as_path(), compressed, true)?;
|
||||
indexer.import_stores()?;
|
||||
indexer.import_vecs()?;
|
||||
|
||||
let height_to_timestamp = &indexer.vecs().height_to_timestamp;
|
||||
|
||||
dbg!(height_to_timestamp.len());
|
||||
|
||||
// height_to_timestamp.iter().for_each(|t| {
|
||||
// dbg!(t);
|
||||
// });
|
||||
|
||||
// let index = max_from.min(A::from(self.len()));
|
||||
let mut height_to_timestamp_iter = height_to_timestamp.iter();
|
||||
// height_to_timestamp.iter().for_each(|t| {
|
||||
// dbg!(t);
|
||||
// });
|
||||
(0..2).for_each(|i| {
|
||||
dbg!(height_to_timestamp_iter.get_(i));
|
||||
});
|
||||
// for_each(|t| {
|
||||
// dbg!(t);
|
||||
// });
|
||||
// .try_for_each(|(height, timestamp)| -> Result<()> {
|
||||
// let interval = height.decremented().map_or(Timestamp::ZERO, |prev_h| {
|
||||
// dbg!((height, prev_h));
|
||||
// let prev_timestamp = height_to_timestamp_iter
|
||||
// .nth(prev_h.unwrap_to_usize())
|
||||
// .context("To work")
|
||||
// .inspect_err(|_| {
|
||||
// dbg!(prev_h);
|
||||
// })
|
||||
// .unwrap()
|
||||
// .1
|
||||
// .into_inner();
|
||||
// timestamp
|
||||
// .into_inner()
|
||||
// .checked_sub(prev_timestamp)
|
||||
// .unwrap_or(Timestamp::ZERO)
|
||||
// // Ok(())
|
||||
// });
|
||||
|
||||
// Ok(())
|
||||
// // let (i, v) = t((a, b.into_inner(), self, &mut other_iter));
|
||||
// // self.forced_push_at(i, v, exit)
|
||||
// })?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -24,16 +24,16 @@ pub fn main() -> color_eyre::Result<()> {
|
||||
|
||||
let outputs_dir = Path::new("../../_outputs");
|
||||
|
||||
let compressed = true;
|
||||
let compressed = false;
|
||||
|
||||
let mut indexer = Indexer::new(outputs_dir.join("indexed"), compressed, true)?;
|
||||
let mut indexer = Indexer::new(outputs_dir, compressed, true)?;
|
||||
indexer.import_stores()?;
|
||||
indexer.import_vecs()?;
|
||||
|
||||
let fetcher = Fetcher::import(None)?;
|
||||
|
||||
let mut computer = Computer::new(outputs_dir.join("computed"), Some(fetcher), compressed);
|
||||
computer.import_stores()?;
|
||||
let mut computer = Computer::new(outputs_dir, Some(fetcher), compressed);
|
||||
computer.import_stores(&indexer)?;
|
||||
computer.import_vecs()?;
|
||||
|
||||
let starting_indexes = indexer.index(&parser, rpc, &exit)?;
|
||||
|
||||
@@ -26,9 +26,9 @@ pub struct Computer {
|
||||
}
|
||||
|
||||
impl Computer {
|
||||
pub fn new(computed_dir: PathBuf, fetcher: Option<Fetcher>, compressed: bool) -> Self {
|
||||
pub fn new(outputs_dir: &Path, fetcher: Option<Fetcher>, compressed: bool) -> Self {
|
||||
Self {
|
||||
path: computed_dir,
|
||||
path: outputs_dir.to_owned(),
|
||||
fetcher,
|
||||
vecs: None,
|
||||
stores: None,
|
||||
@@ -38,7 +38,7 @@ impl Computer {
|
||||
|
||||
pub fn import_vecs(&mut self) -> color_eyre::Result<()> {
|
||||
self.vecs = Some(Vecs::import(
|
||||
&self.path.join("vecs"),
|
||||
&self.path.join("vecs/computed"),
|
||||
self.fetcher.is_some(),
|
||||
self.compressed,
|
||||
)?);
|
||||
@@ -47,8 +47,11 @@ impl Computer {
|
||||
|
||||
/// Do NOT import multiple times or things will break !!!
|
||||
/// Clone struct instead
|
||||
pub fn import_stores(&mut self) -> color_eyre::Result<()> {
|
||||
self.stores = Some(Stores::import(&self.path.join("stores"))?);
|
||||
pub fn import_stores(&mut self, indexer: &Indexer) -> color_eyre::Result<()> {
|
||||
self.stores = Some(Stores::import(
|
||||
&self.path.join("stores"),
|
||||
indexer.keyspace(),
|
||||
)?);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -72,10 +75,6 @@ impl Computer {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn path(&self) -> &Path {
|
||||
&self.path
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> &Vecs {
|
||||
self.vecs.as_ref().unwrap()
|
||||
}
|
||||
|
||||
@@ -1,25 +1,31 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{AddressindexTxoutindex, Unit};
|
||||
use brk_indexer::Store;
|
||||
use brk_vec::Version;
|
||||
use fjall::TransactionalKeyspace;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Stores {
|
||||
pub address_to_utxos_received: Store<AddressindexTxoutindex, Unit>,
|
||||
pub address_to_utxos_spent: Store<AddressindexTxoutindex, Unit>,
|
||||
// pub address_to_utxos_received: Store<AddressIndexOutputIndex, Unit>,
|
||||
// pub address_to_utxos_spent: Store<AddressIndexOutputIndex, Unit>,
|
||||
}
|
||||
|
||||
impl Stores {
|
||||
pub fn import(path: &Path) -> color_eyre::Result<Self> {
|
||||
let address_to_utxos_received =
|
||||
Store::import(&path.join("address_to_utxos_received"), Version::ONE)?;
|
||||
let address_to_utxos_spent =
|
||||
Store::import(&path.join("address_to_utxos_spent"), Version::ONE)?;
|
||||
pub fn import(_: &Path, _: &TransactionalKeyspace) -> color_eyre::Result<Self> {
|
||||
// let address_to_utxos_received = Store::import(
|
||||
// keyspace.clone(),
|
||||
// path,
|
||||
// "address_to_utxos_received",
|
||||
// Version::ZERO,
|
||||
// )?;
|
||||
// let address_to_utxos_spent = Store::import(
|
||||
// keyspace.clone(),
|
||||
// path,
|
||||
// "address_to_utxos_spent",
|
||||
// Version::ZERO,
|
||||
// )?;
|
||||
|
||||
Ok(Self {
|
||||
address_to_utxos_received,
|
||||
address_to_utxos_spent,
|
||||
// address_to_utxos_received,
|
||||
// address_to_utxos_spent,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,330 +0,0 @@
|
||||
use core::error;
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
fmt::Debug,
|
||||
io,
|
||||
ops::{Add, Sub},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use brk_core::CheckedSub;
|
||||
use brk_exit::Exit;
|
||||
use brk_vec::{AnyStorableVec, Compressed, Error, Result, StoredIndex, StoredType, Version};
|
||||
|
||||
const FLUSH_EVERY: usize = 10_000;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StorableVec<I, T> {
|
||||
computed_version: Option<Version>,
|
||||
vec: brk_vec::StorableVec<I, T>,
|
||||
}
|
||||
|
||||
impl<I, T> StorableVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
version: Version,
|
||||
compressed: Compressed,
|
||||
) -> brk_vec::Result<Self> {
|
||||
let vec = brk_vec::StorableVec::forced_import(path, version, compressed)?;
|
||||
|
||||
Ok(Self {
|
||||
computed_version: None,
|
||||
vec,
|
||||
})
|
||||
}
|
||||
|
||||
fn safe_truncate_if_needed(&mut self, index: I, exit: &Exit) -> Result<()> {
|
||||
if exit.triggered() {
|
||||
return Ok(());
|
||||
}
|
||||
exit.block();
|
||||
self.vec.truncate_if_needed(index)?;
|
||||
exit.release();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn forced_push_at(&mut self, index: I, value: T, exit: &Exit) -> Result<()> {
|
||||
match self.len().cmp(&index.to_usize()?) {
|
||||
Ordering::Less => {
|
||||
return Err(Error::IndexTooHigh);
|
||||
}
|
||||
ord => {
|
||||
if ord == Ordering::Greater {
|
||||
self.safe_truncate_if_needed(index, exit)?;
|
||||
}
|
||||
self.vec.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
if self.vec.pushed_len() >= FLUSH_EVERY {
|
||||
Ok(self.safe_flush(exit)?)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn safe_flush(&mut self, exit: &Exit) -> io::Result<()> {
|
||||
if exit.triggered() {
|
||||
return Ok(());
|
||||
}
|
||||
exit.block();
|
||||
self.vec.flush()?;
|
||||
exit.release();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn version(&self) -> Version {
|
||||
self.vec.version()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.vec.len()
|
||||
}
|
||||
|
||||
pub fn vec(&self) -> &brk_vec::StorableVec<I, T> {
|
||||
&self.vec
|
||||
}
|
||||
|
||||
pub fn mut_vec(&mut self) -> &mut brk_vec::StorableVec<I, T> {
|
||||
&mut self.vec
|
||||
}
|
||||
|
||||
pub fn any_vec(&self) -> &dyn AnyStorableVec {
|
||||
&self.vec
|
||||
}
|
||||
|
||||
pub fn mut_any_vec(&mut self) -> &mut dyn AnyStorableVec {
|
||||
&mut self.vec
|
||||
}
|
||||
|
||||
pub fn get(&mut self, index: I) -> Result<Option<&T>> {
|
||||
self.vec.get(index)
|
||||
}
|
||||
|
||||
pub fn collect_range(&self, from: Option<i64>, to: Option<i64>) -> Result<Vec<T>> {
|
||||
self.vec.collect_range(from, to)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn path_computed_version(&self) -> PathBuf {
|
||||
self.vec.path().join("computed_version")
|
||||
}
|
||||
|
||||
fn validate_computed_version_or_reset_file(&mut self, version: Version) -> Result<()> {
|
||||
let path = self.path_computed_version();
|
||||
if version.validate(path.as_ref()).is_err() {
|
||||
self.vec.reset()?;
|
||||
}
|
||||
version.write(path.as_ref())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute_transform<A, B, F>(
|
||||
&mut self,
|
||||
max_from: A,
|
||||
other: &mut brk_vec::StorableVec<A, B>,
|
||||
mut t: F,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
A: StoredIndex,
|
||||
B: StoredType,
|
||||
F: FnMut((A, B, &mut Self, &mut brk_vec::StorableVec<A, B>)) -> (I, T),
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + other.version(),
|
||||
)?;
|
||||
|
||||
let index = max_from.min(A::from(self.len()));
|
||||
other.iter_from_cloned(index, |(a, b, other)| {
|
||||
let (i, v) = t((a, b, self, other));
|
||||
self.forced_push_at(i, v, exit)
|
||||
})?;
|
||||
|
||||
Ok(self.safe_flush(exit)?)
|
||||
}
|
||||
|
||||
pub fn compute_inverse_more_to_less(
|
||||
&mut self,
|
||||
max_from: T,
|
||||
other: &mut brk_vec::StorableVec<T, I>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
I: StoredType + StoredIndex,
|
||||
T: StoredIndex,
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + other.version(),
|
||||
)?;
|
||||
|
||||
let index = max_from.min(self.vec.get_last()?.cloned().unwrap_or_default());
|
||||
other.iter_from(index, |(v, i, ..)| {
|
||||
let i = *i;
|
||||
if self.get(i).unwrap().is_none_or(|old_v| *old_v > v) {
|
||||
self.forced_push_at(i, v, exit)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(self.safe_flush(exit)?)
|
||||
}
|
||||
|
||||
pub fn compute_inverse_less_to_more(
|
||||
&mut self,
|
||||
max_from: T,
|
||||
first_indexes: &mut brk_vec::StorableVec<T, I>,
|
||||
last_indexes: &mut brk_vec::StorableVec<T, I>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
I: StoredType,
|
||||
T: StoredIndex,
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + first_indexes.version() + last_indexes.version(),
|
||||
)?;
|
||||
|
||||
let index = max_from.min(T::from(self.len()));
|
||||
first_indexes.iter_from(index, |(value, first_index, ..)| {
|
||||
let first_index = (first_index).to_usize()?;
|
||||
let last_index = (last_indexes.get(value)?.unwrap()).to_usize()?;
|
||||
(first_index..last_index)
|
||||
.try_for_each(|index| self.forced_push_at(I::from(index), value, exit))
|
||||
})?;
|
||||
|
||||
Ok(self.safe_flush(exit)?)
|
||||
}
|
||||
|
||||
pub fn compute_last_index_from_first(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
first_indexes: &mut brk_vec::StorableVec<I, T>,
|
||||
final_len: usize,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
T: Copy + From<usize> + CheckedSub<T> + StoredIndex,
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + first_indexes.version(),
|
||||
)?;
|
||||
|
||||
let index = max_from.min(I::from(self.len()));
|
||||
let one = T::from(1);
|
||||
let mut prev_index: Option<I> = None;
|
||||
first_indexes.iter_from(index, |(i, v, ..)| {
|
||||
if let Some(prev_index) = prev_index.take() {
|
||||
self.forced_push_at(prev_index, v.checked_sub(one).unwrap(), exit)?;
|
||||
}
|
||||
prev_index.replace(i);
|
||||
Ok(())
|
||||
})?;
|
||||
if let Some(prev_index) = prev_index {
|
||||
self.forced_push_at(
|
||||
prev_index,
|
||||
T::from(final_len).checked_sub(one).unwrap(),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(self.safe_flush(exit)?)
|
||||
}
|
||||
|
||||
pub fn compute_count_from_indexes<T2>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
first_indexes: &mut brk_vec::StorableVec<I, T2>,
|
||||
last_indexes: &mut brk_vec::StorableVec<I, T2>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
T: From<T2>,
|
||||
T2: StoredType + Copy + Add<usize, Output = T2> + CheckedSub<T2> + TryInto<T> + Default,
|
||||
<T2 as TryInto<T>>::Error: error::Error + 'static,
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + first_indexes.version() + last_indexes.version(),
|
||||
)?;
|
||||
|
||||
let index = max_from.min(I::from(self.len()));
|
||||
first_indexes.iter_from(index, |(i, first_index, ..)| {
|
||||
let last_index = last_indexes.get(i)?.unwrap();
|
||||
let count = (*last_index + 1_usize)
|
||||
.checked_sub(*first_index)
|
||||
.unwrap_or_default();
|
||||
self.forced_push_at(i, count.into(), exit)
|
||||
})?;
|
||||
|
||||
Ok(self.safe_flush(exit)?)
|
||||
}
|
||||
|
||||
pub fn compute_is_first_ordered<A>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
self_to_other: &mut brk_vec::StorableVec<I, A>,
|
||||
other_to_self: &mut brk_vec::StorableVec<A, I>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
I: StoredType,
|
||||
T: From<bool>,
|
||||
A: StoredIndex + StoredType,
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + self_to_other.version() + other_to_self.version(),
|
||||
)?;
|
||||
|
||||
let index = max_from.min(I::from(self.len()));
|
||||
self_to_other.iter_from(index, |(i, other, ..)| {
|
||||
self.forced_push_at(i, T::from(other_to_self.get(*other)?.unwrap() == &i), exit)
|
||||
})?;
|
||||
|
||||
Ok(self.safe_flush(exit)?)
|
||||
}
|
||||
|
||||
pub fn compute_sum_from_indexes<T2>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
first_indexes: &mut brk_vec::StorableVec<I, T2>,
|
||||
last_indexes: &mut brk_vec::StorableVec<I, T2>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
T: From<T2>,
|
||||
T2: StoredType + Copy + Add<usize, Output = T2> + Sub<T2, Output = T2> + TryInto<T>,
|
||||
<T2 as TryInto<T>>::Error: error::Error + 'static,
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + first_indexes.version() + last_indexes.version(),
|
||||
)?;
|
||||
|
||||
let index = max_from.min(I::from(self.len()));
|
||||
first_indexes.iter_from(index, |(index, first_index, ..)| {
|
||||
let last_index = last_indexes.get(index)?.unwrap();
|
||||
let count = *last_index + 1_usize - *first_index;
|
||||
self.forced_push_at(index, count.into(), exit)
|
||||
})?;
|
||||
|
||||
Ok(self.safe_flush(exit)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> Clone for StorableVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
computed_version: self.computed_version,
|
||||
vec: self.vec.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,32 @@
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use brk_core::{CheckedSub, Dateindex, Height, Timestamp};
|
||||
use brk_core::{
|
||||
CheckedSub, DifficultyEpoch, HalvingEpoch, Height, StoredU32, StoredU64, StoredUsize,
|
||||
Timestamp, Weight,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyStorableVec, Compressed, Version};
|
||||
use brk_parser::bitcoin;
|
||||
use brk_vec::{Compressed, Version};
|
||||
|
||||
use super::{
|
||||
Indexes, StorableVec, indexes,
|
||||
stats::{StorableVecGeneatorOptions, StorableVecsStatsFromHeight},
|
||||
EagerVec, Indexes,
|
||||
grouped::{ComputedVecsFromDateindex, ComputedVecsFromHeight, StorableVecGeneatorOptions},
|
||||
indexes,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vecs {
|
||||
pub height_to_block_interval: StorableVec<Height, Timestamp>,
|
||||
pub indexes_to_block_interval_stats: StorableVecsStatsFromHeight<Timestamp>,
|
||||
pub dateindex_to_block_count: StorableVec<Dateindex, u16>,
|
||||
pub dateindex_to_total_block_count: StorableVec<Dateindex, u32>,
|
||||
pub height_to_interval: EagerVec<Height, Timestamp>,
|
||||
pub height_to_vbytes: EagerVec<Height, StoredU64>,
|
||||
pub difficultyepoch_to_timestamp: EagerVec<DifficultyEpoch, Timestamp>,
|
||||
pub halvingepoch_to_timestamp: EagerVec<HalvingEpoch, Timestamp>,
|
||||
pub timeindexes_to_timestamp: ComputedVecsFromDateindex<Timestamp>,
|
||||
pub indexes_to_block_count: ComputedVecsFromHeight<StoredU32>,
|
||||
pub indexes_to_block_interval: ComputedVecsFromHeight<Timestamp>,
|
||||
pub indexes_to_block_size: ComputedVecsFromHeight<StoredUsize>,
|
||||
pub indexes_to_block_vbytes: ComputedVecsFromHeight<StoredU64>,
|
||||
pub indexes_to_block_weight: ComputedVecsFromHeight<Weight>,
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
@@ -23,27 +34,74 @@ impl Vecs {
|
||||
fs::create_dir_all(path)?;
|
||||
|
||||
Ok(Self {
|
||||
height_to_block_interval: StorableVec::forced_import(
|
||||
&path.join("height_to_block_interval"),
|
||||
Version::ONE,
|
||||
height_to_interval: EagerVec::forced_import(
|
||||
&path.join("height_to_interval"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
indexes_to_block_interval_stats: StorableVecsStatsFromHeight::forced_import(
|
||||
&path.join("block_interval"),
|
||||
timeindexes_to_timestamp: ComputedVecsFromDateindex::forced_import(
|
||||
path,
|
||||
"timestamp",
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_first(),
|
||||
)?,
|
||||
indexes_to_block_interval: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"block_interval",
|
||||
false,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_percentiles()
|
||||
.add_minmax()
|
||||
.add_average(),
|
||||
)?,
|
||||
dateindex_to_block_count: StorableVec::forced_import(
|
||||
&path.join("dateindex_to_block_count"),
|
||||
Version::ONE,
|
||||
indexes_to_block_count: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"block_count",
|
||||
true,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_sum().add_total(),
|
||||
)?,
|
||||
indexes_to_block_weight: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"block_weight",
|
||||
false,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_sum().add_total(),
|
||||
)?,
|
||||
indexes_to_block_size: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"block_size",
|
||||
false,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_sum().add_total(),
|
||||
)?,
|
||||
height_to_vbytes: EagerVec::forced_import(
|
||||
&path.join("height_to_vbytes"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
dateindex_to_total_block_count: StorableVec::forced_import(
|
||||
&path.join("dateindex_to_total_block_count"),
|
||||
Version::ONE,
|
||||
indexes_to_block_vbytes: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"block_vbytes",
|
||||
false,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_sum().add_total(),
|
||||
)?,
|
||||
difficultyepoch_to_timestamp: EagerVec::forced_import(
|
||||
&path.join("difficultyepoch_to_timestamp"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
halvingepoch_to_timestamp: EagerVec::forced_import(
|
||||
&path.join("halvingepoch_to_timestamp"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
})
|
||||
@@ -51,19 +109,52 @@ impl Vecs {
|
||||
|
||||
pub fn compute(
|
||||
&mut self,
|
||||
indexer: &mut Indexer,
|
||||
indexes: &mut indexes::Vecs,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
let indexer_vecs = indexer.mut_vecs();
|
||||
self.timeindexes_to_timestamp.compute(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|vec, _, indexes, starting_indexes, exit| {
|
||||
vec.compute_transform(
|
||||
starting_indexes.dateindex,
|
||||
indexes.dateindex_to_date.vec(),
|
||||
|(di, d, ..)| (di, Timestamp::from(d)),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
self.height_to_block_interval.compute_transform(
|
||||
self.indexes_to_block_count.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, indexer, _, starting_indexes, exit| {
|
||||
let indexer_vecs = indexer.vecs();
|
||||
|
||||
v.compute_range(
|
||||
starting_indexes.height,
|
||||
indexer_vecs.height_to_weight.vec(),
|
||||
|h| (h, StoredU32::from(1_u32)),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
let indexer_vecs = indexer.vecs();
|
||||
|
||||
let mut height_to_timestamp_iter = indexer_vecs.height_to_timestamp.iter();
|
||||
self.height_to_interval.compute_transform(
|
||||
starting_indexes.height,
|
||||
indexer_vecs.height_to_timestamp.mut_vec(),
|
||||
|(height, timestamp, _, height_to_timestamp)| {
|
||||
indexer_vecs.height_to_timestamp.vec(),
|
||||
|(height, timestamp, ..)| {
|
||||
let interval = height.decremented().map_or(Timestamp::ZERO, |prev_h| {
|
||||
let prev_timestamp = *height_to_timestamp.get(prev_h).unwrap().unwrap();
|
||||
let prev_timestamp = height_to_timestamp_iter.unwrap_get_inner(prev_h);
|
||||
timestamp
|
||||
.checked_sub(prev_timestamp)
|
||||
.unwrap_or(Timestamp::ZERO)
|
||||
@@ -73,24 +164,79 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.indexes_to_block_interval_stats.compute(
|
||||
&mut self.height_to_block_interval,
|
||||
self.indexes_to_block_interval.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(self.height_to_interval.vec()),
|
||||
)?;
|
||||
|
||||
self.indexes_to_block_weight.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(indexer_vecs.height_to_weight.vec()),
|
||||
)?;
|
||||
|
||||
self.indexes_to_block_size.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(indexer_vecs.height_to_total_size.vec()),
|
||||
)?;
|
||||
|
||||
self.height_to_vbytes.compute_transform(
|
||||
starting_indexes.height,
|
||||
indexer_vecs.height_to_weight.vec(),
|
||||
|(h, w, ..)| {
|
||||
(
|
||||
h,
|
||||
StoredU64::from(bitcoin::Weight::from(w).to_vbytes_floor()),
|
||||
)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.indexes_to_block_vbytes.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(self.height_to_vbytes.vec()),
|
||||
)?;
|
||||
|
||||
let mut height_to_timestamp_iter = indexer_vecs.height_to_timestamp.iter();
|
||||
|
||||
self.difficultyepoch_to_timestamp.compute_transform(
|
||||
starting_indexes.difficultyepoch,
|
||||
indexes.difficultyepoch_to_first_height.vec(),
|
||||
|(i, h, ..)| (i, height_to_timestamp_iter.get(h).unwrap().1.into_inner()),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.halvingepoch_to_timestamp.compute_transform(
|
||||
starting_indexes.halvingepoch,
|
||||
indexes.halvingepoch_to_first_height.vec(),
|
||||
|(i, h, ..)| (i, height_to_timestamp_iter.get(h).unwrap().1.into_inner()),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn brk_vec::AnyStoredVec> {
|
||||
[
|
||||
vec![
|
||||
self.height_to_block_interval.any_vec(),
|
||||
self.dateindex_to_block_count.any_vec(),
|
||||
self.dateindex_to_total_block_count.any_vec(),
|
||||
self.height_to_interval.any_vec(),
|
||||
self.height_to_vbytes.any_vec(),
|
||||
self.difficultyepoch_to_timestamp.any_vec(),
|
||||
self.halvingepoch_to_timestamp.any_vec(),
|
||||
],
|
||||
self.indexes_to_block_interval_stats.as_any_vecs(),
|
||||
self.timeindexes_to_timestamp.any_vecs(),
|
||||
self.indexes_to_block_count.any_vecs(),
|
||||
self.indexes_to_block_interval.any_vecs(),
|
||||
self.indexes_to_block_size.any_vecs(),
|
||||
self.indexes_to_block_vbytes.any_vecs(),
|
||||
self.indexes_to_block_weight.any_vecs(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,789 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{CheckedSub, StoredUsize};
|
||||
use brk_exit::Exit;
|
||||
use brk_vec::{Compressed, DynamicVec, Result, StoredIndex, StoredType, StoredVec, Version};
|
||||
use color_eyre::eyre::ContextCompat;
|
||||
|
||||
use crate::storage::{ComputedType, EagerVec};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ComputedVecBuilder<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: ComputedType,
|
||||
{
|
||||
first: Option<EagerVec<I, T>>,
|
||||
average: Option<EagerVec<I, T>>,
|
||||
sum: Option<EagerVec<I, T>>,
|
||||
max: Option<EagerVec<I, T>>,
|
||||
_90p: Option<EagerVec<I, T>>,
|
||||
_75p: Option<EagerVec<I, T>>,
|
||||
median: Option<EagerVec<I, T>>,
|
||||
_25p: Option<EagerVec<I, T>>,
|
||||
_10p: Option<EagerVec<I, T>>,
|
||||
min: Option<EagerVec<I, T>>,
|
||||
last: Option<EagerVec<I, T>>,
|
||||
total: Option<EagerVec<I, T>>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<I, T> ComputedVecBuilder<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: ComputedType,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
version: Version,
|
||||
compressed: Compressed,
|
||||
options: StorableVecGeneatorOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let key = I::to_string().split("::").last().unwrap().to_lowercase();
|
||||
|
||||
let only_one_active = options.is_only_one_active();
|
||||
|
||||
let default = || path.join(format!("{key}_to_{name}"));
|
||||
|
||||
let prefix = |s: &str| path.join(format!("{key}_to_{s}_{name}"));
|
||||
|
||||
let maybe_prefix = |s: &str| {
|
||||
if only_one_active {
|
||||
default()
|
||||
} else {
|
||||
prefix(s)
|
||||
}
|
||||
};
|
||||
|
||||
let suffix = |s: &str| path.join(format!("{key}_to_{name}_{s}"));
|
||||
|
||||
let maybe_suffix = |s: &str| {
|
||||
if only_one_active {
|
||||
default()
|
||||
} else {
|
||||
suffix(s)
|
||||
}
|
||||
};
|
||||
|
||||
let version = VERSION + version;
|
||||
|
||||
let s = Self {
|
||||
first: options.first.then(|| {
|
||||
EagerVec::forced_import(&maybe_prefix("first"), version + Version::ZERO, compressed)
|
||||
.unwrap()
|
||||
}),
|
||||
last: options.last.then(|| {
|
||||
EagerVec::forced_import(
|
||||
&path.join(format!("{key}_to_{name}")),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
min: options.min.then(|| {
|
||||
EagerVec::forced_import(&maybe_suffix("min"), version + Version::ZERO, compressed)
|
||||
.unwrap()
|
||||
}),
|
||||
max: options.max.then(|| {
|
||||
EagerVec::forced_import(&maybe_suffix("max"), version + Version::ZERO, compressed)
|
||||
.unwrap()
|
||||
}),
|
||||
median: options.median.then(|| {
|
||||
EagerVec::forced_import(
|
||||
&maybe_suffix("median"),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
average: options.average.then(|| {
|
||||
EagerVec::forced_import(
|
||||
&maybe_suffix("average"),
|
||||
version + Version::ZERO,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
sum: options.sum.then(|| {
|
||||
EagerVec::forced_import(&maybe_suffix("sum"), version + Version::ZERO, compressed)
|
||||
.unwrap()
|
||||
}),
|
||||
total: options.total.then(|| {
|
||||
EagerVec::forced_import(&prefix("total"), version + Version::ZERO, compressed)
|
||||
.unwrap()
|
||||
}),
|
||||
_90p: options._90p.then(|| {
|
||||
EagerVec::forced_import(&maybe_suffix("90p"), version + Version::ZERO, compressed)
|
||||
.unwrap()
|
||||
}),
|
||||
_75p: options._75p.then(|| {
|
||||
EagerVec::forced_import(&maybe_suffix("75p"), version + Version::ZERO, compressed)
|
||||
.unwrap()
|
||||
}),
|
||||
_25p: options._25p.then(|| {
|
||||
EagerVec::forced_import(&maybe_suffix("25p"), version + Version::ZERO, compressed)
|
||||
.unwrap()
|
||||
}),
|
||||
_10p: options._10p.then(|| {
|
||||
EagerVec::forced_import(&maybe_suffix("10p"), version + Version::ZERO, compressed)
|
||||
.unwrap()
|
||||
}),
|
||||
};
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
pub fn extend(&mut self, max_from: I, source: &StoredVec<I, T>, exit: &Exit) -> Result<()> {
|
||||
if self.total.is_none() {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let index = self.starting_index(max_from);
|
||||
|
||||
let total_vec = self.total.as_mut().unwrap();
|
||||
|
||||
let mut total = index.decremented().map_or(T::from(0_usize), |index| {
|
||||
total_vec.iter().unwrap_get_inner(index)
|
||||
});
|
||||
source.iter_at(index).try_for_each(|(i, v)| -> Result<()> {
|
||||
total = total.clone() + v.into_inner();
|
||||
total_vec.forced_push_at(i, total.clone(), exit)
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute<I2>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
source: &StoredVec<I2, T>,
|
||||
first_indexes: &StoredVec<I, I2>,
|
||||
count_indexes: &StoredVec<I, StoredUsize>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
I2: StoredIndex + StoredType + CheckedSub<I2>,
|
||||
{
|
||||
let index = self.starting_index(max_from);
|
||||
|
||||
let mut count_indexes_iter = count_indexes.iter();
|
||||
let mut source_iter = source.iter();
|
||||
|
||||
let total_vec = self.total.as_mut();
|
||||
|
||||
let mut total = total_vec.map(|total_vec| {
|
||||
index.decremented().map_or(T::from(0_usize), |index| {
|
||||
total_vec.iter().unwrap_get_inner(index)
|
||||
})
|
||||
});
|
||||
|
||||
first_indexes
|
||||
.iter_at(index)
|
||||
.try_for_each(|(i, first_index)| -> Result<()> {
|
||||
let first_index = first_index.into_inner();
|
||||
|
||||
let count_index = count_indexes_iter.get(i).unwrap().1.into_inner();
|
||||
|
||||
if let Some(first) = self.first.as_mut() {
|
||||
let f = source_iter
|
||||
.get(first_index)
|
||||
.map_or(T::from(0_usize), |f| f.1.into_inner());
|
||||
first.forced_push_at(index, f, exit)?;
|
||||
}
|
||||
|
||||
if let Some(last) = self.last.as_mut() {
|
||||
let count_index = *count_index;
|
||||
if count_index == 0 {
|
||||
panic!("should compute last if count can be 0")
|
||||
}
|
||||
let last_index = first_index + (count_index - 1);
|
||||
let v = source_iter
|
||||
.get(last_index)
|
||||
.context("to work")
|
||||
.inspect_err(|_| {
|
||||
dbg!(first_index, count_index, last_index);
|
||||
})
|
||||
.unwrap()
|
||||
.1
|
||||
.into_inner();
|
||||
last.forced_push_at(index, v, exit)?;
|
||||
}
|
||||
|
||||
let needs_sum_or_total = self.sum.is_some() || self.total.is_some();
|
||||
let needs_average_sum_or_total = needs_sum_or_total || self.average.is_some();
|
||||
let needs_sorted = self.max.is_some()
|
||||
|| self._90p.is_some()
|
||||
|| self._75p.is_some()
|
||||
|| self.median.is_some()
|
||||
|| self._25p.is_some()
|
||||
|| self._10p.is_some()
|
||||
|| self.min.is_some();
|
||||
let needs_values = needs_sorted || needs_average_sum_or_total;
|
||||
|
||||
if needs_values {
|
||||
source_iter.set(first_index);
|
||||
let mut values = (&mut source_iter)
|
||||
.take(*count_index)
|
||||
.map(|(_, v)| v.into_inner())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if needs_sorted {
|
||||
values.sort_unstable();
|
||||
|
||||
if let Some(max) = self.max.as_mut() {
|
||||
max.forced_push_at(
|
||||
i,
|
||||
values
|
||||
.last()
|
||||
.context("expect some")
|
||||
.inspect_err(|_| {
|
||||
dbg!(
|
||||
&values,
|
||||
max.path(),
|
||||
first_indexes.path(),
|
||||
first_index,
|
||||
count_indexes.path(),
|
||||
count_index,
|
||||
source.len(),
|
||||
source.path()
|
||||
);
|
||||
})
|
||||
.unwrap()
|
||||
.clone(),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(_90p) = self._90p.as_mut() {
|
||||
_90p.forced_push_at(i, Self::get_percentile(&values, 0.90), exit)?;
|
||||
}
|
||||
|
||||
if let Some(_75p) = self._75p.as_mut() {
|
||||
_75p.forced_push_at(i, Self::get_percentile(&values, 0.75), exit)?;
|
||||
}
|
||||
|
||||
if let Some(median) = self.median.as_mut() {
|
||||
median.forced_push_at(i, Self::get_percentile(&values, 0.50), exit)?;
|
||||
}
|
||||
|
||||
if let Some(_25p) = self._25p.as_mut() {
|
||||
_25p.forced_push_at(i, Self::get_percentile(&values, 0.25), exit)?;
|
||||
}
|
||||
|
||||
if let Some(_10p) = self._10p.as_mut() {
|
||||
_10p.forced_push_at(i, Self::get_percentile(&values, 0.10), exit)?;
|
||||
}
|
||||
|
||||
if let Some(min) = self.min.as_mut() {
|
||||
min.forced_push_at(i, values.first().unwrap().clone(), exit)?;
|
||||
}
|
||||
}
|
||||
|
||||
if needs_average_sum_or_total {
|
||||
let len = values.len();
|
||||
let sum = values.into_iter().fold(T::from(0), |a, b| a + b);
|
||||
|
||||
if let Some(average) = self.average.as_mut() {
|
||||
let avg = sum.clone() / len;
|
||||
average.forced_push_at(i, avg, exit)?;
|
||||
}
|
||||
|
||||
if needs_sum_or_total {
|
||||
if let Some(sum_vec) = self.sum.as_mut() {
|
||||
sum_vec.forced_push_at(i, sum.clone(), exit)?;
|
||||
}
|
||||
|
||||
if let Some(total_vec) = self.total.as_mut() {
|
||||
let t = total.as_ref().unwrap().clone() + sum;
|
||||
total.replace(t.clone());
|
||||
total_vec.forced_push_at(i, t, exit)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
pub fn from_aligned<I2>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
source: &ComputedVecBuilder<I2, T>,
|
||||
first_indexes: &StoredVec<I, I2>,
|
||||
count_indexes: &StoredVec<I, StoredUsize>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
I2: StoredIndex + StoredType + CheckedSub<I2>,
|
||||
{
|
||||
if self._90p.is_some()
|
||||
|| self._75p.is_some()
|
||||
|| self.median.is_some()
|
||||
|| self._25p.is_some()
|
||||
|| self._10p.is_some()
|
||||
{
|
||||
panic!("unsupported");
|
||||
}
|
||||
|
||||
let index = self.starting_index(max_from);
|
||||
|
||||
let mut count_indexes_iter = count_indexes.iter();
|
||||
|
||||
let mut source_first_iter = source.first.as_ref().map(|f| f.iter());
|
||||
let mut source_last_iter = source.last.as_ref().map(|f| f.iter());
|
||||
let mut source_max_iter = source.max.as_ref().map(|f| f.iter());
|
||||
let mut source_min_iter = source.min.as_ref().map(|f| f.iter());
|
||||
let mut source_average_iter = source.average.as_ref().map(|f| f.iter());
|
||||
let mut source_sum_iter = source.sum.as_ref().map(|f| f.iter());
|
||||
|
||||
let mut total = self.total.as_mut().map(|total_vec| {
|
||||
index.decremented().map_or(T::from(0_usize), |index| {
|
||||
total_vec.iter().unwrap_get_inner(index)
|
||||
})
|
||||
});
|
||||
|
||||
first_indexes
|
||||
.iter_at(index)
|
||||
.try_for_each(|(i, first_index, ..)| -> Result<()> {
|
||||
let first_index = first_index.into_inner();
|
||||
|
||||
let count_index = count_indexes_iter.get(i).unwrap().1.into_inner();
|
||||
|
||||
if let Some(first) = self.first.as_mut() {
|
||||
let v = source_first_iter
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.unwrap_get_inner(first_index);
|
||||
first.forced_push_at(index, v, exit)?;
|
||||
}
|
||||
|
||||
if let Some(last) = self.last.as_mut() {
|
||||
let count_index = *count_index;
|
||||
if count_index == 0 {
|
||||
panic!("should compute last if count can be 0")
|
||||
}
|
||||
let last_index = first_index + (count_index - 1);
|
||||
let v = source_last_iter
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.unwrap_get_inner(last_index);
|
||||
last.forced_push_at(index, v, exit)?;
|
||||
}
|
||||
|
||||
let needs_sum_or_total = self.sum.is_some() || self.total.is_some();
|
||||
let needs_average_sum_or_total = needs_sum_or_total || self.average.is_some();
|
||||
let needs_sorted = self.max.is_some() || self.min.is_some();
|
||||
let needs_values = needs_sorted || needs_average_sum_or_total;
|
||||
|
||||
if needs_values {
|
||||
if needs_sorted {
|
||||
if let Some(max) = self.max.as_mut() {
|
||||
let source_max_iter = source_max_iter.as_mut().unwrap();
|
||||
source_max_iter.set(first_index);
|
||||
let mut values = source_max_iter
|
||||
.take(*count_index)
|
||||
.map(|(_, v)| v.into_inner())
|
||||
.collect::<Vec<_>>();
|
||||
values.sort_unstable();
|
||||
max.forced_push_at(i, values.last().unwrap().clone(), exit)?;
|
||||
}
|
||||
|
||||
if let Some(min) = self.min.as_mut() {
|
||||
let source_min_iter = source_min_iter.as_mut().unwrap();
|
||||
source_min_iter.set(first_index);
|
||||
let mut values = source_min_iter
|
||||
.take(*count_index)
|
||||
.map(|(_, v)| v.into_inner())
|
||||
.collect::<Vec<_>>();
|
||||
values.sort_unstable();
|
||||
min.forced_push_at(i, values.first().unwrap().clone(), exit)?;
|
||||
}
|
||||
}
|
||||
|
||||
if needs_average_sum_or_total {
|
||||
if let Some(average) = self.average.as_mut() {
|
||||
let source_average_iter = source_average_iter.as_mut().unwrap();
|
||||
source_average_iter.set(first_index);
|
||||
let values = source_average_iter
|
||||
.take(*count_index)
|
||||
.map(|(_, v)| v.into_inner())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let len = values.len();
|
||||
let total = values.into_iter().fold(T::from(0), |a, b| a + b);
|
||||
// TODO: Multiply by count then divide by total
|
||||
// Right now it's not 100% accurate as there could be more or less elements in the lower timeframe (28 days vs 31 days in a month for example)
|
||||
let avg = total / len;
|
||||
average.forced_push_at(i, avg, exit)?;
|
||||
}
|
||||
|
||||
if needs_sum_or_total {
|
||||
let source_sum_iter = source_sum_iter.as_mut().unwrap();
|
||||
source_sum_iter.set(first_index);
|
||||
let values = source_sum_iter
|
||||
.take(*count_index)
|
||||
.map(|(_, v)| v.into_inner())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let sum = values.into_iter().fold(T::from(0), |a, b| a + b);
|
||||
|
||||
if let Some(sum_vec) = self.sum.as_mut() {
|
||||
sum_vec.forced_push_at(i, sum.clone(), exit)?;
|
||||
}
|
||||
|
||||
if let Some(total_vec) = self.total.as_mut() {
|
||||
let t = total.as_ref().unwrap().clone() + sum;
|
||||
total.replace(t.clone());
|
||||
total_vec.forced_push_at(i, t, exit)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_percentile(sorted: &[T], percentile: f64) -> T {
|
||||
let len = sorted.len();
|
||||
|
||||
if len == 0 {
|
||||
panic!();
|
||||
} else if len == 1 {
|
||||
sorted[0].clone()
|
||||
} else {
|
||||
let index = (len - 1) as f64 * percentile;
|
||||
|
||||
let fract = index.fract();
|
||||
|
||||
if fract != 0.0 {
|
||||
let left = sorted.get(index as usize).unwrap().clone();
|
||||
let right = sorted.get(index.ceil() as usize).unwrap().clone();
|
||||
left / 2 + right / 2
|
||||
} else {
|
||||
sorted.get(index as usize).unwrap().clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn starting_index(&self, max_from: I) -> I {
|
||||
max_from.min(I::from(
|
||||
self.any_vecs().into_iter().map(|v| v.len()).min().unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn unwrap_first(&mut self) -> &mut EagerVec<I, T> {
|
||||
self.first.as_mut().unwrap()
|
||||
}
|
||||
pub fn unwrap_average(&mut self) -> &mut EagerVec<I, T> {
|
||||
self.average.as_mut().unwrap()
|
||||
}
|
||||
pub fn unwrap_sum(&mut self) -> &mut EagerVec<I, T> {
|
||||
self.sum.as_mut().unwrap()
|
||||
}
|
||||
pub fn unwrap_max(&mut self) -> &mut EagerVec<I, T> {
|
||||
self.max.as_mut().unwrap()
|
||||
}
|
||||
pub fn unwrap_90p(&mut self) -> &mut EagerVec<I, T> {
|
||||
self._90p.as_mut().unwrap()
|
||||
}
|
||||
pub fn unwrap_75p(&mut self) -> &mut EagerVec<I, T> {
|
||||
self._75p.as_mut().unwrap()
|
||||
}
|
||||
pub fn unwrap_median(&mut self) -> &mut EagerVec<I, T> {
|
||||
self.median.as_mut().unwrap()
|
||||
}
|
||||
pub fn unwrap_25p(&mut self) -> &mut EagerVec<I, T> {
|
||||
self._25p.as_mut().unwrap()
|
||||
}
|
||||
pub fn unwrap_10p(&mut self) -> &mut EagerVec<I, T> {
|
||||
self._10p.as_mut().unwrap()
|
||||
}
|
||||
pub fn unwrap_min(&mut self) -> &mut EagerVec<I, T> {
|
||||
self.min.as_mut().unwrap()
|
||||
}
|
||||
pub fn unwrap_last(&mut self) -> &mut EagerVec<I, T> {
|
||||
self.last.as_mut().unwrap()
|
||||
}
|
||||
pub fn unwrap_total(&mut self) -> &mut EagerVec<I, T> {
|
||||
self.total.as_mut().unwrap()
|
||||
}
|
||||
|
||||
pub fn any_vecs(&self) -> Vec<&dyn brk_vec::AnyStoredVec> {
|
||||
let mut v: Vec<&dyn brk_vec::AnyStoredVec> = vec![];
|
||||
|
||||
if let Some(first) = self.first.as_ref() {
|
||||
v.push(first.any_vec());
|
||||
}
|
||||
if let Some(last) = self.last.as_ref() {
|
||||
v.push(last.any_vec());
|
||||
}
|
||||
if let Some(min) = self.min.as_ref() {
|
||||
v.push(min.any_vec());
|
||||
}
|
||||
if let Some(max) = self.max.as_ref() {
|
||||
v.push(max.any_vec());
|
||||
}
|
||||
if let Some(median) = self.median.as_ref() {
|
||||
v.push(median.any_vec());
|
||||
}
|
||||
if let Some(average) = self.average.as_ref() {
|
||||
v.push(average.any_vec());
|
||||
}
|
||||
if let Some(sum) = self.sum.as_ref() {
|
||||
v.push(sum.any_vec());
|
||||
}
|
||||
if let Some(total) = self.total.as_ref() {
|
||||
v.push(total.any_vec());
|
||||
}
|
||||
if let Some(_90p) = self._90p.as_ref() {
|
||||
v.push(_90p.any_vec());
|
||||
}
|
||||
if let Some(_75p) = self._75p.as_ref() {
|
||||
v.push(_75p.any_vec());
|
||||
}
|
||||
if let Some(_25p) = self._25p.as_ref() {
|
||||
v.push(_25p.any_vec());
|
||||
}
|
||||
if let Some(_10p) = self._10p.as_ref() {
|
||||
v.push(_10p.any_vec());
|
||||
}
|
||||
|
||||
v
|
||||
}
|
||||
|
||||
pub fn safe_flush(&mut self, exit: &Exit) -> Result<()> {
|
||||
if let Some(first) = self.first.as_mut() {
|
||||
first.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(last) = self.last.as_mut() {
|
||||
last.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(min) = self.min.as_mut() {
|
||||
min.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(max) = self.max.as_mut() {
|
||||
max.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(median) = self.median.as_mut() {
|
||||
median.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(average) = self.average.as_mut() {
|
||||
average.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(sum) = self.sum.as_mut() {
|
||||
sum.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(total) = self.total.as_mut() {
|
||||
total.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(_90p) = self._90p.as_mut() {
|
||||
_90p.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(_75p) = self._75p.as_mut() {
|
||||
_75p.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(_25p) = self._25p.as_mut() {
|
||||
_25p.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(_10p) = self._10p.as_mut() {
|
||||
_10p.safe_flush(exit)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Copy)]
|
||||
pub struct StorableVecGeneatorOptions {
|
||||
average: bool,
|
||||
sum: bool,
|
||||
max: bool,
|
||||
_90p: bool,
|
||||
_75p: bool,
|
||||
median: bool,
|
||||
_25p: bool,
|
||||
_10p: bool,
|
||||
min: bool,
|
||||
first: bool,
|
||||
last: bool,
|
||||
total: bool,
|
||||
}
|
||||
|
||||
impl StorableVecGeneatorOptions {
|
||||
pub fn add_first(mut self) -> Self {
|
||||
self.first = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_last(mut self) -> Self {
|
||||
self.last = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_min(mut self) -> Self {
|
||||
self.min = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_max(mut self) -> Self {
|
||||
self.max = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_median(mut self) -> Self {
|
||||
self.median = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_average(mut self) -> Self {
|
||||
self.average = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_sum(mut self) -> Self {
|
||||
self.sum = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_90p(mut self) -> Self {
|
||||
self._90p = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_75p(mut self) -> Self {
|
||||
self._75p = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_25p(mut self) -> Self {
|
||||
self._25p = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_10p(mut self) -> Self {
|
||||
self._10p = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_total(mut self) -> Self {
|
||||
self.total = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_min(mut self) -> Self {
|
||||
self.min = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_max(mut self) -> Self {
|
||||
self.max = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_median(mut self) -> Self {
|
||||
self.median = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_average(mut self) -> Self {
|
||||
self.average = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_sum(mut self) -> Self {
|
||||
self.sum = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_90p(mut self) -> Self {
|
||||
self._90p = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_75p(mut self) -> Self {
|
||||
self._75p = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_25p(mut self) -> Self {
|
||||
self._25p = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_10p(mut self) -> Self {
|
||||
self._10p = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_total(mut self) -> Self {
|
||||
self.total = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_minmax(mut self) -> Self {
|
||||
self.min = true;
|
||||
self.max = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_percentiles(mut self) -> Self {
|
||||
self._90p = true;
|
||||
self._75p = true;
|
||||
self.median = true;
|
||||
self._25p = true;
|
||||
self._10p = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn remove_percentiles(mut self) -> Self {
|
||||
self._90p = false;
|
||||
self._75p = false;
|
||||
self.median = false;
|
||||
self._25p = false;
|
||||
self._10p = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_only_one_active(&self) -> bool {
|
||||
[
|
||||
self.average,
|
||||
self.sum,
|
||||
self.max,
|
||||
self._90p,
|
||||
self._75p,
|
||||
self.median,
|
||||
self._25p,
|
||||
self._10p,
|
||||
self.min,
|
||||
self.first,
|
||||
self.last,
|
||||
self.total,
|
||||
]
|
||||
.iter()
|
||||
.filter(|b| **b)
|
||||
.count()
|
||||
== 1
|
||||
}
|
||||
|
||||
pub fn copy_self_extra(&self) -> Self {
|
||||
Self {
|
||||
total: self.total,
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{DateIndex, DecadeIndex, MonthIndex, QuarterIndex, WeekIndex, YearIndex};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyStoredVec, Compressed, Result, Version};
|
||||
|
||||
use crate::storage::{ComputedType, EagerVec, Indexes, indexes};
|
||||
|
||||
use super::{ComputedVecBuilder, StorableVecGeneatorOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedVecsFromDateindex<T>
|
||||
where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub dateindex: EagerVec<DateIndex, T>,
|
||||
pub dateindex_extra: ComputedVecBuilder<DateIndex, T>,
|
||||
pub weekindex: ComputedVecBuilder<WeekIndex, T>,
|
||||
pub monthindex: ComputedVecBuilder<MonthIndex, T>,
|
||||
pub quarterindex: ComputedVecBuilder<QuarterIndex, T>,
|
||||
pub yearindex: ComputedVecBuilder<YearIndex, T>,
|
||||
pub decadeindex: ComputedVecBuilder<DecadeIndex, T>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<T> ComputedVecsFromDateindex<T>
|
||||
where
|
||||
T: ComputedType,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
version: Version,
|
||||
compressed: Compressed,
|
||||
options: StorableVecGeneatorOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let version = VERSION + version;
|
||||
|
||||
let dateindex_extra = ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version,
|
||||
compressed,
|
||||
options.copy_self_extra(),
|
||||
)?;
|
||||
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
Ok(Self {
|
||||
dateindex: EagerVec::forced_import(
|
||||
&path.join(format!("dateindex_to_{name}")),
|
||||
version,
|
||||
compressed,
|
||||
)?,
|
||||
dateindex_extra,
|
||||
weekindex: ComputedVecBuilder::forced_import(path, name, version, compressed, options)?,
|
||||
monthindex: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
quarterindex: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
yearindex: ComputedVecBuilder::forced_import(path, name, version, compressed, options)?,
|
||||
decadeindex: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute<F>(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(
|
||||
&mut EagerVec<DateIndex, T>,
|
||||
&Indexer,
|
||||
&indexes::Vecs,
|
||||
&Indexes,
|
||||
&Exit,
|
||||
) -> Result<()>,
|
||||
{
|
||||
compute(
|
||||
&mut self.dateindex,
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.dateindex_extra
|
||||
.extend(starting_indexes.dateindex, self.dateindex.vec(), exit)?;
|
||||
|
||||
self.weekindex.compute(
|
||||
starting_indexes.weekindex,
|
||||
self.dateindex.vec(),
|
||||
indexes.weekindex_to_first_dateindex.vec(),
|
||||
indexes.weekindex_to_dateindex_count.vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex.compute(
|
||||
starting_indexes.monthindex,
|
||||
self.dateindex.vec(),
|
||||
indexes.monthindex_to_first_dateindex.vec(),
|
||||
indexes.monthindex_to_dateindex_count.vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.quarterindex.from_aligned(
|
||||
starting_indexes.quarterindex,
|
||||
&self.monthindex,
|
||||
indexes.quarterindex_to_first_monthindex.vec(),
|
||||
indexes.quarterindex_to_monthindex_count.vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex.from_aligned(
|
||||
starting_indexes.yearindex,
|
||||
&self.monthindex,
|
||||
indexes.yearindex_to_first_monthindex.vec(),
|
||||
indexes.yearindex_to_monthindex_count.vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex.from_aligned(
|
||||
starting_indexes.decadeindex,
|
||||
&self.yearindex,
|
||||
indexes.decadeindex_to_first_yearindex.vec(),
|
||||
indexes.decadeindex_to_yearindex_count.vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn any_vecs(&self) -> Vec<&dyn AnyStoredVec> {
|
||||
[
|
||||
vec![self.dateindex.any_vec()],
|
||||
self.dateindex_extra.any_vecs(),
|
||||
self.weekindex.any_vecs(),
|
||||
self.monthindex.any_vecs(),
|
||||
self.quarterindex.any_vecs(),
|
||||
self.yearindex.any_vecs(),
|
||||
self.decadeindex.any_vecs(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{
|
||||
DateIndex, DecadeIndex, DifficultyEpoch, Height, MonthIndex, QuarterIndex, WeekIndex, YearIndex,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyStoredVec, Compressed, Result, StoredVec, Version};
|
||||
|
||||
use crate::storage::{ComputedType, EagerVec, Indexes, indexes};
|
||||
|
||||
use super::{ComputedVecBuilder, StorableVecGeneatorOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedVecsFromHeight<T>
|
||||
where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub height: Option<EagerVec<Height, T>>,
|
||||
pub height_extra: ComputedVecBuilder<Height, T>,
|
||||
pub dateindex: ComputedVecBuilder<DateIndex, T>,
|
||||
pub weekindex: ComputedVecBuilder<WeekIndex, T>,
|
||||
pub difficultyepoch: ComputedVecBuilder<DifficultyEpoch, T>,
|
||||
pub monthindex: ComputedVecBuilder<MonthIndex, T>,
|
||||
pub quarterindex: ComputedVecBuilder<QuarterIndex, T>,
|
||||
pub yearindex: ComputedVecBuilder<YearIndex, T>,
|
||||
// TODO: pub halvingepoch: StorableVecGeneator<Halvingepoch, T>,
|
||||
pub decadeindex: ComputedVecBuilder<DecadeIndex, T>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<T> ComputedVecsFromHeight<T>
|
||||
where
|
||||
T: ComputedType + Ord + From<f64>,
|
||||
f64: From<T>,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
compute_source: bool,
|
||||
version: Version,
|
||||
compressed: Compressed,
|
||||
options: StorableVecGeneatorOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let version = VERSION + version;
|
||||
|
||||
let height = compute_source.then(|| {
|
||||
EagerVec::forced_import(&path.join(format!("height_to_{name}")), version, compressed)
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
let height_extra = ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version,
|
||||
compressed,
|
||||
options.copy_self_extra(),
|
||||
)?;
|
||||
|
||||
let dateindex =
|
||||
ComputedVecBuilder::forced_import(path, name, version, compressed, options)?;
|
||||
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
Ok(Self {
|
||||
height,
|
||||
height_extra,
|
||||
dateindex,
|
||||
weekindex: ComputedVecBuilder::forced_import(path, name, version, compressed, options)?,
|
||||
difficultyepoch: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
monthindex: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
quarterindex: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
yearindex: ComputedVecBuilder::forced_import(path, name, version, compressed, options)?,
|
||||
// halvingepoch: StorableVecGeneator::forced_import(path, name, version, compressed, options)?,
|
||||
decadeindex: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute_all<F>(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(&mut EagerVec<Height, T>, &Indexer, &indexes::Vecs, &Indexes, &Exit) -> Result<()>,
|
||||
{
|
||||
compute(
|
||||
self.height.as_mut().unwrap(),
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.compute_rest(indexes, starting_indexes, exit, None)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
height: Option<&StoredVec<Height, T>>,
|
||||
) -> color_eyre::Result<()> {
|
||||
let height = height.unwrap_or_else(|| self.height.as_ref().unwrap().vec());
|
||||
|
||||
self.height_extra
|
||||
.extend(starting_indexes.height, height, exit)?;
|
||||
|
||||
self.dateindex.compute(
|
||||
starting_indexes.dateindex,
|
||||
height,
|
||||
indexes.dateindex_to_first_height.vec(),
|
||||
indexes.dateindex_to_height_count.vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.weekindex.from_aligned(
|
||||
starting_indexes.weekindex,
|
||||
&self.dateindex,
|
||||
indexes.weekindex_to_first_dateindex.vec(),
|
||||
indexes.weekindex_to_dateindex_count.vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex.from_aligned(
|
||||
starting_indexes.monthindex,
|
||||
&self.dateindex,
|
||||
indexes.monthindex_to_first_dateindex.vec(),
|
||||
indexes.monthindex_to_dateindex_count.vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.quarterindex.from_aligned(
|
||||
starting_indexes.quarterindex,
|
||||
&self.monthindex,
|
||||
indexes.quarterindex_to_first_monthindex.vec(),
|
||||
indexes.quarterindex_to_monthindex_count.vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex.from_aligned(
|
||||
starting_indexes.yearindex,
|
||||
&self.monthindex,
|
||||
indexes.yearindex_to_first_monthindex.vec(),
|
||||
indexes.yearindex_to_monthindex_count.vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex.from_aligned(
|
||||
starting_indexes.decadeindex,
|
||||
&self.yearindex,
|
||||
indexes.decadeindex_to_first_yearindex.vec(),
|
||||
indexes.decadeindex_to_yearindex_count.vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.difficultyepoch.compute(
|
||||
starting_indexes.difficultyepoch,
|
||||
height,
|
||||
indexes.difficultyepoch_to_first_height.vec(),
|
||||
indexes.difficultyepoch_to_height_count.vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn any_vecs(&self) -> Vec<&dyn AnyStoredVec> {
|
||||
[
|
||||
self.height.as_ref().map_or(vec![], |v| vec![v.any_vec()]),
|
||||
self.height_extra.any_vecs(),
|
||||
self.dateindex.any_vecs(),
|
||||
self.weekindex.any_vecs(),
|
||||
self.difficultyepoch.any_vecs(),
|
||||
self.monthindex.any_vecs(),
|
||||
self.quarterindex.any_vecs(),
|
||||
self.yearindex.any_vecs(),
|
||||
// self.halvingepoch.as_any_vecs(),
|
||||
self.decadeindex.any_vecs(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{DifficultyEpoch, Height};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyStoredVec, Compressed, Result, Version};
|
||||
|
||||
use crate::storage::{ComputedType, EagerVec, Indexes, indexes};
|
||||
|
||||
use super::{ComputedVecBuilder, StorableVecGeneatorOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedVecsFromHeightStrict<T>
|
||||
where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub height: EagerVec<Height, T>,
|
||||
pub height_extra: ComputedVecBuilder<Height, T>,
|
||||
pub difficultyepoch: ComputedVecBuilder<DifficultyEpoch, T>,
|
||||
// TODO: pub halvingepoch: StorableVecGeneator<Halvingepoch, T>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<T> ComputedVecsFromHeightStrict<T>
|
||||
where
|
||||
T: ComputedType + Ord + From<f64>,
|
||||
f64: From<T>,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
version: Version,
|
||||
compressed: Compressed,
|
||||
options: StorableVecGeneatorOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let version = VERSION + version;
|
||||
|
||||
let height =
|
||||
EagerVec::forced_import(&path.join(format!("height_to_{name}")), version, compressed)?;
|
||||
|
||||
let height_extra = ComputedVecBuilder::forced_import(
|
||||
path,
|
||||
name,
|
||||
version,
|
||||
compressed,
|
||||
options.copy_self_extra(),
|
||||
)?;
|
||||
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
Ok(Self {
|
||||
height,
|
||||
height_extra,
|
||||
difficultyepoch: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
// halvingepoch: StorableVecGeneator::forced_import(path, name, version, compressed, options)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute<F>(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(&mut EagerVec<Height, T>, &Indexer, &indexes::Vecs, &Indexes, &Exit) -> Result<()>,
|
||||
{
|
||||
compute(&mut self.height, indexer, indexes, starting_indexes, exit)?;
|
||||
|
||||
self.height_extra
|
||||
.extend(starting_indexes.height, self.height.vec(), exit)?;
|
||||
|
||||
self.difficultyepoch.compute(
|
||||
starting_indexes.difficultyepoch,
|
||||
self.height.vec(),
|
||||
indexes.difficultyepoch_to_first_height.vec(),
|
||||
indexes.difficultyepoch_to_height_count.vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn any_vecs(&self) -> Vec<&dyn AnyStoredVec> {
|
||||
[
|
||||
vec![self.height.any_vec()],
|
||||
self.height_extra.any_vecs(),
|
||||
self.difficultyepoch.any_vecs(),
|
||||
// self.halvingepoch.as_any_vecs(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{
|
||||
DateIndex, DecadeIndex, DifficultyEpoch, Height, MonthIndex, QuarterIndex, TxIndex, WeekIndex,
|
||||
YearIndex,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyStoredVec, Compressed, Result, StoredVec, Version};
|
||||
|
||||
use crate::storage::{ComputedType, EagerVec, Indexes, indexes};
|
||||
|
||||
use super::{ComputedVecBuilder, StorableVecGeneatorOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComputedVecsFromTxindex<T>
|
||||
where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub txindex: Option<EagerVec<TxIndex, T>>,
|
||||
pub height: ComputedVecBuilder<Height, T>,
|
||||
pub dateindex: ComputedVecBuilder<DateIndex, T>,
|
||||
pub weekindex: ComputedVecBuilder<WeekIndex, T>,
|
||||
pub difficultyepoch: ComputedVecBuilder<DifficultyEpoch, T>,
|
||||
pub monthindex: ComputedVecBuilder<MonthIndex, T>,
|
||||
pub quarterindex: ComputedVecBuilder<QuarterIndex, T>,
|
||||
pub yearindex: ComputedVecBuilder<YearIndex, T>,
|
||||
// TODO: pub halvingepoch: StorableVecGeneator<Halvingepoch, T>,
|
||||
pub decadeindex: ComputedVecBuilder<DecadeIndex, T>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<T> ComputedVecsFromTxindex<T>
|
||||
where
|
||||
T: ComputedType + Ord + From<f64>,
|
||||
f64: From<T>,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
name: &str,
|
||||
compute_source: bool,
|
||||
version: Version,
|
||||
compressed: Compressed,
|
||||
options: StorableVecGeneatorOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let version = VERSION + version;
|
||||
|
||||
let txindex = compute_source.then(|| {
|
||||
EagerVec::forced_import(
|
||||
&path.join(format!("txindex_to_{name}")),
|
||||
version,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
let height = ComputedVecBuilder::forced_import(path, name, version, compressed, options)?;
|
||||
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
Ok(Self {
|
||||
txindex,
|
||||
height,
|
||||
dateindex: ComputedVecBuilder::forced_import(path, name, version, compressed, options)?,
|
||||
weekindex: ComputedVecBuilder::forced_import(path, name, version, compressed, options)?,
|
||||
difficultyepoch: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
monthindex: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
quarterindex: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
yearindex: ComputedVecBuilder::forced_import(path, name, version, compressed, options)?,
|
||||
// halvingepoch: StorableVecGeneator::forced_import(path, name, version, compressed, options)?,
|
||||
decadeindex: ComputedVecBuilder::forced_import(
|
||||
path, name, version, compressed, options,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute_all<F>(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(
|
||||
&mut EagerVec<TxIndex, T>,
|
||||
&Indexer,
|
||||
&indexes::Vecs,
|
||||
&Indexes,
|
||||
&Exit,
|
||||
) -> Result<()>,
|
||||
{
|
||||
compute(
|
||||
self.txindex.as_mut().unwrap(),
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.compute_rest(indexer, indexes, starting_indexes, exit, None)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
txindex: Option<&StoredVec<TxIndex, T>>,
|
||||
) -> color_eyre::Result<()> {
|
||||
let txindex = txindex.unwrap_or_else(|| self.txindex.as_ref().unwrap().vec());
|
||||
|
||||
self.height.compute(
|
||||
starting_indexes.height,
|
||||
txindex,
|
||||
indexer.vecs().height_to_first_txindex.vec(),
|
||||
indexes.height_to_txindex_count.vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.dateindex.from_aligned(
|
||||
starting_indexes.dateindex,
|
||||
&self.height,
|
||||
indexes.dateindex_to_first_height.vec(),
|
||||
indexes.dateindex_to_height_count.vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.weekindex.from_aligned(
|
||||
starting_indexes.weekindex,
|
||||
&self.dateindex,
|
||||
indexes.weekindex_to_first_dateindex.vec(),
|
||||
indexes.weekindex_to_dateindex_count.vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex.from_aligned(
|
||||
starting_indexes.monthindex,
|
||||
&self.dateindex,
|
||||
indexes.monthindex_to_first_dateindex.vec(),
|
||||
indexes.monthindex_to_dateindex_count.vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.quarterindex.from_aligned(
|
||||
starting_indexes.quarterindex,
|
||||
&self.monthindex,
|
||||
indexes.quarterindex_to_first_monthindex.vec(),
|
||||
indexes.quarterindex_to_monthindex_count.vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex.from_aligned(
|
||||
starting_indexes.yearindex,
|
||||
&self.monthindex,
|
||||
indexes.yearindex_to_first_monthindex.vec(),
|
||||
indexes.yearindex_to_monthindex_count.vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex.from_aligned(
|
||||
starting_indexes.decadeindex,
|
||||
&self.yearindex,
|
||||
indexes.decadeindex_to_first_yearindex.vec(),
|
||||
indexes.decadeindex_to_yearindex_count.vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.difficultyepoch.from_aligned(
|
||||
starting_indexes.difficultyepoch,
|
||||
&self.height,
|
||||
indexes.difficultyepoch_to_first_height.vec(),
|
||||
indexes.difficultyepoch_to_height_count.vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn any_vecs(&self) -> Vec<&dyn AnyStoredVec> {
|
||||
[
|
||||
self.txindex.as_ref().map_or(vec![], |v| vec![v.any_vec()]),
|
||||
self.height.any_vecs(),
|
||||
self.dateindex.any_vecs(),
|
||||
self.weekindex.any_vecs(),
|
||||
self.difficultyepoch.any_vecs(),
|
||||
self.monthindex.any_vecs(),
|
||||
self.quarterindex.any_vecs(),
|
||||
self.yearindex.any_vecs(),
|
||||
// self.halvingepoch.as_any_vecs(),
|
||||
self.decadeindex.any_vecs(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
mod builder;
|
||||
mod from_dateindex;
|
||||
mod from_height;
|
||||
mod from_height_strict;
|
||||
mod from_txindex;
|
||||
mod value_from_height;
|
||||
mod value_from_txindex;
|
||||
|
||||
pub use builder::*;
|
||||
pub use from_dateindex::*;
|
||||
pub use from_height::*;
|
||||
pub use from_height_strict::*;
|
||||
pub use from_txindex::*;
|
||||
pub use value_from_height::*;
|
||||
pub use value_from_txindex::*;
|
||||
@@ -0,0 +1,156 @@
|
||||
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::{
|
||||
EagerVec, 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: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
marketprices: Option<&marketprice::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(
|
||||
&mut EagerVec<Height, Sats>,
|
||||
&Indexer,
|
||||
&indexes::Vecs,
|
||||
&Indexes,
|
||||
&Exit,
|
||||
) -> Result<()>,
|
||||
{
|
||||
compute(
|
||||
self.sats.height.as_mut().unwrap(),
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.compute_rest(indexer, indexes, marketprices, starting_indexes, exit, None)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
marketprices: Option<&marketprice::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
height: Option<&StoredVec<Height, Sats>>,
|
||||
) -> color_eyre::Result<()> {
|
||||
if let Some(height) = height.as_ref() {
|
||||
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_ref().unwrap().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_ref().unwrap().vec();
|
||||
let price = marketprices
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.chainindexes_to_close
|
||||
.height
|
||||
.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,158 @@
|
||||
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::{
|
||||
EagerVec, 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: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
marketprices: Option<&marketprice::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
mut compute: F,
|
||||
) -> color_eyre::Result<()>
|
||||
where
|
||||
F: FnMut(
|
||||
&mut EagerVec<TxIndex, Sats>,
|
||||
&Indexer,
|
||||
&indexes::Vecs,
|
||||
&Indexes,
|
||||
&Exit,
|
||||
) -> Result<()>,
|
||||
{
|
||||
compute(
|
||||
self.sats.txindex.as_mut().unwrap(),
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.compute_rest(indexer, indexes, marketprices, starting_indexes, exit, None)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute_rest(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
marketprices: Option<&marketprice::Vecs>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
txindex: Option<&StoredVec<TxIndex, Sats>>,
|
||||
) -> color_eyre::Result<()> {
|
||||
if let Some(txindex) = txindex.as_ref() {
|
||||
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_ref().unwrap().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();
|
||||
|
||||
if let Some(dollars) = self.dollars.as_mut() {
|
||||
let price = marketprices.unwrap().chainindexes_to_close.height.vec();
|
||||
|
||||
dollars.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, _, indexes, starting_indexes, exit| {
|
||||
v.compute_from_bitcoin(
|
||||
starting_indexes.txindex,
|
||||
txindex,
|
||||
indexes.txindex_to_height.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()
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,124 @@
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use brk_core::{DifficultyEpoch, HalvingEpoch, StoredF64};
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{Compressed, Version};
|
||||
|
||||
use super::{
|
||||
Indexes,
|
||||
grouped::{ComputedVecsFromDateindex, ComputedVecsFromHeight, StorableVecGeneatorOptions},
|
||||
indexes,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vecs {
|
||||
pub indexes_to_difficulty: ComputedVecsFromHeight<StoredF64>,
|
||||
pub indexes_to_difficultyepoch: ComputedVecsFromDateindex<DifficultyEpoch>,
|
||||
pub indexes_to_halvingepoch: ComputedVecsFromDateindex<HalvingEpoch>,
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
pub fn forced_import(path: &Path, compressed: Compressed) -> color_eyre::Result<Self> {
|
||||
fs::create_dir_all(path)?;
|
||||
|
||||
Ok(Self {
|
||||
indexes_to_difficulty: ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
"difficulty",
|
||||
false,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
)?,
|
||||
indexes_to_difficultyepoch: ComputedVecsFromDateindex::forced_import(
|
||||
path,
|
||||
"difficultyepoch",
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
)?,
|
||||
indexes_to_halvingepoch: ComputedVecsFromDateindex::forced_import(
|
||||
path,
|
||||
"halvingepoch",
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
let mut height_to_difficultyepoch_iter = indexes.height_to_difficultyepoch.iter();
|
||||
self.indexes_to_difficultyepoch.compute(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|vec, _, indexes, starting_indexes, exit| {
|
||||
let mut height_count_iter = indexes.dateindex_to_height_count.iter();
|
||||
vec.compute_transform(
|
||||
starting_indexes.dateindex,
|
||||
indexes.dateindex_to_first_height.vec(),
|
||||
|(di, height, ..)| {
|
||||
(
|
||||
di,
|
||||
height_to_difficultyepoch_iter.unwrap_get_inner(
|
||||
height + (*height_count_iter.unwrap_get_inner(di) - 1),
|
||||
),
|
||||
)
|
||||
},
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
let mut height_to_halvingepoch_iter = indexes.height_to_halvingepoch.iter();
|
||||
self.indexes_to_halvingepoch.compute(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|vec, _, indexes, starting_indexes, exit| {
|
||||
let mut height_count_iter = indexes.dateindex_to_height_count.iter();
|
||||
vec.compute_transform(
|
||||
starting_indexes.dateindex,
|
||||
indexes.dateindex_to_first_height.vec(),
|
||||
|(di, height, ..)| {
|
||||
(
|
||||
di,
|
||||
height_to_halvingepoch_iter.unwrap_get_inner(
|
||||
height + (*height_count_iter.unwrap_get_inner(di) - 1),
|
||||
),
|
||||
)
|
||||
},
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
self.indexes_to_difficulty.compute_rest(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(indexer.vecs().height_to_difficulty.vec()),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn brk_vec::AnyStoredVec> {
|
||||
[
|
||||
self.indexes_to_difficulty.any_vecs(),
|
||||
self.indexes_to_difficultyepoch.any_vecs(),
|
||||
self.indexes_to_halvingepoch.any_vecs(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
@@ -3,22 +3,24 @@ use std::{fs, path::Path};
|
||||
use brk_exit::Exit;
|
||||
use brk_fetcher::Fetcher;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{AnyStorableVec, Compressed};
|
||||
use brk_vec::{AnyStoredVec, Compressed};
|
||||
|
||||
mod base;
|
||||
mod blocks;
|
||||
mod indexes;
|
||||
mod marketprice;
|
||||
mod stats;
|
||||
mod transactions;
|
||||
pub mod blocks;
|
||||
pub mod grouped;
|
||||
pub mod indexes;
|
||||
pub mod marketprice;
|
||||
pub mod mining;
|
||||
pub mod transactions;
|
||||
pub mod vec;
|
||||
|
||||
use base::*;
|
||||
use indexes::*;
|
||||
pub use indexes::Indexes;
|
||||
pub use vec::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vecs {
|
||||
pub blocks: blocks::Vecs,
|
||||
pub indexes: indexes::Vecs,
|
||||
pub blocks: blocks::Vecs,
|
||||
pub mining: mining::Vecs,
|
||||
pub transactions: transactions::Vecs,
|
||||
pub marketprice: Option<marketprice::Vecs>,
|
||||
}
|
||||
@@ -30,14 +32,15 @@ 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)?,
|
||||
mining: mining::Vecs::forced_import(path, compressed)?,
|
||||
transactions: transactions::Vecs::forced_import(path, compressed, fetch)?,
|
||||
marketprice: fetch.then(|| marketprice::Vecs::forced_import(path, compressed).unwrap()),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute(
|
||||
&mut self,
|
||||
indexer: &mut Indexer,
|
||||
indexer: &Indexer,
|
||||
starting_indexes: brk_indexer::Indexes,
|
||||
fetcher: Option<&mut Fetcher>,
|
||||
exit: &Exit,
|
||||
@@ -45,28 +48,37 @@ impl Vecs {
|
||||
let starting_indexes = self.indexes.compute(indexer, starting_indexes, exit)?;
|
||||
|
||||
self.blocks
|
||||
.compute(indexer, &mut self.indexes, &starting_indexes, exit)?;
|
||||
.compute(indexer, &self.indexes, &starting_indexes, exit)?;
|
||||
|
||||
self.transactions
|
||||
.compute(indexer, &mut self.indexes, &starting_indexes, exit)?;
|
||||
self.mining
|
||||
.compute(indexer, &self.indexes, &starting_indexes, exit)?;
|
||||
|
||||
if let Some(marketprice) = self.marketprice.as_mut() {
|
||||
marketprice.compute(
|
||||
indexer,
|
||||
&mut self.indexes,
|
||||
&self.indexes,
|
||||
&starting_indexes,
|
||||
fetcher.unwrap(),
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
self.transactions.compute(
|
||||
indexer,
|
||||
&self.indexes,
|
||||
&starting_indexes,
|
||||
self.marketprice.as_ref(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStoredVec> {
|
||||
[
|
||||
self.indexes.as_any_vecs(),
|
||||
self.blocks.as_any_vecs(),
|
||||
self.mining.as_any_vecs(),
|
||||
self.transactions.as_any_vecs(),
|
||||
self.marketprice
|
||||
.as_ref()
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{Dateindex, Decadeindex, Monthindex, Quarterindex, Weekindex, Yearindex};
|
||||
use brk_exit::Exit;
|
||||
use brk_vec::{AnyStorableVec, Compressed};
|
||||
|
||||
use crate::storage::vecs::{Indexes, base::StorableVec, indexes};
|
||||
|
||||
use super::{ComputedType, StorableVecBuilder, StorableVecGeneatorOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StorableVecsStatsFromDate<T>
|
||||
where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub weekindex: StorableVecBuilder<Weekindex, T>,
|
||||
pub monthindex: StorableVecBuilder<Monthindex, T>,
|
||||
pub quarterindex: StorableVecBuilder<Quarterindex, T>,
|
||||
pub yearindex: StorableVecBuilder<Yearindex, T>,
|
||||
pub decadeindex: StorableVecBuilder<Decadeindex, T>,
|
||||
}
|
||||
|
||||
impl<T> StorableVecsStatsFromDate<T>
|
||||
where
|
||||
T: ComputedType + Ord + From<f64>,
|
||||
f64: From<T>,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
compressed: Compressed,
|
||||
options: StorableVecGeneatorOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
Ok(Self {
|
||||
weekindex: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
monthindex: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
quarterindex: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
yearindex: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
decadeindex: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute(
|
||||
&mut self,
|
||||
source: &mut StorableVec<Dateindex, T>,
|
||||
indexes: &mut indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
self.weekindex.compute(
|
||||
starting_indexes.weekindex,
|
||||
source,
|
||||
indexes.weekindex_to_first_dateindex.mut_vec(),
|
||||
indexes.weekindex_to_last_dateindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex.compute(
|
||||
starting_indexes.monthindex,
|
||||
source,
|
||||
indexes.monthindex_to_first_dateindex.mut_vec(),
|
||||
indexes.monthindex_to_last_dateindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.quarterindex.from_aligned(
|
||||
starting_indexes.quarterindex,
|
||||
&mut self.monthindex,
|
||||
indexes.quarterindex_to_first_monthindex.mut_vec(),
|
||||
indexes.quarterindex_to_last_monthindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex.from_aligned(
|
||||
starting_indexes.yearindex,
|
||||
&mut self.monthindex,
|
||||
indexes.yearindex_to_first_monthindex.mut_vec(),
|
||||
indexes.yearindex_to_last_monthindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex.from_aligned(
|
||||
starting_indexes.decadeindex,
|
||||
&mut self.yearindex,
|
||||
indexes.decadeindex_to_first_yearindex.mut_vec(),
|
||||
indexes.decadeindex_to_last_yearindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
|
||||
[
|
||||
self.weekindex.as_any_vecs(),
|
||||
self.monthindex.as_any_vecs(),
|
||||
self.quarterindex.as_any_vecs(),
|
||||
self.yearindex.as_any_vecs(),
|
||||
self.decadeindex.as_any_vecs(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{
|
||||
Dateindex, Decadeindex, Difficultyepoch, Height, Monthindex, Quarterindex, Weekindex, Yearindex,
|
||||
};
|
||||
use brk_exit::Exit;
|
||||
use brk_vec::{AnyStorableVec, Compressed};
|
||||
|
||||
use crate::storage::vecs::{Indexes, base::StorableVec, indexes};
|
||||
|
||||
use super::{ComputedType, StorableVecBuilder, StorableVecGeneatorOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StorableVecsStatsFromHeight<T>
|
||||
where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub dateindex: StorableVecBuilder<Dateindex, T>,
|
||||
pub weekindex: StorableVecBuilder<Weekindex, T>,
|
||||
pub difficultyepoch: StorableVecBuilder<Difficultyepoch, T>,
|
||||
pub monthindex: StorableVecBuilder<Monthindex, T>,
|
||||
pub quarterindex: StorableVecBuilder<Quarterindex, T>,
|
||||
pub yearindex: StorableVecBuilder<Yearindex, T>,
|
||||
// TODO: pub halvingepoch: StorableVecGeneator<Halvingepoch, T>,
|
||||
pub decadeindex: StorableVecBuilder<Decadeindex, T>,
|
||||
}
|
||||
|
||||
impl<T> StorableVecsStatsFromHeight<T>
|
||||
where
|
||||
T: ComputedType + Ord + From<f64>,
|
||||
f64: From<T>,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
compressed: Compressed,
|
||||
options: StorableVecGeneatorOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let dateindex = StorableVecBuilder::forced_import(path, compressed, options)?;
|
||||
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
Ok(Self {
|
||||
dateindex,
|
||||
weekindex: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
difficultyepoch: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
monthindex: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
quarterindex: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
yearindex: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
// halvingepoch: StorableVecGeneator::forced_import(path, compressed, options)?,
|
||||
decadeindex: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute(
|
||||
&mut self,
|
||||
source: &mut StorableVec<Height, T>,
|
||||
indexes: &mut indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
self.dateindex.compute(
|
||||
starting_indexes.dateindex,
|
||||
source,
|
||||
indexes.dateindex_to_first_height.mut_vec(),
|
||||
indexes.dateindex_to_last_height.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.weekindex.from_aligned(
|
||||
starting_indexes.weekindex,
|
||||
&mut self.dateindex,
|
||||
indexes.weekindex_to_first_dateindex.mut_vec(),
|
||||
indexes.weekindex_to_last_dateindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.monthindex.from_aligned(
|
||||
starting_indexes.monthindex,
|
||||
&mut self.dateindex,
|
||||
indexes.monthindex_to_first_dateindex.mut_vec(),
|
||||
indexes.monthindex_to_last_dateindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.quarterindex.from_aligned(
|
||||
starting_indexes.quarterindex,
|
||||
&mut self.monthindex,
|
||||
indexes.quarterindex_to_first_monthindex.mut_vec(),
|
||||
indexes.quarterindex_to_last_monthindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.yearindex.from_aligned(
|
||||
starting_indexes.yearindex,
|
||||
&mut self.monthindex,
|
||||
indexes.yearindex_to_first_monthindex.mut_vec(),
|
||||
indexes.yearindex_to_last_monthindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.decadeindex.from_aligned(
|
||||
starting_indexes.decadeindex,
|
||||
&mut self.yearindex,
|
||||
indexes.decadeindex_to_first_yearindex.mut_vec(),
|
||||
indexes.decadeindex_to_last_yearindex.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.difficultyepoch.compute(
|
||||
starting_indexes.difficultyepoch,
|
||||
source,
|
||||
indexes.difficultyepoch_to_first_height.mut_vec(),
|
||||
indexes.difficultyepoch_to_last_height.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
|
||||
[
|
||||
self.dateindex.as_any_vecs(),
|
||||
self.weekindex.as_any_vecs(),
|
||||
self.difficultyepoch.as_any_vecs(),
|
||||
self.monthindex.as_any_vecs(),
|
||||
self.quarterindex.as_any_vecs(),
|
||||
self.yearindex.as_any_vecs(),
|
||||
// self.halvingepoch.as_any_vecs(),
|
||||
self.decadeindex.as_any_vecs(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{Difficultyepoch, Height};
|
||||
use brk_exit::Exit;
|
||||
use brk_vec::{AnyStorableVec, Compressed};
|
||||
|
||||
use crate::storage::vecs::{Indexes, base::StorableVec, indexes};
|
||||
|
||||
use super::{ComputedType, StorableVecBuilder, StorableVecGeneatorOptions};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StorableVecsStatsFromHeightStrict<T>
|
||||
where
|
||||
T: ComputedType + PartialOrd,
|
||||
{
|
||||
pub difficultyepoch: StorableVecBuilder<Difficultyepoch, T>,
|
||||
// TODO: pub halvingepoch: StorableVecGeneator<Halvingepoch, T>,
|
||||
}
|
||||
|
||||
impl<T> StorableVecsStatsFromHeightStrict<T>
|
||||
where
|
||||
T: ComputedType + Ord + From<f64>,
|
||||
f64: From<T>,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
compressed: Compressed,
|
||||
options: StorableVecGeneatorOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let options = options.remove_percentiles();
|
||||
|
||||
Ok(Self {
|
||||
difficultyepoch: StorableVecBuilder::forced_import(path, compressed, options)?,
|
||||
// halvingepoch: StorableVecGeneator::forced_import(path, compressed, options)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute(
|
||||
&mut self,
|
||||
source: &mut StorableVec<Height, T>,
|
||||
indexes: &mut indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
self.difficultyepoch.compute(
|
||||
starting_indexes.difficultyepoch,
|
||||
source,
|
||||
indexes.difficultyepoch_to_first_height.mut_vec(),
|
||||
indexes.difficultyepoch_to_last_height.mut_vec(),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
|
||||
[
|
||||
self.difficultyepoch.as_any_vecs(),
|
||||
// self.halvingepoch.as_any_vecs(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
@@ -1,601 +0,0 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_exit::Exit;
|
||||
use brk_vec::{AnyStorableVec, Compressed, Result, StoredIndex, StoredType, Version};
|
||||
|
||||
use crate::storage::vecs::base::StorableVec;
|
||||
|
||||
use super::ComputedType;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StorableVecBuilder<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: ComputedType,
|
||||
{
|
||||
pub first: Option<StorableVec<I, T>>,
|
||||
pub average: Option<StorableVec<I, T>>,
|
||||
pub sum: Option<StorableVec<I, T>>,
|
||||
pub max: Option<StorableVec<I, T>>,
|
||||
pub _90p: Option<StorableVec<I, T>>,
|
||||
pub _75p: Option<StorableVec<I, T>>,
|
||||
pub median: Option<StorableVec<I, T>>,
|
||||
pub _25p: Option<StorableVec<I, T>>,
|
||||
pub _10p: Option<StorableVec<I, T>>,
|
||||
pub min: Option<StorableVec<I, T>>,
|
||||
pub last: Option<StorableVec<I, T>>,
|
||||
}
|
||||
|
||||
impl<I, T> StorableVecBuilder<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: ComputedType,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
compressed: Compressed,
|
||||
options: StorableVecGeneatorOptions,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let name = path.file_name().unwrap().to_str().unwrap().to_string();
|
||||
let key = I::to_string().split("::").last().unwrap().to_lowercase();
|
||||
|
||||
let only_one_active = options.is_only_one_active();
|
||||
|
||||
let prefix = |s: &str| {
|
||||
if only_one_active {
|
||||
path.with_file_name(format!("{key}_to_{name}"))
|
||||
} else {
|
||||
path.with_file_name(format!("{key}_to_{s}_{name}"))
|
||||
}
|
||||
};
|
||||
|
||||
let suffix = |s: &str| {
|
||||
if only_one_active {
|
||||
path.with_file_name(format!("{key}_to_{name}"))
|
||||
} else {
|
||||
path.with_file_name(format!("{key}_to_{name}_{s}"))
|
||||
}
|
||||
};
|
||||
|
||||
let s = Self {
|
||||
first: options.first.then(|| {
|
||||
StorableVec::forced_import(&prefix("first"), Version::ONE, compressed).unwrap()
|
||||
}),
|
||||
last: options.last.then(|| {
|
||||
StorableVec::forced_import(
|
||||
&path.with_file_name(format!("{key}_to_{name}")),
|
||||
Version::ONE,
|
||||
compressed,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
min: options.min.then(|| {
|
||||
StorableVec::forced_import(&suffix("min"), Version::ONE, compressed).unwrap()
|
||||
}),
|
||||
max: options.max.then(|| {
|
||||
StorableVec::forced_import(&suffix("max"), Version::ONE, compressed).unwrap()
|
||||
}),
|
||||
median: options.median.then(|| {
|
||||
StorableVec::forced_import(&suffix("median"), Version::ONE, compressed).unwrap()
|
||||
}),
|
||||
average: options.average.then(|| {
|
||||
StorableVec::forced_import(&suffix("average"), Version::ONE, compressed).unwrap()
|
||||
}),
|
||||
sum: options.sum.then(|| {
|
||||
StorableVec::forced_import(&suffix("sum"), Version::ONE, compressed).unwrap()
|
||||
}),
|
||||
_90p: options._90p.then(|| {
|
||||
StorableVec::forced_import(&suffix("90p"), Version::ONE, compressed).unwrap()
|
||||
}),
|
||||
_75p: options._75p.then(|| {
|
||||
StorableVec::forced_import(&suffix("75p"), Version::ONE, compressed).unwrap()
|
||||
}),
|
||||
_25p: options._25p.then(|| {
|
||||
StorableVec::forced_import(&suffix("25p"), Version::ONE, compressed).unwrap()
|
||||
}),
|
||||
_10p: options._10p.then(|| {
|
||||
StorableVec::forced_import(&suffix("10p"), Version::ONE, compressed).unwrap()
|
||||
}),
|
||||
};
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
pub fn compute<I2>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
source: &mut StorableVec<I2, T>,
|
||||
first_indexes: &mut brk_vec::StorableVec<I, I2>,
|
||||
last_indexes: &mut brk_vec::StorableVec<I, I2>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
I2: StoredIndex + StoredType,
|
||||
T: Ord + From<f64>,
|
||||
f64: From<T>,
|
||||
{
|
||||
let index = self.starting_index(max_from);
|
||||
|
||||
first_indexes.iter_from(index, |(i, first_index)| {
|
||||
let first_index = *first_index;
|
||||
let last_index = *last_indexes.get(i).unwrap().unwrap();
|
||||
|
||||
if let Some(first) = self.first.as_mut() {
|
||||
let v = source.get(first_index).unwrap().unwrap();
|
||||
first.forced_push_at(index, v.clone(), exit)?;
|
||||
}
|
||||
|
||||
if let Some(last) = self.last.as_mut() {
|
||||
let v = source.get(last_index).unwrap().unwrap();
|
||||
last.forced_push_at(index, v.clone(), exit)?;
|
||||
}
|
||||
|
||||
let first_index = first_index.to_usize()?;
|
||||
let last_index = last_index.to_usize()?;
|
||||
|
||||
let needs_sum_or_average = self.sum.is_some() || self.average.is_some();
|
||||
let needs_sorted = self.max.is_some()
|
||||
|| self._90p.is_some()
|
||||
|| self._75p.is_some()
|
||||
|| self.median.is_some()
|
||||
|| self._25p.is_some()
|
||||
|| self._10p.is_some()
|
||||
|| self.min.is_some();
|
||||
let needs_values = needs_sorted || needs_sum_or_average;
|
||||
|
||||
if needs_values {
|
||||
let mut values =
|
||||
source.collect_range(Some(first_index as i64), Some(last_index as i64))?;
|
||||
|
||||
if needs_sorted {
|
||||
values.sort_unstable();
|
||||
|
||||
if let Some(max) = self.max.as_mut() {
|
||||
max.forced_push_at(i, values.last().unwrap().clone(), exit)?;
|
||||
}
|
||||
|
||||
if let Some(_90p) = self._90p.as_mut() {
|
||||
_90p.forced_push_at(i, Self::get_percentile(&values, 0.90), exit)?;
|
||||
}
|
||||
|
||||
if let Some(_75p) = self._75p.as_mut() {
|
||||
_75p.forced_push_at(i, Self::get_percentile(&values, 0.75), exit)?;
|
||||
}
|
||||
|
||||
if let Some(median) = self.median.as_mut() {
|
||||
median.forced_push_at(i, Self::get_percentile(&values, 0.50), exit)?;
|
||||
}
|
||||
|
||||
if let Some(_25p) = self._25p.as_mut() {
|
||||
_25p.forced_push_at(i, Self::get_percentile(&values, 0.25), exit)?;
|
||||
}
|
||||
|
||||
if let Some(_10p) = self._10p.as_mut() {
|
||||
_10p.forced_push_at(i, Self::get_percentile(&values, 0.10), exit)?;
|
||||
}
|
||||
|
||||
if let Some(min) = self.min.as_mut() {
|
||||
min.forced_push_at(i, values.first().unwrap().clone(), exit)?;
|
||||
}
|
||||
}
|
||||
|
||||
if needs_sum_or_average {
|
||||
let len = values.len();
|
||||
|
||||
if let Some(average) = self.average.as_mut() {
|
||||
let len = len as f64;
|
||||
let total = values
|
||||
.iter()
|
||||
.map(|v| f64::from(v.clone()))
|
||||
.fold(0.0, |a, b| a + b);
|
||||
let avg = T::from(total / len);
|
||||
average.forced_push_at(i, avg, exit)?;
|
||||
}
|
||||
|
||||
if let Some(sum_vec) = self.sum.as_mut() {
|
||||
let sum = values.into_iter().fold(T::from(0), |a, b| a + b);
|
||||
sum_vec.forced_push_at(i, sum, exit)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
pub fn from_aligned<I2>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
source: &mut StorableVecBuilder<I2, T>,
|
||||
first_indexes: &mut brk_vec::StorableVec<I, I2>,
|
||||
last_indexes: &mut brk_vec::StorableVec<I, I2>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
I2: StoredIndex + StoredType,
|
||||
T: Ord + From<f64>,
|
||||
f64: From<T>,
|
||||
{
|
||||
if self._90p.is_some()
|
||||
|| self._75p.is_some()
|
||||
|| self.median.is_some()
|
||||
|| self._25p.is_some()
|
||||
|| self._10p.is_some()
|
||||
{
|
||||
panic!("unsupported");
|
||||
}
|
||||
|
||||
let index = self.starting_index(max_from);
|
||||
|
||||
first_indexes.iter_from(index, |(i, first_index)| {
|
||||
let first_index = *first_index;
|
||||
let last_index = *last_indexes.get(i).unwrap().unwrap();
|
||||
|
||||
if let Some(first) = self.first.as_mut() {
|
||||
let v = source
|
||||
.first
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.get(first_index)
|
||||
.unwrap()
|
||||
.cloned()
|
||||
.unwrap();
|
||||
first.forced_push_at(index, v, exit)?;
|
||||
}
|
||||
|
||||
if let Some(last) = self.last.as_mut() {
|
||||
let v = source
|
||||
.last
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.get(last_index)
|
||||
.unwrap()
|
||||
.cloned()
|
||||
.unwrap();
|
||||
last.forced_push_at(index, v, exit)?;
|
||||
}
|
||||
|
||||
let first_index = Some(first_index.to_usize()? as i64);
|
||||
let last_index = Some(last_index.to_usize()? as i64);
|
||||
|
||||
let needs_sum_or_average = self.sum.is_some() || self.average.is_some();
|
||||
let needs_sorted = self.max.is_some() || self.min.is_some();
|
||||
let needs_values = needs_sorted || needs_sum_or_average;
|
||||
|
||||
if needs_values {
|
||||
if needs_sorted {
|
||||
if let Some(max) = self.max.as_mut() {
|
||||
let mut values = source
|
||||
.max
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.collect_range(first_index, last_index)?;
|
||||
values.sort_unstable();
|
||||
max.forced_push_at(i, values.last().unwrap().clone(), exit)?;
|
||||
}
|
||||
|
||||
if let Some(min) = self.min.as_mut() {
|
||||
let mut values = source
|
||||
.min
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.collect_range(first_index, last_index)?;
|
||||
values.sort_unstable();
|
||||
min.forced_push_at(i, values.first().unwrap().clone(), exit)?;
|
||||
}
|
||||
}
|
||||
|
||||
if needs_sum_or_average {
|
||||
if let Some(average) = self.average.as_mut() {
|
||||
let values = source
|
||||
.average
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.collect_range(first_index, last_index)?;
|
||||
let len = values.len() as f64;
|
||||
let total = values
|
||||
.into_iter()
|
||||
.map(|v| f64::from(v))
|
||||
.fold(0.0, |a, b| a + b);
|
||||
// TODO: Multiply by count then divide by total
|
||||
// Right now it's not 100% accurate as there could be more or less elements in the lower timeframe (28 days vs 31 days in a month for example)
|
||||
let avg = T::from(total / len);
|
||||
average.forced_push_at(i, avg, exit)?;
|
||||
}
|
||||
|
||||
if let Some(sum_vec) = self.sum.as_mut() {
|
||||
let values = source
|
||||
.sum
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.collect_range(first_index, last_index)?;
|
||||
let sum = values.into_iter().fold(T::from(0), |a, b| a + b);
|
||||
sum_vec.forced_push_at(i, sum, exit)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_percentile(sorted: &[T], percentile: f64) -> T {
|
||||
let len = sorted.len();
|
||||
|
||||
if len == 0 {
|
||||
panic!();
|
||||
} else if len == 1 {
|
||||
sorted[0].clone()
|
||||
} else {
|
||||
let index = (len - 1) as f64 * percentile;
|
||||
|
||||
let fract = index.fract();
|
||||
|
||||
if fract != 0.0 {
|
||||
let left = sorted.get(index as usize).unwrap().clone();
|
||||
let right = sorted.get(index.ceil() as usize).unwrap().clone();
|
||||
left / 2 + right / 2
|
||||
} else {
|
||||
sorted.get(index as usize).unwrap().clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn starting_index(&self, max_from: I) -> I {
|
||||
max_from.min(I::from(
|
||||
self.as_any_vecs()
|
||||
.into_iter()
|
||||
.map(|v| v.len())
|
||||
.min()
|
||||
.unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
|
||||
let mut v: Vec<&dyn AnyStorableVec> = vec![];
|
||||
|
||||
if let Some(first) = self.first.as_ref() {
|
||||
v.push(first.any_vec());
|
||||
}
|
||||
if let Some(last) = self.last.as_ref() {
|
||||
v.push(last.any_vec());
|
||||
}
|
||||
if let Some(min) = self.min.as_ref() {
|
||||
v.push(min.any_vec());
|
||||
}
|
||||
if let Some(max) = self.max.as_ref() {
|
||||
v.push(max.any_vec());
|
||||
}
|
||||
if let Some(median) = self.median.as_ref() {
|
||||
v.push(median.any_vec());
|
||||
}
|
||||
if let Some(average) = self.average.as_ref() {
|
||||
v.push(average.any_vec());
|
||||
}
|
||||
if let Some(sum) = self.sum.as_ref() {
|
||||
v.push(sum.any_vec());
|
||||
}
|
||||
if let Some(_90p) = self._90p.as_ref() {
|
||||
v.push(_90p.any_vec());
|
||||
}
|
||||
if let Some(_75p) = self._75p.as_ref() {
|
||||
v.push(_75p.any_vec());
|
||||
}
|
||||
if let Some(_25p) = self._25p.as_ref() {
|
||||
v.push(_25p.any_vec());
|
||||
}
|
||||
if let Some(_10p) = self._10p.as_ref() {
|
||||
v.push(_10p.any_vec());
|
||||
}
|
||||
|
||||
v
|
||||
}
|
||||
|
||||
pub fn safe_flush(&mut self, exit: &Exit) -> Result<()> {
|
||||
if let Some(first) = self.first.as_mut() {
|
||||
first.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(last) = self.last.as_mut() {
|
||||
last.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(min) = self.min.as_mut() {
|
||||
min.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(max) = self.max.as_mut() {
|
||||
max.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(median) = self.median.as_mut() {
|
||||
median.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(average) = self.average.as_mut() {
|
||||
average.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(sum) = self.sum.as_mut() {
|
||||
sum.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(_90p) = self._90p.as_mut() {
|
||||
_90p.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(_75p) = self._75p.as_mut() {
|
||||
_75p.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(_25p) = self._25p.as_mut() {
|
||||
_25p.safe_flush(exit)?;
|
||||
}
|
||||
if let Some(_10p) = self._10p.as_mut() {
|
||||
_10p.safe_flush(exit)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Copy)]
|
||||
pub struct StorableVecGeneatorOptions {
|
||||
average: bool,
|
||||
sum: bool,
|
||||
max: bool,
|
||||
_90p: bool,
|
||||
_75p: bool,
|
||||
median: bool,
|
||||
_25p: bool,
|
||||
_10p: bool,
|
||||
min: bool,
|
||||
first: bool,
|
||||
last: bool,
|
||||
}
|
||||
|
||||
impl StorableVecGeneatorOptions {
|
||||
pub fn add_first(mut self) -> Self {
|
||||
self.first = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_last(mut self) -> Self {
|
||||
self.last = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_min(mut self) -> Self {
|
||||
self.min = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_max(mut self) -> Self {
|
||||
self.max = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_median(mut self) -> Self {
|
||||
self.median = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_average(mut self) -> Self {
|
||||
self.average = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_sum(mut self) -> Self {
|
||||
self.sum = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_90p(mut self) -> Self {
|
||||
self._90p = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_75p(mut self) -> Self {
|
||||
self._75p = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_25p(mut self) -> Self {
|
||||
self._25p = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_10p(mut self) -> Self {
|
||||
self._10p = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_min(mut self) -> Self {
|
||||
self.min = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_max(mut self) -> Self {
|
||||
self.max = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_median(mut self) -> Self {
|
||||
self.median = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_average(mut self) -> Self {
|
||||
self.average = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_sum(mut self) -> Self {
|
||||
self.sum = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_90p(mut self) -> Self {
|
||||
self._90p = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_75p(mut self) -> Self {
|
||||
self._75p = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_25p(mut self) -> Self {
|
||||
self._25p = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rm_10p(mut self) -> Self {
|
||||
self._10p = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_minmax(mut self) -> Self {
|
||||
self.min = true;
|
||||
self.max = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_percentiles(mut self) -> Self {
|
||||
self._90p = true;
|
||||
self._75p = true;
|
||||
self.median = true;
|
||||
self._25p = true;
|
||||
self._10p = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn remove_percentiles(mut self) -> Self {
|
||||
self._90p = false;
|
||||
self._75p = false;
|
||||
self.median = false;
|
||||
self._25p = false;
|
||||
self._10p = false;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_only_one_active(&self) -> bool {
|
||||
[
|
||||
self.average,
|
||||
self.sum,
|
||||
self.max,
|
||||
self._90p,
|
||||
self._75p,
|
||||
self.median,
|
||||
self._25p,
|
||||
self._10p,
|
||||
self.min,
|
||||
self.first,
|
||||
self.last,
|
||||
]
|
||||
.iter()
|
||||
.filter(|b| **b)
|
||||
.count()
|
||||
== 1
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
mod from_date;
|
||||
mod from_height;
|
||||
mod from_height_strict;
|
||||
mod generic;
|
||||
mod stored_type;
|
||||
|
||||
pub use from_date::*;
|
||||
pub use from_height::*;
|
||||
pub use from_height_strict::*;
|
||||
pub use generic::*;
|
||||
pub use stored_type::*;
|
||||
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -4,10 +4,10 @@ use brk_vec::StoredType;
|
||||
|
||||
pub trait ComputedType
|
||||
where
|
||||
Self: StoredType + From<usize> + Div<usize, Output = Self> + Add<Output = Self>,
|
||||
Self: StoredType + From<usize> + Div<usize, Output = Self> + Add<Output = Self> + Ord,
|
||||
{
|
||||
}
|
||||
impl<T> ComputedType for T where
|
||||
T: StoredType + From<usize> + Div<usize, Output = Self> + Add<Output = Self>
|
||||
T: StoredType + From<usize> + Div<usize, Output = Self> + Add<Output = Self> + Ord
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,540 @@
|
||||
use core::error;
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
fmt::Debug,
|
||||
ops::Add,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use brk_core::{Bitcoin, CheckedSub, Close, Dollars, Height, Sats, StoredUsize, TxIndex};
|
||||
use brk_exit::Exit;
|
||||
use brk_vec::{
|
||||
Compressed, DynamicVec, Error, GenericVec, Result, StoredIndex, StoredType, StoredVec,
|
||||
StoredVecIterator, Value, Version,
|
||||
};
|
||||
use color_eyre::eyre::ContextCompat;
|
||||
use log::info;
|
||||
|
||||
const ONE_KIB: usize = 1024;
|
||||
const ONE_MIB: usize = ONE_KIB * ONE_KIB;
|
||||
const MAX_CACHE_SIZE: usize = 210 * ONE_MIB;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EagerVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
computed_version: Option<Version>,
|
||||
inner: StoredVec<I, T>,
|
||||
}
|
||||
|
||||
impl<I, T> EagerVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
const SIZE_OF: usize = size_of::<T>();
|
||||
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
version: Version,
|
||||
compressed: Compressed,
|
||||
) -> brk_vec::Result<Self> {
|
||||
let inner = StoredVec::forced_import(path, version, compressed)?;
|
||||
|
||||
Ok(Self {
|
||||
computed_version: None,
|
||||
inner,
|
||||
})
|
||||
}
|
||||
|
||||
fn safe_truncate_if_needed(&mut self, index: I, exit: &Exit) -> Result<()> {
|
||||
if exit.triggered() {
|
||||
return Ok(());
|
||||
}
|
||||
exit.block();
|
||||
self.inner.truncate_if_needed(index)?;
|
||||
exit.release();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn forced_push_at(&mut self, index: I, value: T, exit: &Exit) -> Result<()> {
|
||||
match self.len().cmp(&index.to_usize()?) {
|
||||
Ordering::Less => {
|
||||
return Err(Error::IndexTooHigh);
|
||||
}
|
||||
ord => {
|
||||
if ord == Ordering::Greater {
|
||||
self.safe_truncate_if_needed(index, exit)?;
|
||||
}
|
||||
self.inner.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
if self.inner.pushed_len() * Self::SIZE_OF >= MAX_CACHE_SIZE {
|
||||
self.safe_flush(exit)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn safe_flush(&mut self, exit: &Exit) -> Result<()> {
|
||||
if exit.triggered() {
|
||||
return Ok(());
|
||||
}
|
||||
exit.block();
|
||||
self.inner.flush()?;
|
||||
exit.release();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn version(&self) -> Version {
|
||||
self.inner.version()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.inner.len()
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.inner.is_empty()
|
||||
}
|
||||
|
||||
fn file_name(&self) -> String {
|
||||
self.inner.file_name()
|
||||
}
|
||||
|
||||
pub fn vec(&self) -> &StoredVec<I, T> {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub fn mut_vec(&mut self) -> &StoredVec<I, T> {
|
||||
&mut self.inner
|
||||
}
|
||||
|
||||
pub fn any_vec(&self) -> &dyn brk_vec::AnyStoredVec {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub fn mut_any_vec(&mut self) -> &mut dyn brk_vec::AnyStoredVec {
|
||||
&mut self.inner
|
||||
}
|
||||
|
||||
pub fn path(&self) -> &Path {
|
||||
self.inner.path()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn path_computed_version(&self) -> PathBuf {
|
||||
self.inner.path().join("computed_version")
|
||||
}
|
||||
|
||||
fn validate_computed_version_or_reset_file(&mut self, version: Version) -> Result<()> {
|
||||
let path = self.path_computed_version();
|
||||
if version.validate(path.as_ref()).is_err() {
|
||||
self.inner.reset()?;
|
||||
}
|
||||
version.write(path.as_ref())?;
|
||||
|
||||
if self.is_empty() {
|
||||
info!("Computing {}...", self.file_name())
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> StoredVecIterator<I, T> {
|
||||
self.into_iter()
|
||||
}
|
||||
|
||||
pub fn compute_range<A, F>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
other: &StoredVec<I, A>,
|
||||
mut t: F,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
A: StoredType,
|
||||
F: FnMut(I) -> (I, T),
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + other.version(),
|
||||
)?;
|
||||
|
||||
let index = max_from.min(I::from(self.len()));
|
||||
(index.to_usize()?..other.len()).try_for_each(|i| {
|
||||
let (i, v) = t(I::from(i));
|
||||
self.forced_push_at(i, v, exit)
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
|
||||
pub fn compute_transform<A, B, F>(
|
||||
&mut self,
|
||||
max_from: A,
|
||||
other: &StoredVec<A, B>,
|
||||
mut t: F,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
A: StoredIndex,
|
||||
B: StoredType,
|
||||
F: FnMut((A, B, &Self)) -> (I, T),
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + other.version(),
|
||||
)?;
|
||||
|
||||
let index = max_from.min(A::from(self.len()));
|
||||
other.iter_at(index).try_for_each(|(a, b)| {
|
||||
let (i, v) = t((a, b.into_inner(), self));
|
||||
self.forced_push_at(i, v, exit)
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
|
||||
pub fn compute_inverse_more_to_less(
|
||||
&mut self,
|
||||
max_from: T,
|
||||
other: &StoredVec<T, I>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
I: StoredType + StoredIndex,
|
||||
T: StoredIndex,
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + other.version(),
|
||||
)?;
|
||||
|
||||
let index = max_from.min(
|
||||
self.inner
|
||||
.iter()
|
||||
.last()
|
||||
.map_or_else(T::default, |(_, v)| v.into_inner()),
|
||||
);
|
||||
let mut prev_i = None;
|
||||
other.iter_at(index).try_for_each(|(v, i)| -> Result<()> {
|
||||
let i = i.into_inner();
|
||||
if prev_i.is_some_and(|prev_i| prev_i == i) {
|
||||
return Ok(());
|
||||
}
|
||||
if self
|
||||
.inner
|
||||
.get(i)?
|
||||
.is_none_or(|old_v| old_v.into_inner() > v)
|
||||
{
|
||||
self.forced_push_at(i, v, exit)?;
|
||||
}
|
||||
prev_i.replace(i);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
|
||||
pub fn compute_inverse_less_to_more(
|
||||
&mut self,
|
||||
max_from: T,
|
||||
first_indexes: &StoredVec<T, I>,
|
||||
indexes_count: &StoredVec<T, StoredUsize>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
I: StoredType,
|
||||
T: StoredIndex,
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + first_indexes.version() + indexes_count.version(),
|
||||
)?;
|
||||
|
||||
let mut indexes_count_iter = indexes_count.iter();
|
||||
|
||||
let index = max_from.min(T::from(self.len()));
|
||||
first_indexes
|
||||
.iter_at(index)
|
||||
.try_for_each(|(value, first_index)| {
|
||||
let first_index = (first_index).to_usize()?;
|
||||
let count = *indexes_count_iter.unwrap_get_inner(value);
|
||||
(first_index..first_index + count)
|
||||
.try_for_each(|index| self.forced_push_at(I::from(index), value, exit))
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
|
||||
pub fn compute_count_from_indexes<T2, T3>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
first_indexes: &StoredVec<I, T2>,
|
||||
other_to_else: &StoredVec<T2, T3>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
T: From<T2>,
|
||||
T2: StoredType
|
||||
+ StoredIndex
|
||||
+ Copy
|
||||
+ Add<usize, Output = T2>
|
||||
+ CheckedSub<T2>
|
||||
+ TryInto<T>
|
||||
+ Default,
|
||||
<T2 as TryInto<T>>::Error: error::Error + 'static,
|
||||
T3: StoredType,
|
||||
{
|
||||
let opt: Option<Box<dyn FnMut(T2) -> bool>> = None;
|
||||
self.compute_filtered_count_from_indexes_(max_from, first_indexes, other_to_else, opt, exit)
|
||||
}
|
||||
|
||||
pub fn compute_filtered_count_from_indexes<T2, T3, F>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
first_indexes: &StoredVec<I, T2>,
|
||||
other_to_else: &StoredVec<T2, T3>,
|
||||
filter: F,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
T: From<T2>,
|
||||
T2: StoredType
|
||||
+ StoredIndex
|
||||
+ Copy
|
||||
+ Add<usize, Output = T2>
|
||||
+ CheckedSub<T2>
|
||||
+ TryInto<T>
|
||||
+ Default,
|
||||
<T2 as TryInto<T>>::Error: error::Error + 'static,
|
||||
T3: StoredType,
|
||||
F: FnMut(T2) -> bool,
|
||||
{
|
||||
self.compute_filtered_count_from_indexes_(
|
||||
max_from,
|
||||
first_indexes,
|
||||
other_to_else,
|
||||
Some(Box::new(filter)),
|
||||
exit,
|
||||
)
|
||||
}
|
||||
|
||||
fn compute_filtered_count_from_indexes_<T2, T3>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
first_indexes: &StoredVec<I, T2>,
|
||||
other_to_else: &StoredVec<T2, T3>,
|
||||
mut filter: Option<Box<dyn FnMut(T2) -> bool + '_>>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
T: From<T2>,
|
||||
T2: StoredType
|
||||
+ StoredIndex
|
||||
+ Copy
|
||||
+ Add<usize, Output = T2>
|
||||
+ CheckedSub<T2>
|
||||
+ TryInto<T>
|
||||
+ Default,
|
||||
T3: StoredType,
|
||||
<T2 as TryInto<T>>::Error: error::Error + 'static,
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + first_indexes.version(), // + last_indexes.version(),
|
||||
)?;
|
||||
|
||||
let mut other_iter = first_indexes.iter();
|
||||
let index = max_from.min(I::from(self.len()));
|
||||
first_indexes
|
||||
.iter_at(index)
|
||||
.try_for_each(|(i, first_index)| {
|
||||
let end = other_iter
|
||||
.get(i + 1)
|
||||
.map(|(_, v)| v.into_inner().unwrap_to_usize())
|
||||
.unwrap_or_else(|| other_to_else.len());
|
||||
|
||||
let range = first_index.unwrap_to_usize()..end;
|
||||
let count = if let Some(filter) = filter.as_mut() {
|
||||
range.into_iter().filter(|i| filter(T2::from(*i))).count()
|
||||
} else {
|
||||
range.count()
|
||||
};
|
||||
self.forced_push_at(i, T::from(T2::from(count)), exit)
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
|
||||
pub fn compute_is_first_ordered<A>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
self_to_other: &StoredVec<I, A>,
|
||||
other_to_self: &StoredVec<A, I>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
I: StoredType,
|
||||
T: From<bool>,
|
||||
A: StoredIndex + StoredType,
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + self_to_other.version() + other_to_self.version(),
|
||||
)?;
|
||||
|
||||
let mut other_to_self_iter = other_to_self.iter();
|
||||
let index = max_from.min(I::from(self.len()));
|
||||
self_to_other.iter_at(index).try_for_each(|(i, other)| {
|
||||
self.forced_push_at(
|
||||
i,
|
||||
T::from(
|
||||
other_to_self_iter
|
||||
.get(other.into_inner())
|
||||
.unwrap()
|
||||
.1
|
||||
.into_inner()
|
||||
== i,
|
||||
),
|
||||
exit,
|
||||
)
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
|
||||
pub fn compute_sum_from_indexes<T2>(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
first_indexes: &StoredVec<I, T2>,
|
||||
indexes_count: &StoredVec<I, StoredUsize>,
|
||||
source: &StoredVec<T2, T>,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
T: From<usize> + Add<T, Output = T>,
|
||||
T2: StoredIndex + StoredType,
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + first_indexes.version() + indexes_count.version(),
|
||||
)?;
|
||||
|
||||
let mut indexes_count_iter = indexes_count.iter();
|
||||
let mut source_iter = source.iter();
|
||||
let index = max_from.min(I::from(self.len()));
|
||||
first_indexes
|
||||
.iter_at(index)
|
||||
.try_for_each(|(i, first_index)| {
|
||||
let count = *indexes_count_iter.get(i).unwrap().1.into_inner();
|
||||
let first_index = first_index.unwrap_to_usize();
|
||||
let range = first_index..first_index + count;
|
||||
let mut sum = T::from(0_usize);
|
||||
range.into_iter().for_each(|i| {
|
||||
sum = sum.clone() + source_iter.get(T2::from(i)).unwrap().1.into_inner();
|
||||
});
|
||||
self.forced_push_at(i, sum, exit)
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> EagerVec<I, Bitcoin>
|
||||
where
|
||||
I: StoredIndex,
|
||||
{
|
||||
pub fn compute_from_sats(
|
||||
&mut self,
|
||||
max_from: I,
|
||||
sats: &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_at(index).try_for_each(|(i, sats)| {
|
||||
let (i, v) = (i, Bitcoin::from(sats.into_inner()));
|
||||
self.forced_push_at(i, v, exit)
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
}
|
||||
|
||||
impl EagerVec<Height, Dollars> {
|
||||
pub fn compute_from_bitcoin(
|
||||
&mut self,
|
||||
max_from: Height,
|
||||
bitcoin: &StoredVec<Height, Bitcoin>,
|
||||
price: &StoredVec<Height, Close<Dollars>>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + bitcoin.version(),
|
||||
)?;
|
||||
|
||||
let mut price_iter = price.iter();
|
||||
let index = max_from.min(Height::from(self.len()));
|
||||
bitcoin.iter_at(index).try_for_each(|(i, bitcoin)| {
|
||||
let dollars = price_iter.get(i).unwrap().1.into_inner();
|
||||
let (i, v) = (i, *dollars * bitcoin.into_inner());
|
||||
self.forced_push_at(i, v, exit)
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
}
|
||||
|
||||
impl EagerVec<TxIndex, Dollars> {
|
||||
pub fn compute_from_bitcoin(
|
||||
&mut self,
|
||||
max_from: TxIndex,
|
||||
bitcoin: &StoredVec<TxIndex, Bitcoin>,
|
||||
i_to_height: &StoredVec<TxIndex, Height>,
|
||||
price: &StoredVec<Height, Close<Dollars>>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::ZERO + self.version() + bitcoin.version(),
|
||||
)?;
|
||||
|
||||
let mut i_to_height_iter = i_to_height.iter();
|
||||
let mut price_iter = price.iter();
|
||||
let index = max_from.min(TxIndex::from(self.len()));
|
||||
bitcoin.iter_at(index).try_for_each(|(i, bitcoin, ..)| {
|
||||
let height = i_to_height_iter.get(i).unwrap().1.into_inner();
|
||||
let dollars = price_iter.get(height).unwrap().1.into_inner();
|
||||
let (i, v) = (i, *dollars * bitcoin.into_inner());
|
||||
self.forced_push_at(i, v, exit)
|
||||
})?;
|
||||
|
||||
self.safe_flush(exit)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> Clone for EagerVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
computed_version: self.computed_version,
|
||||
inner: self.inner.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, I, T> IntoIterator for &'a EagerVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
type Item = (I, Value<'a, T>);
|
||||
type IntoIter = StoredVecIterator<'a, I, T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.inner.into_iter()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
use brk_vec::{DynamicVec, GenericVec, StoredIndex, StoredType, StoredVec, Version};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LazyVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
inner: StoredVec<I, T>,
|
||||
}
|
||||
|
||||
impl<I, T> LazyVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
const SIZE_OF: usize = size_of::<T>();
|
||||
|
||||
fn version(&self) -> Version {
|
||||
self.inner.version()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.inner.len()
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.inner.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> Clone for LazyVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
inner: self.inner.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
mod _type;
|
||||
mod eager;
|
||||
mod lazy;
|
||||
|
||||
pub use _type::*;
|
||||
pub use eager::*;
|
||||
pub use lazy::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum Mode {
|
||||
Lazy,
|
||||
Eager,
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
<a href="https://deps.rs/crate/brk_core">
|
||||
<img src="https://deps.rs/crate/brk_core/latest/status.svg" alt="Dependency status">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cvrwpv3zEG">
|
||||
<a href="https://discord.gg/HaR3wpH3nr">
|
||||
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
|
||||
@@ -29,7 +29,7 @@
|
||||
<a href="https://bsky.app/profile/bitcoinresearchkit.org">
|
||||
<img src="https://img.shields.io/badge/bluesky-blue?link=https%3A%2F%2Fbsky.app%2Fprofile%2Fbitcoinresearchkit.org" alt="Bluesky" />
|
||||
</a>
|
||||
<a href="https://x.com/0xbrk">
|
||||
<a href="https://x.com/brkdotorg">
|
||||
<img src="https://img.shields.io/badge/x.com-black" alt="X" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
+15
-15
@@ -21,9 +21,9 @@ use crate::Error;
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Addressindex(u32);
|
||||
pub struct AddressIndex(u32);
|
||||
|
||||
impl Addressindex {
|
||||
impl AddressIndex {
|
||||
pub const BYTES: usize = size_of::<Self>();
|
||||
|
||||
pub fn increment(&mut self) {
|
||||
@@ -35,56 +35,56 @@ impl Addressindex {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for Addressindex {
|
||||
impl From<u32> for AddressIndex {
|
||||
fn from(value: u32) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Addressindex {
|
||||
impl From<u64> for AddressIndex {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(value as u32)
|
||||
}
|
||||
}
|
||||
impl From<Addressindex> for u64 {
|
||||
fn from(value: Addressindex) -> Self {
|
||||
impl From<AddressIndex> for u64 {
|
||||
fn from(value: AddressIndex) -> Self {
|
||||
value.0 as u64
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Addressindex {
|
||||
impl From<usize> for AddressIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u32)
|
||||
}
|
||||
}
|
||||
impl From<Addressindex> for usize {
|
||||
fn from(value: Addressindex) -> Self {
|
||||
impl From<AddressIndex> for usize {
|
||||
fn from(value: AddressIndex) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ByteView> for Addressindex {
|
||||
impl TryFrom<ByteView> for AddressIndex {
|
||||
type Error = Error;
|
||||
fn try_from(value: ByteView) -> Result<Self, Self::Error> {
|
||||
Ok(Self::read_from_bytes(&value)?)
|
||||
}
|
||||
}
|
||||
impl From<Addressindex> for ByteView {
|
||||
fn from(value: Addressindex) -> Self {
|
||||
impl From<AddressIndex> for ByteView {
|
||||
fn from(value: AddressIndex) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Addressindex {
|
||||
impl Add<usize> for AddressIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 + rhs as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Addressindex> for Addressindex {
|
||||
impl Add<AddressIndex> for AddressIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Addressindex) -> Self::Output {
|
||||
fn add(self, rhs: AddressIndex) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
use byteview::ByteView;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::Error;
|
||||
|
||||
use super::{AddressIndex, Outputindex};
|
||||
|
||||
#[derive(
|
||||
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Immutable, IntoBytes, KnownLayout, FromBytes,
|
||||
)]
|
||||
#[repr(C)]
|
||||
pub struct AddressIndexOutputIndex {
|
||||
addressindex: AddressIndex,
|
||||
_padding: u32,
|
||||
outputindex: Outputindex,
|
||||
}
|
||||
|
||||
impl TryFrom<ByteView> for AddressIndexOutputIndex {
|
||||
type Error = Error;
|
||||
fn try_from(value: ByteView) -> Result<Self, Self::Error> {
|
||||
Ok(Self::read_from_bytes(&value)?)
|
||||
}
|
||||
}
|
||||
impl From<AddressIndexOutputIndex> for ByteView {
|
||||
fn from(value: AddressIndexOutputIndex) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
use serde::Serialize;
|
||||
use zerocopy::{Immutable, IntoBytes, KnownLayout, TryFromBytes};
|
||||
|
||||
use super::OutputType;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
TryFromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
#[repr(u8)]
|
||||
pub enum AddressType {
|
||||
P2PK65,
|
||||
P2PK33,
|
||||
P2PKH,
|
||||
P2SH,
|
||||
P2WPKH,
|
||||
P2WSH,
|
||||
P2TR,
|
||||
P2A,
|
||||
}
|
||||
|
||||
impl From<OutputType> for AddressType {
|
||||
fn from(value: OutputType) -> Self {
|
||||
match value {
|
||||
OutputType::P2A => Self::P2A,
|
||||
OutputType::P2PK33 => Self::P2PK33,
|
||||
OutputType::P2PK65 => Self::P2PK65,
|
||||
OutputType::P2PKH => Self::P2PKH,
|
||||
OutputType::P2SH => Self::P2SH,
|
||||
OutputType::P2TR => Self::P2TR,
|
||||
OutputType::P2WPKH => Self::P2WPKH,
|
||||
OutputType::P2WSH => Self::P2WSH,
|
||||
OutputType::Empty | OutputType::OpReturn | OutputType::P2MS | OutputType::Unknown => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,40 +12,42 @@ use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::Error;
|
||||
|
||||
use super::Addresstype;
|
||||
use super::OutputType;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Addressbytes {
|
||||
P2PK65(P2PK65AddressBytes),
|
||||
P2PK33(P2PK33AddressBytes),
|
||||
P2PKH(P2PKHAddressBytes),
|
||||
P2SH(P2SHAddressBytes),
|
||||
P2WPKH(P2WPKHAddressBytes),
|
||||
P2WSH(P2WSHAddressBytes),
|
||||
P2TR(P2TRAddressBytes),
|
||||
pub enum AddressBytes {
|
||||
P2PK65(P2PK65Bytes),
|
||||
P2PK33(P2PK33Bytes),
|
||||
P2PKH(P2PKHBytes),
|
||||
P2SH(P2SHBytes),
|
||||
P2WPKH(P2WPKHBytes),
|
||||
P2WSH(P2WSHBytes),
|
||||
P2TR(P2TRBytes),
|
||||
P2A(P2ABytes),
|
||||
}
|
||||
|
||||
impl Addressbytes {
|
||||
impl AddressBytes {
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
match self {
|
||||
Addressbytes::P2PK65(bytes) => &bytes[..],
|
||||
Addressbytes::P2PK33(bytes) => &bytes[..],
|
||||
Addressbytes::P2PKH(bytes) => &bytes[..],
|
||||
Addressbytes::P2SH(bytes) => &bytes[..],
|
||||
Addressbytes::P2WPKH(bytes) => &bytes[..],
|
||||
Addressbytes::P2WSH(bytes) => &bytes[..],
|
||||
Addressbytes::P2TR(bytes) => &bytes[..],
|
||||
AddressBytes::P2PK65(bytes) => &bytes[..],
|
||||
AddressBytes::P2PK33(bytes) => &bytes[..],
|
||||
AddressBytes::P2PKH(bytes) => &bytes[..],
|
||||
AddressBytes::P2SH(bytes) => &bytes[..],
|
||||
AddressBytes::P2WPKH(bytes) => &bytes[..],
|
||||
AddressBytes::P2WSH(bytes) => &bytes[..],
|
||||
AddressBytes::P2TR(bytes) => &bytes[..],
|
||||
AddressBytes::P2A(bytes) => &bytes[..],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<(&ScriptBuf, Addresstype)> for Addressbytes {
|
||||
impl TryFrom<(&ScriptBuf, OutputType)> for AddressBytes {
|
||||
type Error = Error;
|
||||
fn try_from(tuple: (&ScriptBuf, Addresstype)) -> Result<Self, Self::Error> {
|
||||
let (script, addresstype) = tuple;
|
||||
fn try_from(tuple: (&ScriptBuf, OutputType)) -> Result<Self, Self::Error> {
|
||||
let (script, outputtype) = tuple;
|
||||
|
||||
match addresstype {
|
||||
Addresstype::P2PK65 => {
|
||||
match outputtype {
|
||||
OutputType::P2PK65 => {
|
||||
let bytes = script.as_bytes();
|
||||
let bytes = match bytes.len() {
|
||||
67 => &bytes[1..66],
|
||||
@@ -54,9 +56,9 @@ impl TryFrom<(&ScriptBuf, Addresstype)> for Addressbytes {
|
||||
return Err(Error::WrongLength);
|
||||
}
|
||||
};
|
||||
Ok(Self::P2PK65(P2PK65AddressBytes(U8x65::from(bytes))))
|
||||
Ok(Self::P2PK65(P2PK65Bytes(U8x65::from(bytes))))
|
||||
}
|
||||
Addresstype::P2PK33 => {
|
||||
OutputType::P2PK33 => {
|
||||
let bytes = script.as_bytes();
|
||||
let bytes = match bytes.len() {
|
||||
35 => &bytes[1..34],
|
||||
@@ -65,47 +67,50 @@ impl TryFrom<(&ScriptBuf, Addresstype)> for Addressbytes {
|
||||
return Err(Error::WrongLength);
|
||||
}
|
||||
};
|
||||
Ok(Self::P2PK33(P2PK33AddressBytes(U8x33::from(bytes))))
|
||||
Ok(Self::P2PK33(P2PK33Bytes(U8x33::from(bytes))))
|
||||
}
|
||||
Addresstype::P2PKH => {
|
||||
OutputType::P2PKH => {
|
||||
let bytes = &script.as_bytes()[3..23];
|
||||
Ok(Self::P2PKH(P2PKHAddressBytes(U8x20::from(bytes))))
|
||||
Ok(Self::P2PKH(P2PKHBytes(U8x20::from(bytes))))
|
||||
}
|
||||
Addresstype::P2SH => {
|
||||
OutputType::P2SH => {
|
||||
let bytes = &script.as_bytes()[2..22];
|
||||
Ok(Self::P2SH(P2SHAddressBytes(U8x20::from(bytes))))
|
||||
Ok(Self::P2SH(P2SHBytes(U8x20::from(bytes))))
|
||||
}
|
||||
Addresstype::P2WPKH => {
|
||||
OutputType::P2WPKH => {
|
||||
let bytes = &script.as_bytes()[2..];
|
||||
Ok(Self::P2WPKH(P2WPKHAddressBytes(U8x20::from(bytes))))
|
||||
Ok(Self::P2WPKH(P2WPKHBytes(U8x20::from(bytes))))
|
||||
}
|
||||
Addresstype::P2WSH => {
|
||||
OutputType::P2WSH => {
|
||||
let bytes = &script.as_bytes()[2..];
|
||||
Ok(Self::P2WSH(P2WSHAddressBytes(U8x32::from(bytes))))
|
||||
Ok(Self::P2WSH(P2WSHBytes(U8x32::from(bytes))))
|
||||
}
|
||||
Addresstype::P2TR => {
|
||||
OutputType::P2TR => {
|
||||
let bytes = &script.as_bytes()[2..];
|
||||
Ok(Self::P2TR(P2TRAddressBytes(U8x32::from(bytes))))
|
||||
Ok(Self::P2TR(P2TRBytes(U8x32::from(bytes))))
|
||||
}
|
||||
Addresstype::Multisig => Err(Error::WrongAddressType),
|
||||
Addresstype::PushOnly => Err(Error::WrongAddressType),
|
||||
Addresstype::Unknown => Err(Error::WrongAddressType),
|
||||
Addresstype::Empty => Err(Error::WrongAddressType),
|
||||
Addresstype::OpReturn => Err(Error::WrongAddressType),
|
||||
OutputType::P2A => {
|
||||
let bytes = &script.as_bytes()[2..];
|
||||
Ok(Self::P2A(P2ABytes(U8x2::from(bytes))))
|
||||
}
|
||||
OutputType::P2MS => Err(Error::WrongAddressType),
|
||||
OutputType::Unknown => Err(Error::WrongAddressType),
|
||||
OutputType::Empty => Err(Error::WrongAddressType),
|
||||
OutputType::OpReturn => Err(Error::WrongAddressType),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2PK65AddressBytes(U8x65);
|
||||
pub struct P2PK65Bytes(U8x65);
|
||||
|
||||
impl fmt::Display for P2PK65AddressBytes {
|
||||
impl fmt::Display for P2PK65Bytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.to_hex_string(Case::Lower))
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2PK65AddressBytes {
|
||||
impl Serialize for P2PK65Bytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
@@ -114,22 +119,22 @@ impl Serialize for P2PK65AddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2PK65AddressBytes> for Addressbytes {
|
||||
fn from(value: P2PK65AddressBytes) -> Self {
|
||||
impl From<P2PK65Bytes> for AddressBytes {
|
||||
fn from(value: P2PK65Bytes) -> Self {
|
||||
Self::P2PK65(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2PK33AddressBytes(U8x33);
|
||||
pub struct P2PK33Bytes(U8x33);
|
||||
|
||||
impl fmt::Display for P2PK33AddressBytes {
|
||||
impl fmt::Display for P2PK33Bytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.to_hex_string(Case::Lower))
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2PK33AddressBytes {
|
||||
impl Serialize for P2PK33Bytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
@@ -138,16 +143,16 @@ impl Serialize for P2PK33AddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2PK33AddressBytes> for Addressbytes {
|
||||
fn from(value: P2PK33AddressBytes) -> Self {
|
||||
impl From<P2PK33Bytes> for AddressBytes {
|
||||
fn from(value: P2PK33Bytes) -> Self {
|
||||
Self::P2PK33(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2PKHAddressBytes(U8x20);
|
||||
pub struct P2PKHBytes(U8x20);
|
||||
|
||||
impl fmt::Display for P2PKHAddressBytes {
|
||||
impl fmt::Display for P2PKHBytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let script = Builder::new()
|
||||
.push_opcode(opcodes::all::OP_DUP)
|
||||
@@ -161,7 +166,7 @@ impl fmt::Display for P2PKHAddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2PKHAddressBytes {
|
||||
impl Serialize for P2PKHBytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
@@ -170,16 +175,16 @@ impl Serialize for P2PKHAddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2PKHAddressBytes> for Addressbytes {
|
||||
fn from(value: P2PKHAddressBytes) -> Self {
|
||||
impl From<P2PKHBytes> for AddressBytes {
|
||||
fn from(value: P2PKHBytes) -> Self {
|
||||
Self::P2PKH(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2SHAddressBytes(U8x20);
|
||||
pub struct P2SHBytes(U8x20);
|
||||
|
||||
impl fmt::Display for P2SHAddressBytes {
|
||||
impl fmt::Display for P2SHBytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let script = Builder::new()
|
||||
.push_opcode(opcodes::all::OP_HASH160)
|
||||
@@ -191,7 +196,7 @@ impl fmt::Display for P2SHAddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2SHAddressBytes {
|
||||
impl Serialize for P2SHBytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
@@ -200,16 +205,16 @@ impl Serialize for P2SHAddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2SHAddressBytes> for Addressbytes {
|
||||
fn from(value: P2SHAddressBytes) -> Self {
|
||||
impl From<P2SHBytes> for AddressBytes {
|
||||
fn from(value: P2SHBytes) -> Self {
|
||||
Self::P2SH(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2WPKHAddressBytes(U8x20);
|
||||
pub struct P2WPKHBytes(U8x20);
|
||||
|
||||
impl fmt::Display for P2WPKHAddressBytes {
|
||||
impl fmt::Display for P2WPKHBytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let script = Builder::new().push_int(0).push_slice(*self.0).into_script();
|
||||
let address = Address::from_script(&script, Network::Bitcoin).unwrap();
|
||||
@@ -217,7 +222,7 @@ impl fmt::Display for P2WPKHAddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2WPKHAddressBytes {
|
||||
impl Serialize for P2WPKHBytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
@@ -226,16 +231,16 @@ impl Serialize for P2WPKHAddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2WPKHAddressBytes> for Addressbytes {
|
||||
fn from(value: P2WPKHAddressBytes) -> Self {
|
||||
impl From<P2WPKHBytes> for AddressBytes {
|
||||
fn from(value: P2WPKHBytes) -> Self {
|
||||
Self::P2WPKH(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2WSHAddressBytes(U8x32);
|
||||
pub struct P2WSHBytes(U8x32);
|
||||
|
||||
impl fmt::Display for P2WSHAddressBytes {
|
||||
impl fmt::Display for P2WSHBytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let script = Builder::new().push_int(0).push_slice(*self.0).into_script();
|
||||
let address = Address::from_script(&script, Network::Bitcoin).unwrap();
|
||||
@@ -243,7 +248,7 @@ impl fmt::Display for P2WSHAddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2WSHAddressBytes {
|
||||
impl Serialize for P2WSHBytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
@@ -252,16 +257,16 @@ impl Serialize for P2WSHAddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2WSHAddressBytes> for Addressbytes {
|
||||
fn from(value: P2WSHAddressBytes) -> Self {
|
||||
impl From<P2WSHBytes> for AddressBytes {
|
||||
fn from(value: P2WSHBytes) -> Self {
|
||||
Self::P2WSH(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2TRAddressBytes(U8x32);
|
||||
pub struct P2TRBytes(U8x32);
|
||||
|
||||
impl fmt::Display for P2TRAddressBytes {
|
||||
impl fmt::Display for P2TRBytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let script = Builder::new().push_int(1).push_slice(*self.0).into_script();
|
||||
let address = Address::from_script(&script, Network::Bitcoin).unwrap();
|
||||
@@ -269,7 +274,7 @@ impl fmt::Display for P2TRAddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2TRAddressBytes {
|
||||
impl Serialize for P2TRBytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
@@ -278,12 +283,60 @@ impl Serialize for P2TRAddressBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2TRAddressBytes> for Addressbytes {
|
||||
fn from(value: P2TRAddressBytes) -> Self {
|
||||
impl From<P2TRBytes> for AddressBytes {
|
||||
fn from(value: P2TRBytes) -> Self {
|
||||
Self::P2TR(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2ABytes(U8x2);
|
||||
|
||||
impl fmt::Display for P2ABytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let script = Builder::new().push_int(1).push_slice(*self.0).into_script();
|
||||
let address = Address::from_script(&script, Network::Bitcoin).unwrap();
|
||||
write!(f, "{}", address)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2ABytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.collect_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2ABytes> for AddressBytes {
|
||||
fn from(value: P2ABytes) -> Self {
|
||||
Self::P2A(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Deref,
|
||||
DerefMut,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
FromBytes,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct U8x2([u8; 2]);
|
||||
impl From<&[u8]> for U8x2 {
|
||||
fn from(slice: &[u8]) -> Self {
|
||||
let mut arr = [0; 2];
|
||||
arr.copy_from_slice(slice);
|
||||
Self(arr)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
use std::hash::Hasher;
|
||||
|
||||
use byteview::ByteView;
|
||||
use derive_deref::Deref;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::Error;
|
||||
|
||||
use super::{AddressBytes, OutputType};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct AddressBytesHash([u8; 8]);
|
||||
|
||||
impl From<(&AddressBytes, OutputType)> for AddressBytesHash {
|
||||
fn from((address_bytes, outputtype): (&AddressBytes, OutputType)) -> Self {
|
||||
let mut hasher = rapidhash::RapidHasher::default();
|
||||
hasher.write(address_bytes.as_slice());
|
||||
let mut slice = hasher.finish().to_le_bytes();
|
||||
slice[0] = slice[0].wrapping_add(outputtype as u8);
|
||||
Self(slice)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; 8]> for AddressBytesHash {
|
||||
fn from(value: [u8; 8]) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ByteView> for AddressBytesHash {
|
||||
type Error = Error;
|
||||
fn try_from(value: ByteView) -> Result<Self, Self::Error> {
|
||||
Ok(Self::read_from_bytes(&value)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&AddressBytesHash> for ByteView {
|
||||
fn from(value: &AddressBytesHash) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AddressBytesHash> for ByteView {
|
||||
fn from(value: AddressBytesHash) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
use byteview::ByteView;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::Error;
|
||||
|
||||
use super::{Addressindex, Txoutindex};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
#[repr(C)]
|
||||
pub struct AddressindexTxoutindex {
|
||||
addressindex: Addressindex,
|
||||
_padding: u32,
|
||||
txoutindex: Txoutindex,
|
||||
}
|
||||
|
||||
impl TryFrom<ByteView> for AddressindexTxoutindex {
|
||||
type Error = Error;
|
||||
fn try_from(value: ByteView) -> Result<Self, Self::Error> {
|
||||
Ok(Self::read_from_bytes(&value)?)
|
||||
}
|
||||
}
|
||||
impl From<AddressindexTxoutindex> for ByteView {
|
||||
fn from(value: AddressindexTxoutindex) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
@@ -1,560 +0,0 @@
|
||||
use std::ops::Add;
|
||||
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Addresstypeindex(u32);
|
||||
|
||||
impl Addresstypeindex {
|
||||
pub fn increment(&mut self) {
|
||||
self.0 += 1;
|
||||
}
|
||||
|
||||
pub fn incremented(self) -> Self {
|
||||
Self(self.0 + 1)
|
||||
}
|
||||
|
||||
pub fn copy_then_increment(&mut self) -> Self {
|
||||
let i = *self;
|
||||
self.increment();
|
||||
i
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for Addresstypeindex {
|
||||
fn from(value: u32) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Addresstypeindex {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(value as u32)
|
||||
}
|
||||
}
|
||||
impl From<Addresstypeindex> for u64 {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
value.0 as u64
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Addresstypeindex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u32)
|
||||
}
|
||||
}
|
||||
impl From<Addresstypeindex> for usize {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Addresstypeindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 + rhs as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Addresstypeindex> for Addresstypeindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Addresstypeindex) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Emptyindex(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for Emptyindex {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<Emptyindex> for usize {
|
||||
fn from(value: Emptyindex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for Emptyindex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for Emptyindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Multisigindex(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for Multisigindex {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<Multisigindex> for usize {
|
||||
fn from(value: Multisigindex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for Multisigindex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for Multisigindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Opreturnindex(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for Opreturnindex {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<Opreturnindex> for usize {
|
||||
fn from(value: Opreturnindex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for Opreturnindex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for Opreturnindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Pushonlyindex(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for Pushonlyindex {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<Pushonlyindex> for usize {
|
||||
fn from(value: Pushonlyindex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for Pushonlyindex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for Pushonlyindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Unknownindex(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for Unknownindex {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<Unknownindex> for usize {
|
||||
fn from(value: Unknownindex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for Unknownindex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for Unknownindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2PK33index(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for P2PK33index {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2PK33index> for usize {
|
||||
fn from(value: P2PK33index) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2PK33index {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2PK33index {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2PK65index(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for P2PK65index {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2PK65index> for usize {
|
||||
fn from(value: P2PK65index) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2PK65index {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2PK65index {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2PKHindex(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for P2PKHindex {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2PKHindex> for usize {
|
||||
fn from(value: P2PKHindex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2PKHindex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2PKHindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2SHindex(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for P2SHindex {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2SHindex> for usize {
|
||||
fn from(value: P2SHindex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2SHindex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2SHindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2TRindex(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for P2TRindex {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2TRindex> for usize {
|
||||
fn from(value: P2TRindex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2TRindex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2TRindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2WPKHindex(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for P2WPKHindex {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2WPKHindex> for usize {
|
||||
fn from(value: P2WPKHindex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2WPKHindex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2WPKHindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2WSHindex(Addresstypeindex);
|
||||
impl From<Addresstypeindex> for P2WSHindex {
|
||||
fn from(value: Addresstypeindex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2WSHindex> for usize {
|
||||
fn from(value: P2WSHindex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2WSHindex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Addresstypeindex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2WSHindex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,49 @@
|
||||
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::from(Sats::from(self) + Sats::from(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul for Bitcoin {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 * rhs.0)
|
||||
Self::from(Sats::from(self) * Sats::from(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for Bitcoin {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self::from(Sats::from(self) / rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Sats> for Bitcoin {
|
||||
fn from(value: Sats) -> Self {
|
||||
Self(u64::from(value) as f64 / (u64::from(Sats::ONE_BTC) as f64))
|
||||
Self(f64::from(value) / (f64::from(Sats::ONE_BTC)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
use byteview::ByteView;
|
||||
use derive_deref::Deref;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::{Error, copy_first_8bytes};
|
||||
|
||||
use super::BlockHash;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct BlockHashPrefix([u8; 8]);
|
||||
|
||||
impl From<BlockHash> for BlockHashPrefix {
|
||||
fn from(value: BlockHash) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&BlockHash> for BlockHashPrefix {
|
||||
fn from(value: &BlockHash) -> Self {
|
||||
Self(copy_first_8bytes(&value[..]).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ByteView> for BlockHashPrefix {
|
||||
type Error = Error;
|
||||
fn try_from(value: ByteView) -> Result<Self, Self::Error> {
|
||||
Ok(Self::read_from_bytes(&value)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&BlockHashPrefix> for ByteView {
|
||||
fn from(value: &BlockHashPrefix) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BlockHashPrefix> for ByteView {
|
||||
fn from(value: BlockHashPrefix) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::ops::{Add, Div};
|
||||
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
@@ -22,7 +24,7 @@ pub struct Cents(u64);
|
||||
|
||||
impl From<Dollars> for Cents {
|
||||
fn from(value: Dollars) -> Self {
|
||||
Self((*value * 100.0).floor() as u64)
|
||||
Self((*value * 100.0).round() as u64)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,3 +33,29 @@ impl From<Cents> for f64 {
|
||||
value.0 as f64
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Cents {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Cents> for u64 {
|
||||
fn from(value: Cents) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Cents {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for Cents {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 / rhs as u64)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
use std::hash::Hasher;
|
||||
|
||||
use byteview::ByteView;
|
||||
use derive_deref::Deref;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::Error;
|
||||
|
||||
use super::{Addressbytes, Addresstype, BlockHash, Txid};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct AddressHash([u8; 8]);
|
||||
impl From<(&Addressbytes, Addresstype)> for AddressHash {
|
||||
fn from((addressbytes, addresstype): (&Addressbytes, Addresstype)) -> Self {
|
||||
let mut hasher = rapidhash::RapidHasher::default();
|
||||
hasher.write(addressbytes.as_slice());
|
||||
let mut slice = hasher.finish().to_le_bytes();
|
||||
slice[0] = slice[0].wrapping_add(addresstype as u8);
|
||||
Self(slice)
|
||||
}
|
||||
}
|
||||
impl From<[u8; 8]> for AddressHash {
|
||||
fn from(value: [u8; 8]) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl TryFrom<ByteView> for AddressHash {
|
||||
type Error = Error;
|
||||
fn try_from(value: ByteView) -> Result<Self, Self::Error> {
|
||||
Ok(Self::read_from_bytes(&value)?)
|
||||
}
|
||||
}
|
||||
impl From<&AddressHash> for ByteView {
|
||||
fn from(value: &AddressHash) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
impl From<AddressHash> for ByteView {
|
||||
fn from(value: AddressHash) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct BlockHashPrefix([u8; 8]);
|
||||
impl From<BlockHash> for BlockHashPrefix {
|
||||
fn from(value: BlockHash) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
impl From<&BlockHash> for BlockHashPrefix {
|
||||
fn from(value: &BlockHash) -> Self {
|
||||
Self(copy_first_8bytes(&value[..]).unwrap())
|
||||
}
|
||||
}
|
||||
impl TryFrom<ByteView> for BlockHashPrefix {
|
||||
type Error = Error;
|
||||
fn try_from(value: ByteView) -> Result<Self, Self::Error> {
|
||||
Ok(Self::read_from_bytes(&value)?)
|
||||
}
|
||||
}
|
||||
impl From<&BlockHashPrefix> for ByteView {
|
||||
fn from(value: &BlockHashPrefix) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
impl From<BlockHashPrefix> for ByteView {
|
||||
fn from(value: BlockHashPrefix) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct TxidPrefix([u8; 8]);
|
||||
impl From<Txid> for TxidPrefix {
|
||||
fn from(value: Txid) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
impl From<&Txid> for TxidPrefix {
|
||||
fn from(value: &Txid) -> Self {
|
||||
Self(copy_first_8bytes(&value[..]).unwrap())
|
||||
}
|
||||
}
|
||||
impl TryFrom<ByteView> for TxidPrefix {
|
||||
type Error = Error;
|
||||
fn try_from(value: ByteView) -> Result<Self, Self::Error> {
|
||||
Ok(Self::read_from_bytes(&value)?)
|
||||
}
|
||||
}
|
||||
impl From<&TxidPrefix> for ByteView {
|
||||
fn from(value: &TxidPrefix) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
impl From<TxidPrefix> for ByteView {
|
||||
fn from(value: TxidPrefix) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
impl From<[u8; 8]> for TxidPrefix {
|
||||
fn from(value: [u8; 8]) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
fn copy_first_8bytes(slice: &[u8]) -> Result<[u8; 8], ()> {
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
let buf_len = buf.len();
|
||||
if slice.len() < buf_len {
|
||||
return Err(());
|
||||
}
|
||||
slice.iter().take(buf_len).enumerate().for_each(|(i, r)| {
|
||||
buf[i] = *r;
|
||||
});
|
||||
Ok(buf)
|
||||
}
|
||||
@@ -2,7 +2,7 @@ use jiff::{Span, civil::Date as Date_, tz::TimeZone};
|
||||
use serde::{Serialize, Serializer};
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use super::{Dateindex, Timestamp};
|
||||
use super::{DateIndex, Timestamp};
|
||||
|
||||
#[derive(
|
||||
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, FromBytes, Immutable, IntoBytes, KnownLayout,
|
||||
@@ -58,9 +58,9 @@ impl From<Timestamp> for Date {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Dateindex> for Date {
|
||||
fn from(value: Dateindex) -> Self {
|
||||
if value == Dateindex::default() {
|
||||
impl From<DateIndex> for Date {
|
||||
fn from(value: DateIndex) -> Self {
|
||||
if value == DateIndex::default() {
|
||||
Date::INDEX_ZERO
|
||||
} else {
|
||||
Self::from(
|
||||
|
||||
@@ -23,38 +23,38 @@ use super::Date;
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Dateindex(u16);
|
||||
pub struct DateIndex(u16);
|
||||
|
||||
impl Dateindex {
|
||||
impl DateIndex {
|
||||
pub const BYTES: usize = size_of::<Self>();
|
||||
}
|
||||
|
||||
impl From<Dateindex> for usize {
|
||||
fn from(value: Dateindex) -> Self {
|
||||
impl From<DateIndex> for usize {
|
||||
fn from(value: DateIndex) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Dateindex {
|
||||
impl From<usize> for DateIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u16)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Dateindex> for i64 {
|
||||
fn from(value: Dateindex) -> Self {
|
||||
impl From<DateIndex> for i64 {
|
||||
fn from(value: DateIndex) -> Self {
|
||||
value.0 as i64
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Dateindex {
|
||||
impl Add<usize> for DateIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 + rhs as u16)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Date> for Dateindex {
|
||||
impl TryFrom<Date> for DateIndex {
|
||||
type Error = Error;
|
||||
fn try_from(value: Date) -> Result<Self, Self::Error> {
|
||||
let value_ = jiff::civil::Date::from(value);
|
||||
@@ -72,7 +72,7 @@ impl TryFrom<Date> for Dateindex {
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for Dateindex {
|
||||
impl CheckedSub for DateIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
use super::{Date, Dateindex, Yearindex};
|
||||
use super::{Date, DateIndex, YearIndex};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
@@ -23,27 +23,27 @@ use super::{Date, Dateindex, Yearindex};
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct Decadeindex(u8);
|
||||
pub struct DecadeIndex(u8);
|
||||
|
||||
impl From<u8> for Decadeindex {
|
||||
impl From<u8> for DecadeIndex {
|
||||
fn from(value: u8) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Decadeindex {
|
||||
impl From<usize> for DecadeIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u8)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Decadeindex> for usize {
|
||||
fn from(value: Decadeindex) -> Self {
|
||||
impl From<DecadeIndex> for usize {
|
||||
fn from(value: DecadeIndex) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Decadeindex {
|
||||
impl Add<usize> for DecadeIndex {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
@@ -51,13 +51,13 @@ impl Add<usize> for Decadeindex {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Dateindex> for Decadeindex {
|
||||
fn from(value: Dateindex) -> Self {
|
||||
impl From<DateIndex> for DecadeIndex {
|
||||
fn from(value: DateIndex) -> Self {
|
||||
Self::from(Date::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Date> for Decadeindex {
|
||||
impl From<Date> for DecadeIndex {
|
||||
fn from(value: Date) -> Self {
|
||||
let year = value.year();
|
||||
if year < 2000 {
|
||||
@@ -67,14 +67,14 @@ impl From<Date> for Decadeindex {
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for Decadeindex {
|
||||
impl CheckedSub for DecadeIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Yearindex> for Decadeindex {
|
||||
fn from(value: Yearindex) -> Self {
|
||||
impl From<YearIndex> for DecadeIndex {
|
||||
fn from(value: YearIndex) -> Self {
|
||||
let v = usize::from(value);
|
||||
if v == 0 {
|
||||
Self(0)
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use std::{fmt::Debug, ops::Add};
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
ops::{Add, Div},
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
@@ -23,27 +26,35 @@ use super::Height;
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct Difficultyepoch(u16);
|
||||
pub struct DifficultyEpoch(u16);
|
||||
|
||||
impl From<u16> for Difficultyepoch {
|
||||
impl From<u16> for DifficultyEpoch {
|
||||
fn from(value: u16) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Difficultyepoch {
|
||||
impl From<usize> for DifficultyEpoch {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u16)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Difficultyepoch> for usize {
|
||||
fn from(value: Difficultyepoch) -> Self {
|
||||
impl From<DifficultyEpoch> for usize {
|
||||
fn from(value: DifficultyEpoch) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Difficultyepoch {
|
||||
impl Add for DifficultyEpoch {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self::from(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for DifficultyEpoch {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
@@ -51,13 +62,20 @@ impl Add<usize> for Difficultyepoch {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Height> for Difficultyepoch {
|
||||
impl Div<usize> for DifficultyEpoch {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self::from(self.0 as usize / rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Height> for DifficultyEpoch {
|
||||
fn from(value: Height) -> Self {
|
||||
Self((u32::from(value) / 2016) as u16)
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for Difficultyepoch {
|
||||
impl CheckedSub for DifficultyEpoch {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
|
||||
@@ -1,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,
|
||||
@@ -49,14 +49,14 @@ impl From<usize> for Dollars {
|
||||
impl Add for Dollars {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
Self::from(Cents::from(self) + Cents::from(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for Dollars {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 / rhs as f64)
|
||||
Self::from(Cents::from(self) / rhs)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,3 +68,12 @@ impl Ord for Dollars {
|
||||
self.0.partial_cmp(&other.0).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Bitcoin> for Dollars {
|
||||
type Output = Dollars;
|
||||
fn mul(self, rhs: Bitcoin) -> Self::Output {
|
||||
Self::from(Cents::from(
|
||||
u64::from(Sats::from(rhs)) * u64::from(Cents::from(self)) / u64::from(Sats::ONE_BTC),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,66 @@
|
||||
use std::ops::{Add, Div};
|
||||
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, FromBytes, Immutable, IntoBytes, KnownLayout)]
|
||||
use super::{Sats, StoredUsize};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Copy,
|
||||
Serialize,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct Feerate(f32);
|
||||
|
||||
impl From<(Sats, StoredUsize)> for Feerate {
|
||||
fn from((sats, vsize): (Sats, StoredUsize)) -> Self {
|
||||
Self((f64::from(sats) / f64::from(vsize)) as f32)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for Feerate {
|
||||
fn from(value: f64) -> Self {
|
||||
Self(value as f32)
|
||||
}
|
||||
}
|
||||
impl From<Feerate> for f64 {
|
||||
fn from(value: Feerate) -> Self {
|
||||
value.0 as f64
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Feerate {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for Feerate {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self((self.0 as f64 / rhs as f64) as f32)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Feerate {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as f32)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Feerate {}
|
||||
|
||||
#[allow(clippy::derive_ord_xor_partial_ord)]
|
||||
impl Ord for Feerate {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.0.partial_cmp(&other.0).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use std::{fmt::Debug, ops::Add};
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
ops::{Add, Div},
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
@@ -23,27 +26,35 @@ use super::Height;
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct Halvingepoch(u8);
|
||||
pub struct HalvingEpoch(u8);
|
||||
|
||||
impl From<u8> for Halvingepoch {
|
||||
impl From<u8> for HalvingEpoch {
|
||||
fn from(value: u8) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Halvingepoch {
|
||||
impl From<usize> for HalvingEpoch {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u8)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Halvingepoch> for usize {
|
||||
fn from(value: Halvingepoch) -> Self {
|
||||
impl From<HalvingEpoch> for usize {
|
||||
fn from(value: HalvingEpoch) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Halvingepoch {
|
||||
impl Add for HalvingEpoch {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self::from(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for HalvingEpoch {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
@@ -51,14 +62,21 @@ impl Add<usize> for Halvingepoch {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Height> for Halvingepoch {
|
||||
impl From<Height> for HalvingEpoch {
|
||||
fn from(value: Height) -> Self {
|
||||
Self((u32::from(value) / 210_000) as u8)
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for Halvingepoch {
|
||||
impl CheckedSub for HalvingEpoch {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for HalvingEpoch {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self::from(self.0 as usize / rhs)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ use crate::CheckedSub;
|
||||
pub struct Height(u32);
|
||||
|
||||
impl Height {
|
||||
pub const ZERO: Self = Height(0);
|
||||
pub const MAX: Self = Height(u32::MAX);
|
||||
pub const ZERO: Self = Self(0);
|
||||
pub const MAX: Self = Self(u32::MAX);
|
||||
|
||||
pub fn new(height: u32) -> Self {
|
||||
Self(height)
|
||||
@@ -181,12 +181,6 @@ impl From<bitcoin::locktime::absolute::Height> for Height {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Height> for bitcoin::locktime::absolute::Height {
|
||||
fn from(value: Height) -> Self {
|
||||
bitcoin::locktime::absolute::Height::from_consensus(value.0).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&std::path::Path> for Height {
|
||||
type Error = crate::Error;
|
||||
fn try_from(value: &std::path::Path) -> Result<Self, Self::Error> {
|
||||
|
||||
+17
-17
@@ -25,49 +25,49 @@ use super::Vin;
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Txinindex(u64);
|
||||
pub struct InputIndex(u64);
|
||||
|
||||
impl Txinindex {
|
||||
impl InputIndex {
|
||||
pub fn incremented(self) -> Self {
|
||||
Self(*self + 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Txinindex> for Txinindex {
|
||||
impl Add<InputIndex> for InputIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Txinindex) -> Self::Output {
|
||||
fn add(self, rhs: InputIndex) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Vin> for Txinindex {
|
||||
impl Add<Vin> for InputIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Vin) -> Self::Output {
|
||||
Self(self.0 + u64::from(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Txinindex {
|
||||
impl Add<usize> for InputIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 + rhs as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<Txinindex> for Txinindex {
|
||||
fn add_assign(&mut self, rhs: Txinindex) {
|
||||
impl AddAssign<InputIndex> for InputIndex {
|
||||
fn add_assign(&mut self, rhs: InputIndex) {
|
||||
self.0 += rhs.0
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub<Txinindex> for Txinindex {
|
||||
impl CheckedSub<InputIndex> for InputIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self::from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Txinindex> for u32 {
|
||||
fn from(value: Txinindex) -> Self {
|
||||
impl From<InputIndex> for u32 {
|
||||
fn from(value: InputIndex) -> Self {
|
||||
if value.0 > u32::MAX as u64 {
|
||||
panic!()
|
||||
}
|
||||
@@ -75,24 +75,24 @@ impl From<Txinindex> for u32 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Txinindex {
|
||||
impl From<u64> for InputIndex {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<Txinindex> for u64 {
|
||||
fn from(value: Txinindex) -> Self {
|
||||
impl From<InputIndex> for u64 {
|
||||
fn from(value: InputIndex) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Txinindex {
|
||||
impl From<usize> for InputIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u64)
|
||||
}
|
||||
}
|
||||
impl From<Txinindex> for usize {
|
||||
fn from(value: Txinindex) -> Self {
|
||||
impl From<InputIndex> for usize {
|
||||
fn from(value: InputIndex) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
use serde::Serialize;
|
||||
use zerocopy::{Immutable, IntoBytes, KnownLayout, TryFromBytes};
|
||||
|
||||
use super::{Height, Timestamp};
|
||||
|
||||
#[derive(Debug, Immutable, Clone, Copy, IntoBytes, KnownLayout, TryFromBytes, Serialize)]
|
||||
#[repr(C)]
|
||||
#[allow(warnings)]
|
||||
pub enum LockTime {
|
||||
Height(Height),
|
||||
Timestamp(Timestamp),
|
||||
}
|
||||
|
||||
impl From<bitcoin::absolute::LockTime> for LockTime {
|
||||
fn from(value: bitcoin::absolute::LockTime) -> Self {
|
||||
match value {
|
||||
bitcoin::absolute::LockTime::Blocks(h) => LockTime::Height(h.into()),
|
||||
bitcoin::absolute::LockTime::Seconds(t) => LockTime::Timestamp(t.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LockTime> for bitcoin::absolute::LockTime {
|
||||
fn from(value: LockTime) -> Self {
|
||||
match value {
|
||||
LockTime::Height(h) => bitcoin::absolute::LockTime::Blocks(h.into()),
|
||||
LockTime::Timestamp(t) => bitcoin::absolute::LockTime::Seconds(t.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
mod addressbytes;
|
||||
mod addressindex;
|
||||
mod addressindextxoutindex;
|
||||
mod addresstype;
|
||||
mod addresstypeindex;
|
||||
mod addressbyteshash;
|
||||
// mod addressindex;
|
||||
// mod addressindexoutputindex;
|
||||
// mod addresstype;
|
||||
mod bitcoin;
|
||||
mod blockhash;
|
||||
mod blockhashprefix;
|
||||
mod cents;
|
||||
mod compressed;
|
||||
mod date;
|
||||
mod dateindex;
|
||||
mod decadeindex;
|
||||
@@ -15,16 +15,24 @@ mod dollars;
|
||||
mod feerate;
|
||||
mod halvingepoch;
|
||||
mod height;
|
||||
mod locktime;
|
||||
mod inputindex;
|
||||
mod monthindex;
|
||||
mod ohlc;
|
||||
mod outputindex;
|
||||
mod outputtype;
|
||||
mod outputtypeindex;
|
||||
mod quarterindex;
|
||||
mod rawlocktime;
|
||||
mod sats;
|
||||
mod stored_f64;
|
||||
mod stored_u32;
|
||||
mod stored_u64;
|
||||
mod stored_u8;
|
||||
mod stored_usize;
|
||||
mod timestamp;
|
||||
mod txid;
|
||||
mod txidprefix;
|
||||
mod txindex;
|
||||
mod txinindex;
|
||||
mod txoutindex;
|
||||
mod txversion;
|
||||
mod unit;
|
||||
mod vin;
|
||||
@@ -34,14 +42,14 @@ mod weight;
|
||||
mod yearindex;
|
||||
|
||||
pub use addressbytes::*;
|
||||
pub use addressindex::*;
|
||||
pub use addressindextxoutindex::*;
|
||||
pub use addresstype::*;
|
||||
pub use addresstypeindex::*;
|
||||
pub use addressbyteshash::*;
|
||||
// pub use addressindex::*;
|
||||
// pub use addressindexoutputindex::*;
|
||||
// pub use addresstype::*;
|
||||
pub use bitcoin::*;
|
||||
pub use blockhash::*;
|
||||
pub use blockhashprefix::*;
|
||||
pub use cents::*;
|
||||
pub use compressed::*;
|
||||
pub use date::*;
|
||||
pub use dateindex::*;
|
||||
pub use decadeindex::*;
|
||||
@@ -50,16 +58,24 @@ pub use dollars::*;
|
||||
pub use feerate::*;
|
||||
pub use halvingepoch::*;
|
||||
pub use height::*;
|
||||
pub use locktime::*;
|
||||
pub use inputindex::*;
|
||||
pub use monthindex::*;
|
||||
pub use ohlc::*;
|
||||
pub use outputindex::*;
|
||||
pub use outputtype::*;
|
||||
pub use outputtypeindex::*;
|
||||
pub use quarterindex::*;
|
||||
pub use rawlocktime::*;
|
||||
pub use sats::*;
|
||||
pub use stored_f64::*;
|
||||
pub use stored_u8::*;
|
||||
pub use stored_u32::*;
|
||||
pub use stored_u64::*;
|
||||
pub use stored_usize::*;
|
||||
pub use timestamp::*;
|
||||
pub use txid::*;
|
||||
pub use txidprefix::*;
|
||||
pub use txindex::*;
|
||||
pub use txinindex::*;
|
||||
pub use txoutindex::*;
|
||||
pub use txversion::*;
|
||||
pub use unit::*;
|
||||
pub use vin::*;
|
||||
|
||||
@@ -5,7 +5,7 @@ use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
use super::{Date, Dateindex, Yearindex};
|
||||
use super::{Date, DateIndex, YearIndex};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
@@ -23,27 +23,27 @@ use super::{Date, Dateindex, Yearindex};
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct Monthindex(u16);
|
||||
pub struct MonthIndex(u16);
|
||||
|
||||
impl From<u16> for Monthindex {
|
||||
impl From<u16> for MonthIndex {
|
||||
fn from(value: u16) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Monthindex {
|
||||
impl From<usize> for MonthIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u16)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Monthindex> for usize {
|
||||
fn from(value: Monthindex) -> Self {
|
||||
impl From<MonthIndex> for usize {
|
||||
fn from(value: MonthIndex) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Monthindex {
|
||||
impl Add<usize> for MonthIndex {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
@@ -51,19 +51,19 @@ impl Add<usize> for Monthindex {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Dateindex> for Monthindex {
|
||||
fn from(value: Dateindex) -> Self {
|
||||
impl From<DateIndex> for MonthIndex {
|
||||
fn from(value: DateIndex) -> Self {
|
||||
Self::from(Date::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Date> for Monthindex {
|
||||
impl From<Date> for MonthIndex {
|
||||
fn from(value: Date) -> Self {
|
||||
Self(u16::from(Yearindex::from(value)) * 12 + value.month() as u16 - 1)
|
||||
Self(u16::from(YearIndex::from(value)) * 12 + value.month() as u16 - 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for Monthindex {
|
||||
impl CheckedSub for MonthIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use super::{Cents, Dollars, Sats};
|
||||
|
||||
#[derive(Debug, Default, Clone, FromBytes, Immutable, IntoBytes, KnownLayout, Serialize)]
|
||||
#[derive(Debug, Default, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
|
||||
#[repr(C)]
|
||||
pub struct OHLCCents {
|
||||
pub open: Open<Cents>,
|
||||
@@ -37,6 +37,20 @@ impl From<Close<Cents>> for OHLCCents {
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for OHLCCents {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut tup = serializer.serialize_tuple(4)?;
|
||||
tup.serialize_element(&self.open)?;
|
||||
tup.serialize_element(&self.high)?;
|
||||
tup.serialize_element(&self.low)?;
|
||||
tup.serialize_element(&self.close)?;
|
||||
tup.end()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
|
||||
#[repr(C)]
|
||||
pub struct OHLCDollars {
|
||||
@@ -99,6 +113,51 @@ impl From<&OHLCCents> for OHLCDollars {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
|
||||
#[repr(C)]
|
||||
pub struct OHLCSats {
|
||||
pub open: Open<Sats>,
|
||||
pub high: High<Sats>,
|
||||
pub low: Low<Sats>,
|
||||
pub close: Close<Sats>,
|
||||
}
|
||||
|
||||
impl Serialize for OHLCSats {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut tup = serializer.serialize_tuple(4)?;
|
||||
tup.serialize_element(&self.open)?;
|
||||
tup.serialize_element(&self.high)?;
|
||||
tup.serialize_element(&self.low)?;
|
||||
tup.serialize_element(&self.close)?;
|
||||
tup.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(Open<Sats>, High<Sats>, Low<Sats>, Close<Sats>)> for OHLCSats {
|
||||
fn from(value: (Open<Sats>, High<Sats>, Low<Sats>, Close<Sats>)) -> Self {
|
||||
Self {
|
||||
open: value.0,
|
||||
high: value.1,
|
||||
low: value.2,
|
||||
close: value.3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Close<Sats>> for OHLCSats {
|
||||
fn from(value: Close<Sats>) -> Self {
|
||||
Self {
|
||||
open: Open::from(value),
|
||||
high: High::from(value),
|
||||
low: Low::from(value),
|
||||
close: value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Default,
|
||||
@@ -117,12 +176,40 @@ impl From<&OHLCCents> for OHLCDollars {
|
||||
)]
|
||||
#[repr(C)]
|
||||
pub struct Open<T>(T);
|
||||
impl<T> From<T> for Open<T> {
|
||||
fn from(value: T) -> Self {
|
||||
|
||||
impl<T> Open<T> {
|
||||
pub fn new(value: T) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<usize> for Open<T>
|
||||
where
|
||||
T: From<usize>,
|
||||
{
|
||||
fn from(value: usize) -> Self {
|
||||
Self(T::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<f64> for Open<T>
|
||||
where
|
||||
T: From<f64>,
|
||||
{
|
||||
fn from(value: f64) -> Self {
|
||||
Self(T::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Open<T>> for f64
|
||||
where
|
||||
f64: From<T>,
|
||||
{
|
||||
fn from(value: Open<T>) -> Self {
|
||||
Self::from(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Close<T>> for Open<T>
|
||||
where
|
||||
T: Copy,
|
||||
@@ -138,24 +225,6 @@ impl From<Open<Cents>> for Open<Dollars> {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Open<Dollars> {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Dollars::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for Open<Dollars> {
|
||||
fn from(value: f64) -> Self {
|
||||
Self(Dollars::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Open<Dollars>> for f64 {
|
||||
fn from(value: Open<Dollars>) -> Self {
|
||||
Self::from(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Add for Open<T>
|
||||
where
|
||||
T: Add<Output = T>,
|
||||
@@ -194,12 +263,40 @@ where
|
||||
)]
|
||||
#[repr(C)]
|
||||
pub struct High<T>(T);
|
||||
impl<T> From<T> for High<T> {
|
||||
fn from(value: T) -> Self {
|
||||
|
||||
impl<T> High<T> {
|
||||
pub fn new(value: T) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<usize> for High<T>
|
||||
where
|
||||
T: From<usize>,
|
||||
{
|
||||
fn from(value: usize) -> Self {
|
||||
Self(T::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<f64> for High<T>
|
||||
where
|
||||
T: From<f64>,
|
||||
{
|
||||
fn from(value: f64) -> Self {
|
||||
Self(T::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<High<T>> for f64
|
||||
where
|
||||
f64: From<T>,
|
||||
{
|
||||
fn from(value: High<T>) -> Self {
|
||||
Self::from(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Close<T>> for High<T>
|
||||
where
|
||||
T: Copy,
|
||||
@@ -215,24 +312,6 @@ impl From<High<Cents>> for High<Dollars> {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for High<Dollars> {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Dollars::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for High<Dollars> {
|
||||
fn from(value: f64) -> Self {
|
||||
Self(Dollars::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<High<Dollars>> for f64 {
|
||||
fn from(value: High<Dollars>) -> Self {
|
||||
Self::from(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Add for High<T>
|
||||
where
|
||||
T: Add<Output = T>,
|
||||
@@ -271,12 +350,40 @@ where
|
||||
)]
|
||||
#[repr(C)]
|
||||
pub struct Low<T>(T);
|
||||
impl<T> From<T> for Low<T> {
|
||||
fn from(value: T) -> Self {
|
||||
|
||||
impl<T> Low<T> {
|
||||
pub fn new(value: T) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<usize> for Low<T>
|
||||
where
|
||||
T: From<usize>,
|
||||
{
|
||||
fn from(value: usize) -> Self {
|
||||
Self(T::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<f64> for Low<T>
|
||||
where
|
||||
T: From<f64>,
|
||||
{
|
||||
fn from(value: f64) -> Self {
|
||||
Self(T::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Low<T>> for f64
|
||||
where
|
||||
f64: From<T>,
|
||||
{
|
||||
fn from(value: Low<T>) -> Self {
|
||||
Self::from(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Close<T>> for Low<T>
|
||||
where
|
||||
T: Copy,
|
||||
@@ -292,24 +399,6 @@ impl From<Low<Cents>> for Low<Dollars> {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Low<Dollars> {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(Dollars::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for Low<Dollars> {
|
||||
fn from(value: f64) -> Self {
|
||||
Self(Dollars::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Low<Dollars>> for f64 {
|
||||
fn from(value: Low<Dollars>) -> Self {
|
||||
Self::from(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Add for Low<T>
|
||||
where
|
||||
T: Add<Output = T>,
|
||||
@@ -348,54 +437,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>,
|
||||
|
||||
+17
-17
@@ -25,9 +25,9 @@ use super::Vout;
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Txoutindex(u64);
|
||||
pub struct OutputIndex(u64);
|
||||
|
||||
impl Txoutindex {
|
||||
impl OutputIndex {
|
||||
pub const COINBASE: Self = Self(u64::MAX);
|
||||
|
||||
pub fn incremented(self) -> Self {
|
||||
@@ -39,41 +39,41 @@ impl Txoutindex {
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Txoutindex> for Txoutindex {
|
||||
impl Add<OutputIndex> for OutputIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Txoutindex) -> Self::Output {
|
||||
fn add(self, rhs: OutputIndex) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Vout> for Txoutindex {
|
||||
impl Add<Vout> for OutputIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Vout) -> Self::Output {
|
||||
Self(self.0 + u64::from(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Txoutindex {
|
||||
impl Add<usize> for OutputIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 + rhs as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<Txoutindex> for Txoutindex {
|
||||
fn add_assign(&mut self, rhs: Txoutindex) {
|
||||
impl AddAssign<OutputIndex> for OutputIndex {
|
||||
fn add_assign(&mut self, rhs: OutputIndex) {
|
||||
self.0 += rhs.0
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub<Txoutindex> for Txoutindex {
|
||||
impl CheckedSub<OutputIndex> for OutputIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self::from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Txoutindex> for u32 {
|
||||
fn from(value: Txoutindex) -> Self {
|
||||
impl From<OutputIndex> for u32 {
|
||||
fn from(value: OutputIndex) -> Self {
|
||||
if value.0 > u32::MAX as u64 {
|
||||
panic!()
|
||||
}
|
||||
@@ -81,24 +81,24 @@ impl From<Txoutindex> for u32 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Txoutindex {
|
||||
impl From<u64> for OutputIndex {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<Txoutindex> for u64 {
|
||||
fn from(value: Txoutindex) -> Self {
|
||||
impl From<OutputIndex> for u64 {
|
||||
fn from(value: OutputIndex) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Txoutindex {
|
||||
impl From<usize> for OutputIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u64)
|
||||
}
|
||||
}
|
||||
impl From<Txoutindex> for usize {
|
||||
fn from(value: Txoutindex) -> Self {
|
||||
impl From<OutputIndex> for usize {
|
||||
fn from(value: OutputIndex) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
+28
-13
@@ -1,27 +1,38 @@
|
||||
use bitcoin::ScriptBuf;
|
||||
use bitcoin::{ScriptBuf, opcodes::all::OP_PUSHBYTES_2};
|
||||
use serde::Serialize;
|
||||
use zerocopy::{Immutable, IntoBytes, KnownLayout, TryFromBytes};
|
||||
|
||||
#[derive(
|
||||
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, TryFromBytes, Immutable, IntoBytes, KnownLayout, Serialize,
|
||||
Debug,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
TryFromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
#[repr(u8)]
|
||||
pub enum Addresstype {
|
||||
pub enum OutputType {
|
||||
P2PK65,
|
||||
P2PK33,
|
||||
P2PKH,
|
||||
P2MS,
|
||||
P2SH,
|
||||
OpReturn,
|
||||
P2WPKH,
|
||||
P2WSH,
|
||||
P2TR,
|
||||
Multisig = 251,
|
||||
PushOnly = 252,
|
||||
OpReturn = 253,
|
||||
P2A,
|
||||
Empty = 254,
|
||||
Unknown = 255,
|
||||
}
|
||||
|
||||
impl From<&ScriptBuf> for Addresstype {
|
||||
impl From<&ScriptBuf> for OutputType {
|
||||
fn from(script: &ScriptBuf) -> Self {
|
||||
if script.is_p2pk() {
|
||||
let bytes = script.as_bytes();
|
||||
@@ -36,22 +47,26 @@ impl From<&ScriptBuf> for Addresstype {
|
||||
}
|
||||
} else if script.is_p2pkh() {
|
||||
Self::P2PKH
|
||||
} else if script.is_multisig() {
|
||||
Self::P2MS
|
||||
} else if script.is_p2sh() {
|
||||
Self::P2SH
|
||||
} else if script.is_op_return() {
|
||||
Self::OpReturn
|
||||
} else if script.is_p2wpkh() {
|
||||
Self::P2WPKH
|
||||
} else if script.is_p2wsh() {
|
||||
Self::P2WSH
|
||||
} else if script.is_p2tr() {
|
||||
Self::P2TR
|
||||
} else if script.witness_version() == Some(bitcoin::WitnessVersion::V1)
|
||||
&& script.len() == 4
|
||||
&& script.as_bytes()[1] == OP_PUSHBYTES_2.to_u8()
|
||||
&& script.as_bytes()[2..4] == [78, 115]
|
||||
{
|
||||
Self::P2A
|
||||
} else if script.is_empty() {
|
||||
Self::Empty
|
||||
} else if script.is_op_return() {
|
||||
Self::OpReturn
|
||||
} else if script.is_push_only() {
|
||||
Self::PushOnly
|
||||
} else if script.is_multisig() {
|
||||
Self::Multisig
|
||||
} else {
|
||||
Self::Unknown
|
||||
}
|
||||
@@ -0,0 +1,634 @@
|
||||
use std::ops::Add;
|
||||
|
||||
use byteview::ByteView;
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::{CheckedSub, Error};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct OutputTypeIndex(u32);
|
||||
|
||||
impl OutputTypeIndex {
|
||||
pub fn increment(&mut self) {
|
||||
self.0 += 1;
|
||||
}
|
||||
|
||||
pub fn incremented(self) -> Self {
|
||||
Self(self.0 + 1)
|
||||
}
|
||||
|
||||
pub fn copy_then_increment(&mut self) -> Self {
|
||||
let i = *self;
|
||||
self.increment();
|
||||
i
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for OutputTypeIndex {
|
||||
fn from(value: u32) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for OutputTypeIndex {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(value as u32)
|
||||
}
|
||||
}
|
||||
impl From<OutputTypeIndex> for u64 {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
value.0 as u64
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for OutputTypeIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u32)
|
||||
}
|
||||
}
|
||||
impl From<OutputTypeIndex> for usize {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for OutputTypeIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 + rhs as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<OutputTypeIndex> for OutputTypeIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: OutputTypeIndex) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
impl TryFrom<ByteView> for OutputTypeIndex {
|
||||
type Error = Error;
|
||||
fn try_from(value: ByteView) -> Result<Self, Self::Error> {
|
||||
Ok(Self::read_from_bytes(&value)?)
|
||||
}
|
||||
}
|
||||
impl From<OutputTypeIndex> for ByteView {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct EmptyOutputIndex(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for EmptyOutputIndex {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<EmptyOutputIndex> for usize {
|
||||
fn from(value: EmptyOutputIndex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for EmptyOutputIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for EmptyOutputIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<EmptyOutputIndex> for EmptyOutputIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2MSIndex(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for P2MSIndex {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2MSIndex> for usize {
|
||||
fn from(value: P2MSIndex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2MSIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2MSIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<P2MSIndex> for P2MSIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2AIndex(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for P2AIndex {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2AIndex> for usize {
|
||||
fn from(value: P2AIndex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2AIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2AIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<P2AIndex> for P2AIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct OpReturnIndex(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for OpReturnIndex {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<OpReturnIndex> for usize {
|
||||
fn from(value: OpReturnIndex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for OpReturnIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for OpReturnIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<OpReturnIndex> for OpReturnIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct UnknownOutputIndex(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for UnknownOutputIndex {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<UnknownOutputIndex> for usize {
|
||||
fn from(value: UnknownOutputIndex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for UnknownOutputIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for UnknownOutputIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<UnknownOutputIndex> for UnknownOutputIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2PK33Index(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for P2PK33Index {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2PK33Index> for usize {
|
||||
fn from(value: P2PK33Index) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2PK33Index {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2PK33Index {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<P2PK33Index> for P2PK33Index {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2PK65Index(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for P2PK65Index {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2PK65Index> for usize {
|
||||
fn from(value: P2PK65Index) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2PK65Index {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2PK65Index {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<P2PK65Index> for P2PK65Index {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2PKHIndex(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for P2PKHIndex {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2PKHIndex> for usize {
|
||||
fn from(value: P2PKHIndex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2PKHIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2PKHIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<P2PKHIndex> for P2PKHIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2SHIndex(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for P2SHIndex {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2SHIndex> for usize {
|
||||
fn from(value: P2SHIndex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2SHIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2SHIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<P2SHIndex> for P2SHIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2TRIndex(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for P2TRIndex {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2TRIndex> for usize {
|
||||
fn from(value: P2TRIndex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2TRIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2TRIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<P2TRIndex> for P2TRIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2WPKHIndex(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for P2WPKHIndex {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2WPKHIndex> for usize {
|
||||
fn from(value: P2WPKHIndex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2WPKHIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2WPKHIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<P2WPKHIndex> for P2WPKHIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct P2WSHIndex(OutputTypeIndex);
|
||||
impl From<OutputTypeIndex> for P2WSHIndex {
|
||||
fn from(value: OutputTypeIndex) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl From<P2WSHIndex> for usize {
|
||||
fn from(value: P2WSHIndex) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
impl From<usize> for P2WSHIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(OutputTypeIndex::from(value))
|
||||
}
|
||||
}
|
||||
impl Add<usize> for P2WSHIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(*self + rhs)
|
||||
}
|
||||
}
|
||||
impl CheckedSub<P2WSHIndex> for P2WSHIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.0.checked_sub(rhs.0.0).map(OutputTypeIndex).map(Self)
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
use super::Monthindex;
|
||||
use super::MonthIndex;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
@@ -23,27 +23,27 @@ use super::Monthindex;
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct Quarterindex(u16);
|
||||
pub struct QuarterIndex(u16);
|
||||
|
||||
impl From<u16> for Quarterindex {
|
||||
impl From<u16> for QuarterIndex {
|
||||
fn from(value: u16) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Quarterindex {
|
||||
impl From<usize> for QuarterIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u16)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Quarterindex> for usize {
|
||||
fn from(value: Quarterindex) -> Self {
|
||||
impl From<QuarterIndex> for usize {
|
||||
fn from(value: QuarterIndex) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Quarterindex {
|
||||
impl Add<usize> for QuarterIndex {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
@@ -51,13 +51,13 @@ impl Add<usize> for Quarterindex {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Monthindex> for Quarterindex {
|
||||
fn from(value: Monthindex) -> Self {
|
||||
impl From<MonthIndex> for QuarterIndex {
|
||||
fn from(value: MonthIndex) -> Self {
|
||||
Self((usize::from(value) / 3) as u16)
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for Quarterindex {
|
||||
impl CheckedSub for QuarterIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
use bitcoin::absolute::LockTime;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{Immutable, IntoBytes, KnownLayout, TryFromBytes};
|
||||
|
||||
#[derive(Debug, Immutable, Clone, Copy, IntoBytes, KnownLayout, TryFromBytes, Serialize)]
|
||||
pub struct RawLockTime(u32);
|
||||
|
||||
impl From<LockTime> for RawLockTime {
|
||||
fn from(value: LockTime) -> Self {
|
||||
Self(value.to_consensus_u32())
|
||||
}
|
||||
}
|
||||
|
||||
const CONSENSUS_DELIMITER: u32 = 500_000_000;
|
||||
|
||||
impl From<RawLockTime> for LockTime {
|
||||
fn from(value: RawLockTime) -> Self {
|
||||
let value = value.0;
|
||||
if value >= CONSENSUS_DELIMITER {
|
||||
bitcoin::locktime::absolute::Height::from_consensus(value)
|
||||
.unwrap()
|
||||
.into()
|
||||
} else {
|
||||
bitcoin::locktime::absolute::Time::from_consensus(value)
|
||||
.unwrap()
|
||||
.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
use super::{Bitcoin, Dollars, Height};
|
||||
use super::{Bitcoin, Cents, Dollars, Height};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
@@ -30,6 +30,7 @@ pub struct Sats(u64);
|
||||
|
||||
impl Sats {
|
||||
pub const ZERO: Self = Self(0);
|
||||
pub const MAX: Self = Self(u64::MAX);
|
||||
pub const ONE_BTC: Self = Self(100_000_000);
|
||||
|
||||
pub fn is_zero(&self) -> bool {
|
||||
@@ -39,8 +40,8 @@ impl Sats {
|
||||
|
||||
impl Add for Sats {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Sats) -> Self::Output {
|
||||
Sats::from(self.0 + rhs.0)
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self::from(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +94,12 @@ impl Sum for Sats {
|
||||
impl Div<Dollars> for Sats {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: Dollars) -> Self::Output {
|
||||
Self((self.0 as f64 / f64::from(rhs)) as u64)
|
||||
let raw_cents = u64::from(Cents::from(rhs));
|
||||
if raw_cents != 0 {
|
||||
Self(self.0 * 100 / raw_cents)
|
||||
} else {
|
||||
Self::MAX
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +124,7 @@ impl From<usize> for Sats {
|
||||
|
||||
impl From<f64> for Sats {
|
||||
fn from(value: f64) -> Self {
|
||||
Self(value as u64)
|
||||
Self(value.round() as u64)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +147,7 @@ impl From<Sats> for Amount {
|
||||
|
||||
impl From<Bitcoin> for Sats {
|
||||
fn from(value: Bitcoin) -> Self {
|
||||
Self((f64::from(value) * (u64::from(Sats::ONE_BTC) as f64)) as u64)
|
||||
Self((f64::from(value) * (Sats::ONE_BTC.0 as f64)).round() as u64)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
use std::ops::{Add, Div};
|
||||
|
||||
use derive_deref::Deref;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct StoredF64(f64);
|
||||
|
||||
impl From<f64> for StoredF64 {
|
||||
fn from(value: f64) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for StoredF64 {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as f64)
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub<StoredF64> for StoredF64 {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
Some(Self(self.0 - rhs.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for StoredF64 {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 / rhs as f64)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for StoredF64 {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StoredF64> for f64 {
|
||||
fn from(value: StoredF64) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for StoredF64 {}
|
||||
|
||||
#[allow(clippy::derive_ord_xor_partial_ord)]
|
||||
impl Ord for StoredF64 {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.0.partial_cmp(&other.0).unwrap()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
use std::ops::{Add, Div};
|
||||
|
||||
use derive_deref::Deref;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
use super::{
|
||||
EmptyOutputIndex, OpReturnIndex, P2AIndex, P2MSIndex, P2PK33Index, P2PK65Index, P2PKHIndex,
|
||||
P2SHIndex, P2TRIndex, P2WPKHIndex, P2WSHIndex, UnknownOutputIndex,
|
||||
};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct StoredU32(u32);
|
||||
|
||||
impl StoredU32 {
|
||||
pub const ZERO: Self = Self(0);
|
||||
|
||||
pub fn new(counter: u32) -> Self {
|
||||
Self(counter)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for StoredU32 {
|
||||
fn from(value: u32) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for StoredU32 {
|
||||
fn from(value: usize) -> Self {
|
||||
if value > u32::MAX as usize {
|
||||
panic!("usize too big (value = {value})")
|
||||
}
|
||||
Self(value as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub<StoredU32> for StoredU32 {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for StoredU32 {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 / rhs as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for StoredU32 {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for StoredU32 {
|
||||
fn from(value: f64) -> Self {
|
||||
if value < 0.0 || value > u32::MAX as f64 {
|
||||
panic!()
|
||||
}
|
||||
Self(value as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StoredU32> for f64 {
|
||||
fn from(value: StoredU32) -> Self {
|
||||
value.0 as f64
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StoredU32> for usize {
|
||||
fn from(value: StoredU32) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2PK65Index> for StoredU32 {
|
||||
fn from(value: P2PK65Index) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2PK33Index> for StoredU32 {
|
||||
fn from(value: P2PK33Index) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2PKHIndex> for StoredU32 {
|
||||
fn from(value: P2PKHIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OpReturnIndex> for StoredU32 {
|
||||
fn from(value: OpReturnIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2MSIndex> for StoredU32 {
|
||||
fn from(value: P2MSIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2SHIndex> for StoredU32 {
|
||||
fn from(value: P2SHIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2WSHIndex> for StoredU32 {
|
||||
fn from(value: P2WSHIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2WPKHIndex> for StoredU32 {
|
||||
fn from(value: P2WPKHIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2TRIndex> for StoredU32 {
|
||||
fn from(value: P2TRIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2AIndex> for StoredU32 {
|
||||
fn from(value: P2AIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UnknownOutputIndex> for StoredU32 {
|
||||
fn from(value: UnknownOutputIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EmptyOutputIndex> for StoredU32 {
|
||||
fn from(value: EmptyOutputIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
use std::ops::{Add, Div};
|
||||
|
||||
use derive_deref::Deref;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
use super::{InputIndex, OutputIndex, TxIndex};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct StoredU64(u64);
|
||||
|
||||
impl StoredU64 {
|
||||
pub const ZERO: Self = Self(0);
|
||||
|
||||
pub fn new(counter: u64) -> Self {
|
||||
Self(counter)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for StoredU64 {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for StoredU64 {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub<StoredU64> for StoredU64 {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for StoredU64 {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 / rhs as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for StoredU64 {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for StoredU64 {
|
||||
fn from(value: f64) -> Self {
|
||||
if value < 0.0 || value > u32::MAX as f64 {
|
||||
panic!()
|
||||
}
|
||||
Self(value as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StoredU64> for f64 {
|
||||
fn from(value: StoredU64) -> Self {
|
||||
value.0 as f64
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TxIndex> for StoredU64 {
|
||||
fn from(value: TxIndex) -> Self {
|
||||
Self(*value as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InputIndex> for StoredU64 {
|
||||
fn from(value: InputIndex) -> Self {
|
||||
Self(*value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OutputIndex> for StoredU64 {
|
||||
fn from(value: OutputIndex) -> Self {
|
||||
Self(*value)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
use std::ops::{Add, Div};
|
||||
|
||||
use derive_deref::Deref;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct StoredU8(u8);
|
||||
|
||||
impl StoredU8 {
|
||||
pub const ZERO: Self = Self(0);
|
||||
|
||||
pub fn new(counter: u8) -> Self {
|
||||
Self(counter)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for StoredU8 {
|
||||
fn from(value: u8) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for StoredU8 {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u8)
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub<StoredU8> for StoredU8 {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for StoredU8 {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 / rhs as u8)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for StoredU8 {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for StoredU8 {
|
||||
fn from(value: f64) -> Self {
|
||||
if value < 0.0 || value > u32::MAX as f64 {
|
||||
panic!()
|
||||
}
|
||||
Self(value as u8)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StoredU8> for f64 {
|
||||
fn from(value: StoredU8) -> Self {
|
||||
value.0 as f64
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
use std::ops::{Add, Div};
|
||||
|
||||
use derive_deref::Deref;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
use super::{
|
||||
DateIndex, EmptyOutputIndex, Height, InputIndex, MonthIndex, OpReturnIndex, OutputIndex,
|
||||
P2AIndex, P2MSIndex, P2PK33Index, P2PK65Index, P2PKHIndex, P2SHIndex, P2TRIndex, P2WPKHIndex,
|
||||
P2WSHIndex, TxIndex, UnknownOutputIndex, YearIndex,
|
||||
};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct StoredUsize(usize);
|
||||
|
||||
impl StoredUsize {
|
||||
pub const ZERO: Self = Self(0);
|
||||
|
||||
pub fn new(counter: usize) -> Self {
|
||||
Self(counter)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for StoredUsize {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub<StoredUsize> for StoredUsize {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for StoredUsize {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 / rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for StoredUsize {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for StoredUsize {
|
||||
fn from(value: f64) -> Self {
|
||||
if value < 0.0 || value > u32::MAX as f64 {
|
||||
panic!()
|
||||
}
|
||||
Self(value as usize)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StoredUsize> for f64 {
|
||||
fn from(value: StoredUsize) -> Self {
|
||||
value.0 as f64
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Height> for StoredUsize {
|
||||
fn from(value: Height) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DateIndex> for StoredUsize {
|
||||
fn from(value: DateIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MonthIndex> for StoredUsize {
|
||||
fn from(value: MonthIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<YearIndex> for StoredUsize {
|
||||
fn from(value: YearIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OutputIndex> for StoredUsize {
|
||||
fn from(value: OutputIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InputIndex> for StoredUsize {
|
||||
fn from(value: InputIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TxIndex> for StoredUsize {
|
||||
fn from(value: TxIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2PK65Index> for StoredUsize {
|
||||
fn from(value: P2PK65Index) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2PK33Index> for StoredUsize {
|
||||
fn from(value: P2PK33Index) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2PKHIndex> for StoredUsize {
|
||||
fn from(value: P2PKHIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OpReturnIndex> for StoredUsize {
|
||||
fn from(value: OpReturnIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2MSIndex> for StoredUsize {
|
||||
fn from(value: P2MSIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2SHIndex> for StoredUsize {
|
||||
fn from(value: P2SHIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2WSHIndex> for StoredUsize {
|
||||
fn from(value: P2WSHIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2WPKHIndex> for StoredUsize {
|
||||
fn from(value: P2WPKHIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2TRIndex> for StoredUsize {
|
||||
fn from(value: P2TRIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2AIndex> for StoredUsize {
|
||||
fn from(value: P2AIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UnknownOutputIndex> for StoredUsize {
|
||||
fn from(value: UnknownOutputIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EmptyOutputIndex> for StoredUsize {
|
||||
fn from(value: EmptyOutputIndex) -> Self {
|
||||
Self::from(usize::from(value))
|
||||
}
|
||||
}
|
||||
@@ -65,12 +65,6 @@ impl From<bitcoin::locktime::absolute::Time> for Timestamp {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Timestamp> for bitcoin::locktime::absolute::Time {
|
||||
fn from(value: Timestamp) -> Self {
|
||||
bitcoin::locktime::absolute::Time::from_consensus(*value).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Timestamp {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u32)
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
use byteview::ByteView;
|
||||
use derive_deref::Deref;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::{Error, copy_first_8bytes};
|
||||
|
||||
use super::Txid;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct TxidPrefix([u8; 8]);
|
||||
|
||||
impl From<Txid> for TxidPrefix {
|
||||
fn from(value: Txid) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Txid> for TxidPrefix {
|
||||
fn from(value: &Txid) -> Self {
|
||||
Self(copy_first_8bytes(&value[..]).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ByteView> for TxidPrefix {
|
||||
type Error = Error;
|
||||
fn try_from(value: ByteView) -> Result<Self, Self::Error> {
|
||||
Ok(Self::read_from_bytes(&value)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&TxidPrefix> for ByteView {
|
||||
fn from(value: &TxidPrefix) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TxidPrefix> for ByteView {
|
||||
fn from(value: TxidPrefix) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; 8]> for TxidPrefix {
|
||||
fn from(value: [u8; 8]) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::{CheckedSub, Error};
|
||||
|
||||
use super::StoredU32;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
@@ -24,76 +26,88 @@ use crate::{CheckedSub, Error};
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Txindex(u32);
|
||||
pub struct TxIndex(u32);
|
||||
|
||||
impl TxIndex {
|
||||
pub const ZERO: Self = Self(0);
|
||||
|
||||
pub fn new(txindex: u32) -> Self {
|
||||
Self(txindex)
|
||||
}
|
||||
|
||||
impl Txindex {
|
||||
pub fn incremented(self) -> Self {
|
||||
Self(*self + 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Txindex> for Txindex {
|
||||
impl Add<TxIndex> for TxIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Txindex) -> Self::Output {
|
||||
fn add(self, rhs: TxIndex) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Txindex {
|
||||
impl Add<usize> for TxIndex {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self(self.0 + rhs as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<Txindex> for Txindex {
|
||||
fn add_assign(&mut self, rhs: Txindex) {
|
||||
impl AddAssign<TxIndex> for TxIndex {
|
||||
fn add_assign(&mut self, rhs: TxIndex) {
|
||||
self.0 += rhs.0
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub<Txindex> for Txindex {
|
||||
fn checked_sub(self, rhs: Txindex) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Txindex::from)
|
||||
impl CheckedSub<TxIndex> for TxIndex {
|
||||
fn checked_sub(self, rhs: TxIndex) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(TxIndex::from)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for Txindex {
|
||||
impl From<u32> for TxIndex {
|
||||
fn from(value: u32) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Txindex {
|
||||
impl From<u64> for TxIndex {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(value as u32)
|
||||
}
|
||||
}
|
||||
impl From<Txindex> for u64 {
|
||||
fn from(value: Txindex) -> Self {
|
||||
impl From<TxIndex> for u64 {
|
||||
fn from(value: TxIndex) -> Self {
|
||||
value.0 as u64
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Txindex {
|
||||
impl From<usize> for TxIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u32)
|
||||
}
|
||||
}
|
||||
impl From<Txindex> for usize {
|
||||
fn from(value: Txindex) -> Self {
|
||||
impl From<TxIndex> for usize {
|
||||
fn from(value: TxIndex) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ByteView> for Txindex {
|
||||
impl TryFrom<ByteView> for TxIndex {
|
||||
type Error = Error;
|
||||
fn try_from(value: ByteView) -> Result<Self, Self::Error> {
|
||||
Ok(Self::read_from_bytes(&value)?)
|
||||
}
|
||||
}
|
||||
impl From<Txindex> for ByteView {
|
||||
fn from(value: Txindex) -> Self {
|
||||
impl From<TxIndex> for ByteView {
|
||||
fn from(value: TxIndex) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TxIndex> for StoredU32 {
|
||||
fn from(value: TxIndex) -> Self {
|
||||
Self::from(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,17 +2,51 @@ use derive_deref::Deref;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
#[derive(Debug, Deref, Clone, Copy, Immutable, IntoBytes, KnownLayout, FromBytes, Serialize)]
|
||||
pub struct TxVersion(i32);
|
||||
use super::StoredU8;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
FromBytes,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct TxVersion(u8);
|
||||
|
||||
impl TxVersion {
|
||||
pub const ONE: Self = Self(1);
|
||||
pub const TWO: Self = Self(2);
|
||||
pub const THREE: Self = Self(3);
|
||||
pub const NON_STANDARD: Self = Self(u8::MAX);
|
||||
}
|
||||
|
||||
impl From<bitcoin::transaction::Version> for TxVersion {
|
||||
fn from(value: bitcoin::transaction::Version) -> Self {
|
||||
Self(value.0)
|
||||
match value.0 {
|
||||
1 => Self::ONE,
|
||||
2 => Self::TWO,
|
||||
3 => Self::THREE,
|
||||
_ => Self::NON_STANDARD,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TxVersion> for bitcoin::transaction::Version {
|
||||
fn from(value: TxVersion) -> Self {
|
||||
Self(value.0)
|
||||
Self(value.0 as i32)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TxVersion> for StoredU8 {
|
||||
fn from(value: TxVersion) -> Self {
|
||||
Self::from(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
use super::{Date, Dateindex};
|
||||
use super::{Date, DateIndex};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
@@ -23,27 +23,27 @@ use super::{Date, Dateindex};
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct Weekindex(u16);
|
||||
pub struct WeekIndex(u16);
|
||||
|
||||
impl From<u16> for Weekindex {
|
||||
impl From<u16> for WeekIndex {
|
||||
fn from(value: u16) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Weekindex {
|
||||
impl From<usize> for WeekIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u16)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Weekindex> for usize {
|
||||
fn from(value: Weekindex) -> Self {
|
||||
impl From<WeekIndex> for usize {
|
||||
fn from(value: WeekIndex) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Weekindex {
|
||||
impl Add<usize> for WeekIndex {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
@@ -51,13 +51,13 @@ impl Add<usize> for Weekindex {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Dateindex> for Weekindex {
|
||||
fn from(value: Dateindex) -> Self {
|
||||
impl From<DateIndex> for WeekIndex {
|
||||
fn from(value: DateIndex) -> Self {
|
||||
Self::from(Date::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Date> for Weekindex {
|
||||
impl From<Date> for WeekIndex {
|
||||
fn from(value: Date) -> Self {
|
||||
let date = jiff::civil::Date::from(value).iso_week_date();
|
||||
|
||||
@@ -81,7 +81,7 @@ impl From<Date> for Weekindex {
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for Weekindex {
|
||||
impl CheckedSub for WeekIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,24 @@
|
||||
use std::ops::{Add, Div};
|
||||
|
||||
use derive_deref::Deref;
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
#[derive(Debug, Deref, Clone, Copy, Immutable, IntoBytes, KnownLayout, FromBytes, Serialize)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
FromBytes,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct Weight(u64);
|
||||
|
||||
impl From<bitcoin::Weight> for Weight {
|
||||
@@ -13,6 +29,45 @@ impl From<bitcoin::Weight> for Weight {
|
||||
|
||||
impl From<Weight> for bitcoin::Weight {
|
||||
fn from(value: Weight) -> Self {
|
||||
Self::from_wu(*value)
|
||||
Self::from_wu(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Weight {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for Weight {
|
||||
fn from(value: f64) -> Self {
|
||||
Self(value as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Weight> for f64 {
|
||||
fn from(value: Weight) -> Self {
|
||||
value.0 as f64
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Weight {
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for Weight {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Self::from(self.0 as usize / rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<Weight> for Weight {
|
||||
type Output = Self;
|
||||
fn div(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 / rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::CheckedSub;
|
||||
|
||||
use super::{Date, Dateindex, Monthindex};
|
||||
use super::{Date, DateIndex, MonthIndex};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
@@ -23,27 +23,27 @@ use super::{Date, Dateindex, Monthindex};
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
)]
|
||||
pub struct Yearindex(u8);
|
||||
pub struct YearIndex(u8);
|
||||
|
||||
impl From<u8> for Yearindex {
|
||||
impl From<u8> for YearIndex {
|
||||
fn from(value: u8) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Yearindex {
|
||||
impl From<usize> for YearIndex {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u8)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Yearindex> for usize {
|
||||
fn from(value: Yearindex) -> Self {
|
||||
impl From<YearIndex> for usize {
|
||||
fn from(value: YearIndex) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Yearindex {
|
||||
impl Add<usize> for YearIndex {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
@@ -51,32 +51,32 @@ impl Add<usize> for Yearindex {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Dateindex> for Yearindex {
|
||||
fn from(value: Dateindex) -> Self {
|
||||
impl From<DateIndex> for YearIndex {
|
||||
fn from(value: DateIndex) -> Self {
|
||||
Self::from(Date::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Date> for Yearindex {
|
||||
impl From<Date> for YearIndex {
|
||||
fn from(value: Date) -> Self {
|
||||
Self((value.year() - 2009) as u8)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Yearindex> for u16 {
|
||||
fn from(value: Yearindex) -> Self {
|
||||
impl From<YearIndex> for u16 {
|
||||
fn from(value: YearIndex) -> Self {
|
||||
value.0 as u16
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for Yearindex {
|
||||
impl CheckedSub for YearIndex {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Monthindex> for Yearindex {
|
||||
fn from(value: Monthindex) -> Self {
|
||||
impl From<MonthIndex> for YearIndex {
|
||||
fn from(value: MonthIndex) -> Self {
|
||||
Self((usize::from(value) / 12) as u8)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#[allow(clippy::result_unit_err)]
|
||||
pub fn copy_first_8bytes(slice: &[u8]) -> Result<[u8; 8], ()> {
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
let buf_len = buf.len();
|
||||
if slice.len() < buf_len {
|
||||
return Err(());
|
||||
}
|
||||
slice.iter().take(buf_len).enumerate().for_each(|(i, r)| {
|
||||
buf[i] = *r;
|
||||
});
|
||||
Ok(buf)
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
mod bytes;
|
||||
mod checked_sub;
|
||||
mod paths;
|
||||
mod pause;
|
||||
mod rlimit;
|
||||
|
||||
pub use bytes::*;
|
||||
pub use checked_sub::*;
|
||||
pub use paths::*;
|
||||
pub use pause::*;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<a href="https://deps.rs/crate/brk_exit">
|
||||
<img src="https://deps.rs/crate/brk_exit/latest/status.svg" alt="Dependency status">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cvrwpv3zEG">
|
||||
<a href="https://discord.gg/HaR3wpH3nr">
|
||||
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
|
||||
@@ -29,7 +29,7 @@
|
||||
<a href="https://bsky.app/profile/bitcoinresearchkit.org">
|
||||
<img src="https://img.shields.io/badge/bluesky-blue?link=https%3A%2F%2Fbsky.app%2Fprofile%2Fbitcoinresearchkit.org" alt="Bluesky" />
|
||||
</a>
|
||||
<a href="https://x.com/0xbrk">
|
||||
<a href="https://x.com/brkdotorg">
|
||||
<img src="https://img.shields.io/badge/x.com-black" alt="X" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<a href="https://deps.rs/crate/brk_fetcher">
|
||||
<img src="https://deps.rs/crate/brk_fetcher/latest/status.svg" alt="Dependency status">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cvrwpv3zEG">
|
||||
<a href="https://discord.gg/HaR3wpH3nr">
|
||||
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
|
||||
@@ -29,7 +29,7 @@
|
||||
<a href="https://bsky.app/profile/bitcoinresearchkit.org">
|
||||
<img src="https://img.shields.io/badge/bluesky-blue?link=https%3A%2F%2Fbsky.app%2Fprofile%2Fbitcoinresearchkit.org" alt="Bluesky" />
|
||||
</a>
|
||||
<a href="https://x.com/0xbrk">
|
||||
<a href="https://x.com/brkdotorg">
|
||||
<img src="https://img.shields.io/badge/x.com-black" alt="X" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -223,10 +223,10 @@ impl Binance {
|
||||
Ok((
|
||||
timestamp,
|
||||
OHLCCents::from((
|
||||
Open::from(get_cents(1)),
|
||||
High::from(get_cents(2)),
|
||||
Low::from(get_cents(3)),
|
||||
Close::from(get_cents(4)),
|
||||
Open::new(get_cents(1)),
|
||||
High::new(get_cents(2)),
|
||||
Low::new(get_cents(3)),
|
||||
Close::new(get_cents(4)),
|
||||
)),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -141,10 +141,10 @@ impl Kibo {
|
||||
};
|
||||
|
||||
Ok(OHLCCents::from((
|
||||
Open::from(get_value("open")?),
|
||||
High::from(get_value("high")?),
|
||||
Low::from(get_value("low")?),
|
||||
Close::from(get_value("close")?),
|
||||
Open::new(get_value("open")?),
|
||||
High::new(get_value("high")?),
|
||||
Low::new(get_value("low")?),
|
||||
Close::new(get_value("close")?),
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,10 +114,10 @@ impl Kraken {
|
||||
Ok((
|
||||
timestamp,
|
||||
OHLCCents::from((
|
||||
Open::from(get_cents(1)),
|
||||
High::from(get_cents(2)),
|
||||
Low::from(get_cents(3)),
|
||||
Close::from(get_cents(4)),
|
||||
Open::new(get_cents(1)),
|
||||
High::new(get_cents(2)),
|
||||
Low::new(get_cents(3)),
|
||||
Close::new(get_cents(4)),
|
||||
)),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -60,9 +60,9 @@ impl Fetcher {
|
||||
self.binance
|
||||
.get_from_1mn(timestamp, previous_timestamp)
|
||||
.unwrap_or_else(|_| {
|
||||
self.kibo.get_from_height(height).unwrap_or_else(|_| {
|
||||
self.kibo.get_from_height(height).unwrap_or_else(|e| {
|
||||
let date = Date::from(timestamp);
|
||||
|
||||
eprintln!("{e}");
|
||||
panic!(
|
||||
"
|
||||
Can't find the price for: height: {height} - date: {date}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<a href="https://deps.rs/crate/brk_indexer">
|
||||
<img src="https://deps.rs/crate/brk_indexer/latest/status.svg" alt="Dependency status">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cvrwpv3zEG">
|
||||
<a href="https://discord.gg/HaR3wpH3nr">
|
||||
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
|
||||
@@ -29,7 +29,7 @@
|
||||
<a href="https://bsky.app/profile/bitcoinresearchkit.org">
|
||||
<img src="https://img.shields.io/badge/bluesky-blue?link=https%3A%2F%2Fbsky.app%2Fprofile%2Fbitcoinresearchkit.org" alt="Bluesky" />
|
||||
</a>
|
||||
<a href="https://x.com/0xbrk">
|
||||
<a href="https://x.com/brkdotorg">
|
||||
<img src="https://img.shields.io/badge/x.com-black" alt="X" />
|
||||
</a>
|
||||
</p>
|
||||
@@ -58,9 +58,21 @@ Stores: `src/storage/stores/mod.rs`
|
||||
|
||||
## Benchmark
|
||||
|
||||
Indexing `0..885_835` took `11 hours 6 min 50 s` on a Macbook Pro M3 Pro with 36 GB of RAM
|
||||
### `v0.0.21`
|
||||
|
||||
`footprint` report:
|
||||
- Peak memory: `5115 MB`
|
||||
- Memory while waiting for a new block: `890 MB`
|
||||
- Reclaimable memory: `6478 MB`
|
||||
- machine: `MBP M3 Pro (36GB RAM)`
|
||||
- mode: `raw`
|
||||
- from: `0`
|
||||
- to: `892_098`
|
||||
- time: `7 hours 10 min 22s`
|
||||
- peak memory: `6.1GB`
|
||||
- disk usage: `270 GB`
|
||||
- overhead: `36%` (`270 GB / 741 GB`)
|
||||
|
||||
### `v0.0.31`
|
||||
|
||||
- machine: `MBP M3 Pro (36GB RAM)`
|
||||
- mode: `raw`
|
||||
- disk usage: `208 GB`
|
||||
- overhead: `28%` (`208 GB / 744 GB`)
|
||||
- peak memory: `5.7GB`
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::path::Path;
|
||||
use std::{path::Path, time::Instant};
|
||||
|
||||
use brk_core::default_bitcoin_path;
|
||||
use brk_exit::Exit;
|
||||
@@ -8,6 +8,8 @@ use brk_parser::{Parser, rpc};
|
||||
fn main() -> color_eyre::Result<()> {
|
||||
color_eyre::install()?;
|
||||
|
||||
let i = Instant::now();
|
||||
|
||||
brk_logger::init(Some(Path::new(".log")));
|
||||
|
||||
let bitcoin_dir = default_bitcoin_path();
|
||||
@@ -22,12 +24,14 @@ fn main() -> color_eyre::Result<()> {
|
||||
|
||||
let outputs = Path::new("../../_outputs");
|
||||
|
||||
let mut indexer = Indexer::new(outputs.join("indexed").to_owned(), true, true)?;
|
||||
let mut indexer = Indexer::new(outputs, false, true)?;
|
||||
|
||||
indexer.import_stores()?;
|
||||
indexer.import_vecs()?;
|
||||
|
||||
indexer.index(&parser, rpc, &exit)?;
|
||||
|
||||
dbg!(i.elapsed());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,56 +1,71 @@
|
||||
use bitcoincore_rpc::Client;
|
||||
use brk_core::{
|
||||
Addressindex, BlockHash, CheckedSub, Emptyindex, Height, Multisigindex, Opreturnindex,
|
||||
P2PK33index, P2PK65index, P2PKHindex, P2SHindex, P2TRindex, P2WPKHindex, P2WSHindex,
|
||||
Pushonlyindex, Txindex, Txinindex, Txoutindex, Unknownindex,
|
||||
BlockHash, CheckedSub, EmptyOutputIndex, Height, InputIndex, OpReturnIndex, OutputIndex,
|
||||
OutputType, OutputTypeIndex, P2AIndex, P2MSIndex, P2PK33Index, P2PK65Index, P2PKHIndex,
|
||||
P2SHIndex, P2TRIndex, P2WPKHIndex, P2WSHIndex, TxIndex, UnknownOutputIndex,
|
||||
};
|
||||
use brk_parser::NUMBER_OF_UNSAFE_BLOCKS;
|
||||
use brk_vec::{Result, StoredIndex, StoredType, Value};
|
||||
use color_eyre::eyre::ContextCompat;
|
||||
|
||||
use crate::{Stores, Vecs};
|
||||
use crate::{IndexedVec, Stores, Vecs};
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct Indexes {
|
||||
pub addressindex: Addressindex,
|
||||
pub emptyindex: Emptyindex,
|
||||
pub emptyoutputindex: EmptyOutputIndex,
|
||||
pub height: Height,
|
||||
pub multisigindex: Multisigindex,
|
||||
pub opreturnindex: Opreturnindex,
|
||||
pub p2pk33index: P2PK33index,
|
||||
pub p2pk65index: P2PK65index,
|
||||
pub p2pkhindex: P2PKHindex,
|
||||
pub p2shindex: P2SHindex,
|
||||
pub p2trindex: P2TRindex,
|
||||
pub p2wpkhindex: P2WPKHindex,
|
||||
pub p2wshindex: P2WSHindex,
|
||||
pub pushonlyindex: Pushonlyindex,
|
||||
pub txindex: Txindex,
|
||||
pub txinindex: Txinindex,
|
||||
pub txoutindex: Txoutindex,
|
||||
pub unknownindex: Unknownindex,
|
||||
pub opreturnindex: OpReturnIndex,
|
||||
pub p2msindex: P2MSIndex,
|
||||
pub p2pk33index: P2PK33Index,
|
||||
pub p2pk65index: P2PK65Index,
|
||||
pub p2pkhindex: P2PKHIndex,
|
||||
pub p2shindex: P2SHIndex,
|
||||
pub p2trindex: P2TRIndex,
|
||||
pub p2wpkhindex: P2WPKHIndex,
|
||||
pub p2wshindex: P2WSHIndex,
|
||||
pub p2aindex: P2AIndex,
|
||||
pub txindex: TxIndex,
|
||||
pub inputindex: InputIndex,
|
||||
pub outputindex: OutputIndex,
|
||||
pub unknownoutputindex: UnknownOutputIndex,
|
||||
}
|
||||
|
||||
impl Indexes {
|
||||
pub fn outputtypeindex(&self, outputtype: OutputType) -> OutputTypeIndex {
|
||||
match outputtype {
|
||||
OutputType::Empty => *self.emptyoutputindex,
|
||||
OutputType::OpReturn => *self.opreturnindex,
|
||||
OutputType::P2A => *self.p2aindex,
|
||||
OutputType::P2MS => *self.p2msindex,
|
||||
OutputType::P2PK33 => *self.p2pkhindex,
|
||||
OutputType::P2PK65 => *self.p2pk65index,
|
||||
OutputType::P2PKH => *self.p2pkhindex,
|
||||
OutputType::P2SH => *self.p2shindex,
|
||||
OutputType::P2TR => *self.p2trindex,
|
||||
OutputType::P2WPKH => *self.p2wpkhindex,
|
||||
OutputType::P2WSH => *self.p2wshindex,
|
||||
OutputType::Unknown => *self.unknownoutputindex,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_if_needed(&self, vecs: &mut Vecs) -> brk_vec::Result<()> {
|
||||
let height = self.height;
|
||||
vecs.height_to_first_txindex
|
||||
.push_if_needed(height, self.txindex)?;
|
||||
vecs.height_to_first_txinindex
|
||||
.push_if_needed(height, self.txinindex)?;
|
||||
vecs.height_to_first_txoutindex
|
||||
.push_if_needed(height, self.txoutindex)?;
|
||||
vecs.height_to_first_addressindex
|
||||
.push_if_needed(height, self.addressindex)?;
|
||||
vecs.height_to_first_emptyindex
|
||||
.push_if_needed(height, self.emptyindex)?;
|
||||
vecs.height_to_first_multisigindex
|
||||
.push_if_needed(height, self.multisigindex)?;
|
||||
vecs.height_to_first_inputindex
|
||||
.push_if_needed(height, self.inputindex)?;
|
||||
vecs.height_to_first_outputindex
|
||||
.push_if_needed(height, self.outputindex)?;
|
||||
vecs.height_to_first_emptyoutputindex
|
||||
.push_if_needed(height, self.emptyoutputindex)?;
|
||||
vecs.height_to_first_p2msindex
|
||||
.push_if_needed(height, self.p2msindex)?;
|
||||
vecs.height_to_first_opreturnindex
|
||||
.push_if_needed(height, self.opreturnindex)?;
|
||||
vecs.height_to_first_pushonlyindex
|
||||
.push_if_needed(height, self.pushonlyindex)?;
|
||||
vecs.height_to_first_unknownindex
|
||||
.push_if_needed(height, self.unknownindex)?;
|
||||
vecs.height_to_first_p2aindex
|
||||
.push_if_needed(height, self.p2aindex)?;
|
||||
vecs.height_to_first_unknownoutputindex
|
||||
.push_if_needed(height, self.unknownoutputindex)?;
|
||||
vecs.height_to_first_p2pk33index
|
||||
.push_if_needed(height, self.p2pk33index)?;
|
||||
vecs.height_to_first_p2pk65index
|
||||
@@ -65,13 +80,7 @@ impl Indexes {
|
||||
.push_if_needed(height, self.p2wpkhindex)?;
|
||||
vecs.height_to_first_p2wshindex
|
||||
.push_if_needed(height, self.p2wshindex)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn push_future_if_needed(&mut self, vecs: &mut Vecs) -> brk_vec::Result<()> {
|
||||
self.height.increment();
|
||||
self.push_if_needed(vecs)?;
|
||||
self.height.decrement();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -111,32 +120,112 @@ impl TryFrom<(&mut Vecs, &Stores, &Client)> for Indexes {
|
||||
.unwrap_or(starting_height);
|
||||
|
||||
Ok(Self {
|
||||
addressindex: *vecs.height_to_first_addressindex.get(height)?.context("")?,
|
||||
emptyindex: *vecs.height_to_first_emptyindex.get(height)?.context("")?,
|
||||
emptyoutputindex: *starting_index(
|
||||
&vecs.height_to_first_emptyoutputindex,
|
||||
&vecs.emptyoutputindex_to_txindex,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
height,
|
||||
multisigindex: *vecs
|
||||
.height_to_first_multisigindex
|
||||
.get(height)?
|
||||
p2msindex: *starting_index(
|
||||
&vecs.height_to_first_p2msindex,
|
||||
&vecs.p2msindex_to_txindex,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
opreturnindex: *starting_index(
|
||||
&vecs.height_to_first_opreturnindex,
|
||||
&vecs.opreturnindex_to_txindex,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
p2pk33index: *starting_index(
|
||||
&vecs.height_to_first_p2pk33index,
|
||||
&vecs.p2pk33index_to_p2pk33bytes,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
p2pk65index: *starting_index(
|
||||
&vecs.height_to_first_p2pk65index,
|
||||
&vecs.p2pk65index_to_p2pk65bytes,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
p2pkhindex: *starting_index(
|
||||
&vecs.height_to_first_p2pkhindex,
|
||||
&vecs.p2pkhindex_to_p2pkhbytes,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
p2shindex: *starting_index(
|
||||
&vecs.height_to_first_p2shindex,
|
||||
&vecs.p2shindex_to_p2shbytes,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
p2trindex: *starting_index(
|
||||
&vecs.height_to_first_p2trindex,
|
||||
&vecs.p2trindex_to_p2trbytes,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
p2wpkhindex: *starting_index(
|
||||
&vecs.height_to_first_p2wpkhindex,
|
||||
&vecs.p2wpkhindex_to_p2wpkhbytes,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
p2wshindex: *starting_index(
|
||||
&vecs.height_to_first_p2wshindex,
|
||||
&vecs.p2wshindex_to_p2wshbytes,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
p2aindex: *starting_index(
|
||||
&vecs.height_to_first_p2aindex,
|
||||
&vecs.p2aindex_to_p2abytes,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
txindex: *starting_index(&vecs.height_to_first_txindex, &vecs.txindex_to_txid, height)?
|
||||
.context("")?,
|
||||
opreturnindex: *vecs
|
||||
.height_to_first_opreturnindex
|
||||
.get(height)?
|
||||
.context("")?,
|
||||
p2pk33index: *vecs.height_to_first_p2pk33index.get(height)?.context("")?,
|
||||
p2pk65index: *vecs.height_to_first_p2pk65index.get(height)?.context("")?,
|
||||
p2pkhindex: *vecs.height_to_first_p2pkhindex.get(height)?.context("")?,
|
||||
p2shindex: *vecs.height_to_first_p2shindex.get(height)?.context("")?,
|
||||
p2trindex: *vecs.height_to_first_p2trindex.get(height)?.context("")?,
|
||||
p2wpkhindex: *vecs.height_to_first_p2wpkhindex.get(height)?.context("")?,
|
||||
p2wshindex: *vecs.height_to_first_p2wshindex.get(height)?.context("")?,
|
||||
pushonlyindex: *vecs
|
||||
.height_to_first_pushonlyindex
|
||||
.get(height)?
|
||||
.context("")?,
|
||||
txindex: *vecs.height_to_first_txindex.get(height)?.context("")?,
|
||||
txinindex: *vecs.height_to_first_txinindex.get(height)?.context("")?,
|
||||
txoutindex: *vecs.height_to_first_txoutindex.get(height)?.context("")?,
|
||||
unknownindex: *vecs.height_to_first_unknownindex.get(height)?.context("")?,
|
||||
inputindex: *starting_index(
|
||||
&vecs.height_to_first_inputindex,
|
||||
&vecs.inputindex_to_outputindex,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
outputindex: *starting_index(
|
||||
&vecs.height_to_first_outputindex,
|
||||
&vecs.outputindex_to_value,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
unknownoutputindex: *starting_index(
|
||||
&vecs.height_to_first_unknownoutputindex,
|
||||
&vecs.unknownoutputindex_to_txindex,
|
||||
height,
|
||||
)?
|
||||
.context("")?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn starting_index<'a, I, T>(
|
||||
height_to_index: &'a IndexedVec<Height, I>,
|
||||
index_to_else: &'a IndexedVec<I, T>,
|
||||
starting_height: Height,
|
||||
) -> Result<Option<Value<'a, I>>>
|
||||
where
|
||||
I: StoredType + StoredIndex + From<usize>,
|
||||
T: StoredType,
|
||||
{
|
||||
if height_to_index
|
||||
.height()
|
||||
.is_ok_and(|h| h + 1_u32 == starting_height)
|
||||
{
|
||||
Ok(Some(Value::Owned(I::from(index_to_else.len()))))
|
||||
} else {
|
||||
height_to_index.get(starting_height)
|
||||
}
|
||||
}
|
||||
|
||||
+171
-163
@@ -11,8 +11,8 @@ use std::{
|
||||
};
|
||||
|
||||
use brk_core::{
|
||||
AddressHash, Addressbytes, Addressindex, Addresstype, BlockHash, BlockHashPrefix, Height, Sats,
|
||||
Timestamp, Txid, TxidPrefix, Txindex, Txinindex, Txoutindex, Vin, Vout, setrlimit,
|
||||
AddressBytes, AddressBytesHash, BlockHash, BlockHashPrefix, Height, InputIndex, OutputIndex,
|
||||
OutputType, OutputTypeIndex, Sats, Timestamp, TxIndex, Txid, TxidPrefix, Vin, Vout, setrlimit,
|
||||
};
|
||||
pub use brk_parser::*;
|
||||
|
||||
@@ -20,7 +20,8 @@ use bitcoin::{Transaction, TxIn, TxOut};
|
||||
use brk_exit::Exit;
|
||||
use brk_vec::Compressed;
|
||||
use color_eyre::eyre::{ContextCompat, eyre};
|
||||
use log::info;
|
||||
use fjall::TransactionalKeyspace;
|
||||
use log::{error, info};
|
||||
use rayon::prelude::*;
|
||||
mod indexes;
|
||||
mod stores;
|
||||
@@ -31,7 +32,7 @@ pub use stores::*;
|
||||
pub use vecs::*;
|
||||
|
||||
const SNAPSHOT_BLOCK_RANGE: usize = 1000;
|
||||
const COLLISIONS_CHECKED_UP_TO: u32 = 888_000;
|
||||
const COLLISIONS_CHECKED_UP_TO: u32 = 893_000;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Indexer {
|
||||
@@ -44,13 +45,13 @@ pub struct Indexer {
|
||||
|
||||
impl Indexer {
|
||||
pub fn new(
|
||||
indexes_dir: PathBuf,
|
||||
outputs_dir: &Path,
|
||||
compressed: bool,
|
||||
check_collisions: bool,
|
||||
) -> color_eyre::Result<Self> {
|
||||
setrlimit()?;
|
||||
Ok(Self {
|
||||
path: indexes_dir,
|
||||
path: outputs_dir.to_owned(),
|
||||
vecs: None,
|
||||
stores: None,
|
||||
compressed: Compressed::from(compressed),
|
||||
@@ -59,14 +60,17 @@ impl Indexer {
|
||||
}
|
||||
|
||||
pub fn import_vecs(&mut self) -> color_eyre::Result<()> {
|
||||
self.vecs = Some(Vecs::import(&self.path.join("vecs"), self.compressed)?);
|
||||
self.vecs = Some(Vecs::forced_import(
|
||||
&self.path.join("vecs/indexed"),
|
||||
self.compressed,
|
||||
)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Do NOT import multiple times are things will break !!!
|
||||
/// Clone struct instead
|
||||
pub fn import_stores(&mut self) -> color_eyre::Result<()> {
|
||||
self.stores = Some(Stores::import(&self.path.join("stores"))?);
|
||||
self.stores = Some(Stores::forced_import(&self.path.join("stores"))?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -81,7 +85,7 @@ impl Indexer {
|
||||
self.stores.as_ref().unwrap(),
|
||||
rpc,
|
||||
))
|
||||
.unwrap_or_else(|_| {
|
||||
.unwrap_or_else(|_report| {
|
||||
let indexes = Indexes::default();
|
||||
indexes.push_if_needed(self.vecs.as_mut().unwrap()).unwrap();
|
||||
indexes
|
||||
@@ -101,6 +105,7 @@ impl Indexer {
|
||||
let vecs = self.vecs.as_mut().unwrap();
|
||||
let stores = self.stores.as_mut().unwrap();
|
||||
|
||||
// Cloned because we want to return starting indexes for the computer
|
||||
let mut idxs = starting_indexes.clone();
|
||||
|
||||
let start = Some(idxs.height);
|
||||
@@ -145,24 +150,26 @@ impl Indexer {
|
||||
let blockhash_prefix = BlockHashPrefix::from(&blockhash);
|
||||
|
||||
if stores
|
||||
.blockhash_prefix_to_height
|
||||
.blockhashprefix_to_height
|
||||
.get(&blockhash_prefix)?
|
||||
.is_some_and(|prev_height| *prev_height != height)
|
||||
{
|
||||
dbg!(blockhash);
|
||||
error!("BlockHash: {blockhash}");
|
||||
return Err(eyre!("Collision, expect prefix to need be set yet"));
|
||||
}
|
||||
|
||||
idxs.push_if_needed(vecs)?;
|
||||
|
||||
stores
|
||||
.blockhash_prefix_to_height
|
||||
.blockhashprefix_to_height
|
||||
.insert_if_needed(blockhash_prefix, height, height);
|
||||
|
||||
vecs.height_to_blockhash.push_if_needed(height, blockhash)?;
|
||||
vecs.height_to_difficulty
|
||||
.push_if_needed(height, block.header.difficulty_float())?;
|
||||
.push_if_needed(height, block.header.difficulty_float().into())?;
|
||||
vecs.height_to_timestamp
|
||||
.push_if_needed(height, Timestamp::from(block.header.time))?;
|
||||
vecs.height_to_size.push_if_needed(height, block.total_size())?;
|
||||
vecs.height_to_total_size.push_if_needed(height, block.total_size().into())?;
|
||||
vecs.height_to_weight.push_if_needed(height, block.weight().into())?;
|
||||
|
||||
let inputs = block
|
||||
@@ -173,7 +180,7 @@ impl Indexer {
|
||||
tx.input
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(move |(vin, txin)| (Txindex::from(index), Vin::from(vin), txin, tx))
|
||||
.map(move |(vin, txin)| (TxIndex::from(index), Vin::from(vin), txin, tx))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -185,7 +192,7 @@ impl Indexer {
|
||||
tx.output
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(move |(vout, txout)| (Txindex::from(index), Vout::from(vout), txout, tx))
|
||||
.map(move |(vout, txout)| (TxIndex::from(index), Vout::from(vout), txout, tx))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -196,7 +203,7 @@ impl Indexer {
|
||||
let (
|
||||
txid_prefix_to_txid_and_block_txindex_and_prev_txindex_join_handle,
|
||||
input_source_vec_handle,
|
||||
txoutindex_to_txout_addresstype_addressbytes_res_addressindex_opt_handle,
|
||||
outputindex_to_txout_outputtype_addressbytes_res_addressindex_opt_handle,
|
||||
) = thread::scope(|scope| {
|
||||
let txid_prefix_to_txid_and_block_txindex_and_prev_txindex_handle =
|
||||
scope.spawn(|| -> color_eyre::Result<_> {
|
||||
@@ -210,14 +217,14 @@ impl Indexer {
|
||||
let txid_prefix = TxidPrefix::from(&txid);
|
||||
|
||||
let prev_txindex_opt =
|
||||
if check_collisions && stores.txid_prefix_to_txindex.needs(height) {
|
||||
if check_collisions && stores.txidprefix_to_txindex.needs(height) {
|
||||
// Should only find collisions for two txids (duplicates), see below
|
||||
stores.txid_prefix_to_txindex.get(&txid_prefix)?.map(|v| *v)
|
||||
stores.txidprefix_to_txindex.get(&txid_prefix)?.map(|v| *v)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok((txid_prefix, (tx, txid, Txindex::from(index), prev_txindex_opt)))
|
||||
Ok((txid_prefix, (tx, txid, TxIndex::from(index), prev_txindex_opt)))
|
||||
})
|
||||
.try_fold(BTreeMap::new, |mut map, tuple| {
|
||||
let (key, value) = tuple?;
|
||||
@@ -239,19 +246,19 @@ impl Indexer {
|
||||
inputs
|
||||
.into_par_iter()
|
||||
.enumerate()
|
||||
.map(|(block_txinindex, (block_txindex, vin, txin, tx))| -> color_eyre::Result<(Txinindex, InputSource)> {
|
||||
.map(|(block_inputindex, (block_txindex, vin, txin, tx))| -> color_eyre::Result<(InputIndex, InputSource)> {
|
||||
let txindex = idxs.txindex + block_txindex;
|
||||
let txinindex = idxs.txinindex + Txinindex::from(block_txinindex);
|
||||
let inputindex = idxs.inputindex + InputIndex::from(block_inputindex);
|
||||
|
||||
let outpoint = txin.previous_output;
|
||||
let txid = Txid::from(outpoint.txid);
|
||||
|
||||
if tx.is_coinbase() {
|
||||
return Ok((txinindex, InputSource::SameBlock((tx, txindex, txin, vin))));
|
||||
return Ok((inputindex, InputSource::SameBlock((tx, txindex, txin, vin))));
|
||||
}
|
||||
|
||||
let prev_txindex = if let Some(txindex) = stores
|
||||
.txid_prefix_to_txindex
|
||||
.txidprefix_to_txindex
|
||||
.get(&TxidPrefix::from(&txid))?
|
||||
.map(|v| *v)
|
||||
.and_then(|txindex| {
|
||||
@@ -261,24 +268,24 @@ impl Indexer {
|
||||
txindex
|
||||
} else {
|
||||
// dbg!(indexes.txindex + block_txindex, txindex, txin, vin);
|
||||
return Ok((txinindex, InputSource::SameBlock((tx, txindex, txin, vin))));
|
||||
return Ok((inputindex, InputSource::SameBlock((tx, txindex, txin, vin))));
|
||||
};
|
||||
|
||||
let vout = Vout::from(outpoint.vout);
|
||||
|
||||
let txoutindex = *vecs
|
||||
.txindex_to_first_txoutindex
|
||||
let outputindex = *vecs
|
||||
.txindex_to_first_outputindex
|
||||
.get(prev_txindex)?
|
||||
.context("Expect txoutindex to not be none")
|
||||
.context("Expect outputindex to not be none")
|
||||
.inspect_err(|_| {
|
||||
dbg!(outpoint.txid, prev_txindex, vout);
|
||||
})?
|
||||
+ vout;
|
||||
|
||||
Ok((txinindex, InputSource::PreviousBlock((
|
||||
Ok((inputindex, InputSource::PreviousBlock((
|
||||
vin,
|
||||
txindex,
|
||||
txoutindex,
|
||||
outputindex,
|
||||
))))
|
||||
})
|
||||
.try_fold(BTreeMap::new, |mut map, tuple| -> color_eyre::Result<_> {
|
||||
@@ -297,71 +304,58 @@ impl Indexer {
|
||||
})
|
||||
});
|
||||
|
||||
let txoutindex_to_txout_addresstype_addressbytes_res_addressindex_opt_handle = scope.spawn(|| {
|
||||
let outputindex_to_txout_outputtype_addressbytes_res_addressindex_opt_handle = scope.spawn(|| {
|
||||
outputs
|
||||
.into_par_iter()
|
||||
.enumerate()
|
||||
.map(
|
||||
#[allow(clippy::type_complexity)]
|
||||
|(block_txoutindex, (block_txindex, vout, txout, tx))| -> color_eyre::Result<(
|
||||
Txoutindex,
|
||||
|(block_outputindex, (block_txindex, vout, txout, tx))| -> color_eyre::Result<(
|
||||
OutputIndex,
|
||||
(
|
||||
&TxOut,
|
||||
Txindex,
|
||||
TxIndex,
|
||||
Vout,
|
||||
Addresstype,
|
||||
brk_core::Result<Addressbytes>,
|
||||
Option<Addressindex>,
|
||||
OutputType,
|
||||
brk_core::Result<AddressBytes>,
|
||||
Option<OutputTypeIndex>,
|
||||
&Transaction,
|
||||
),
|
||||
)> {
|
||||
let txindex = idxs.txindex + block_txindex;
|
||||
let txoutindex = idxs.txoutindex + Txoutindex::from(block_txoutindex);
|
||||
let outputindex = idxs.outputindex + OutputIndex::from(block_outputindex);
|
||||
|
||||
let script = &txout.script_pubkey;
|
||||
|
||||
let addresstype = Addresstype::from(script);
|
||||
let outputtype = OutputType::from(script);
|
||||
|
||||
let addressbytes_res =
|
||||
Addressbytes::try_from((script, addresstype)).inspect_err(|_| {
|
||||
let address_bytes_res =
|
||||
AddressBytes::try_from((script, outputtype)).inspect_err(|_| {
|
||||
// dbg!(&txout, height, txi, &tx.compute_txid());
|
||||
});
|
||||
|
||||
let addressindex_opt = addressbytes_res.as_ref().ok().and_then(|addressbytes| {
|
||||
let outputtypeindex_opt = address_bytes_res.as_ref().ok().and_then(|addressbytes| {
|
||||
stores
|
||||
.addresshash_to_addressindex
|
||||
.get(&AddressHash::from((addressbytes, addresstype)))
|
||||
.addressbyteshash_to_outputtypeindex
|
||||
.get(&AddressBytesHash::from((addressbytes, outputtype)))
|
||||
.unwrap()
|
||||
.map(|v| *v)
|
||||
// Checking if not in the future
|
||||
.and_then(|addressindex_local| {
|
||||
(addressindex_local < idxs.addressindex).then_some(addressindex_local)
|
||||
.and_then(|outputtypeindex_local| {
|
||||
(outputtypeindex_local < idxs.outputtypeindex(outputtype)).then_some(outputtypeindex_local)
|
||||
})
|
||||
});
|
||||
|
||||
if let Some(Some(addressindex)) = check_collisions.then_some(addressindex_opt) {
|
||||
let addressbytes = addressbytes_res.as_ref().unwrap();
|
||||
|
||||
let prev_addresstype = *vecs
|
||||
.addressindex_to_addresstype
|
||||
.get(addressindex)?
|
||||
.context("Expect to have address type")?;
|
||||
|
||||
let addresstypeindex = *vecs
|
||||
.addressindex_to_addresstypeindex
|
||||
.get(addressindex)?
|
||||
.context("Expect to have address type index")?;
|
||||
if let Some(Some(outputtypeindex)) = check_collisions.then_some(outputtypeindex_opt) {
|
||||
let addressbytes = address_bytes_res.as_ref().unwrap();
|
||||
|
||||
let prev_addressbytes_opt =
|
||||
vecs.get_addressbytes(prev_addresstype, addresstypeindex)?;
|
||||
|
||||
vecs.get_addressbytes(outputtype, outputtypeindex)?;
|
||||
let prev_addressbytes =
|
||||
prev_addressbytes_opt.as_ref().context("Expect to have addressbytes")?;
|
||||
|
||||
if (vecs.addressindex_to_addresstype.hasnt(addressindex)?
|
||||
&& addresstype != prev_addresstype)
|
||||
|| (stores.addresshash_to_addressindex.needs(height)
|
||||
&& prev_addressbytes != addressbytes)
|
||||
if stores.addressbyteshash_to_outputtypeindex.needs(height)
|
||||
&& prev_addressbytes != addressbytes
|
||||
{
|
||||
let txid = tx.compute_txid();
|
||||
dbg!(
|
||||
@@ -369,30 +363,28 @@ impl Indexer {
|
||||
txid,
|
||||
vout,
|
||||
block_txindex,
|
||||
addresstype,
|
||||
prev_addresstype,
|
||||
outputtype,
|
||||
prev_addressbytes,
|
||||
addressbytes,
|
||||
idxs.addressindex,
|
||||
addressindex,
|
||||
addresstypeindex,
|
||||
&idxs,
|
||||
outputtypeindex,
|
||||
outputtypeindex,
|
||||
txout,
|
||||
AddressHash::from((addressbytes, addresstype)),
|
||||
AddressHash::from((prev_addressbytes, prev_addresstype))
|
||||
AddressBytesHash::from((addressbytes, outputtype)),
|
||||
);
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
|
||||
Ok((
|
||||
txoutindex,
|
||||
outputindex,
|
||||
(
|
||||
txout,
|
||||
txindex,
|
||||
vout,
|
||||
addresstype,
|
||||
addressbytes_res,
|
||||
addressindex_opt,
|
||||
outputtype,
|
||||
address_bytes_res,
|
||||
outputtypeindex_opt,
|
||||
tx,
|
||||
),
|
||||
))
|
||||
@@ -417,7 +409,7 @@ impl Indexer {
|
||||
(
|
||||
txid_prefix_to_txid_and_block_txindex_and_prev_txindex_handle.join(),
|
||||
input_source_vec_handle.join(),
|
||||
txoutindex_to_txout_addresstype_addressbytes_res_addressindex_opt_handle.join(),
|
||||
outputindex_to_txout_outputtype_addressbytes_res_addressindex_opt_handle.join(),
|
||||
)
|
||||
});
|
||||
|
||||
@@ -432,118 +424,139 @@ impl Indexer {
|
||||
.ok()
|
||||
.context("Export input_source_vec_handle to join")??;
|
||||
|
||||
let txoutindex_to_txout_addresstype_addressbytes_res_addressindex_opt =
|
||||
txoutindex_to_txout_addresstype_addressbytes_res_addressindex_opt_handle
|
||||
let outputindex_to_txout_outputtype_addressbytes_res_addressindex_opt =
|
||||
outputindex_to_txout_outputtype_addressbytes_res_addressindex_opt_handle
|
||||
.ok()
|
||||
.context(
|
||||
"Expect txoutindex_to_txout_addresstype_addressbytes_res_addressindex_opt_handle to join",
|
||||
"Expect outputindex_to_txout_outputtype_addressbytes_res_addressindex_opt_handle to join",
|
||||
)??;
|
||||
|
||||
let mut new_txindexvout_to_txoutindex: BTreeMap<
|
||||
(Txindex, Vout),
|
||||
Txoutindex,
|
||||
let mut new_txindexvout_to_outputindex: BTreeMap<
|
||||
(TxIndex, Vout),
|
||||
OutputIndex,
|
||||
> = BTreeMap::new();
|
||||
|
||||
let mut already_added_addresshash: BTreeMap<AddressHash, Addressindex> = BTreeMap::new();
|
||||
let mut already_added_addressbyteshash: BTreeMap<AddressBytesHash, OutputTypeIndex> = BTreeMap::new();
|
||||
|
||||
txoutindex_to_txout_addresstype_addressbytes_res_addressindex_opt
|
||||
outputindex_to_txout_outputtype_addressbytes_res_addressindex_opt
|
||||
.into_iter()
|
||||
.try_for_each(
|
||||
|(
|
||||
txoutindex,
|
||||
(txout, txindex, vout, addresstype, addressbytes_res, addressindex_opt, _tx),
|
||||
outputindex,
|
||||
(txout, txindex, vout, outputtype, addressbytes_res, outputtypeindex_opt, _tx),
|
||||
)|
|
||||
-> color_eyre::Result<()> {
|
||||
let sats = Sats::from(txout.value);
|
||||
|
||||
if vout.is_zero() {
|
||||
vecs.txindex_to_first_txoutindex.push_if_needed(txindex, txoutindex)?;
|
||||
vecs.txindex_to_first_outputindex.push_if_needed(txindex, outputindex)?;
|
||||
}
|
||||
|
||||
vecs.txoutindex_to_value.push_if_needed(txoutindex, sats)?;
|
||||
vecs.outputindex_to_value.push_if_needed(outputindex, sats)?;
|
||||
|
||||
let mut addressindex = idxs.addressindex;
|
||||
vecs.outputindex_to_outputtype
|
||||
.push_if_needed(outputindex, outputtype)?;
|
||||
|
||||
let mut addresshash = None;
|
||||
let mut addressbyteshash = None;
|
||||
|
||||
if let Some(addressindex_local) = addressindex_opt.or_else(|| {
|
||||
let outputtypeindex;
|
||||
|
||||
if let Some(outputtypeindex_local) = outputtypeindex_opt.or_else(|| {
|
||||
addressbytes_res.as_ref().ok().and_then(|addressbytes| {
|
||||
// Check if address was first seen before in this iterator
|
||||
// Example: https://mempool.space/address/046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0c
|
||||
addresshash.replace(AddressHash::from((addressbytes, addresstype)));
|
||||
already_added_addresshash
|
||||
.get(addresshash.as_ref().unwrap())
|
||||
addressbyteshash.replace(AddressBytesHash::from((addressbytes, outputtype)));
|
||||
already_added_addressbyteshash
|
||||
.get(addressbyteshash.as_ref().unwrap())
|
||||
.cloned()
|
||||
})
|
||||
}) {
|
||||
addressindex = addressindex_local;
|
||||
outputtypeindex = outputtypeindex_local;
|
||||
} else {
|
||||
idxs.addressindex.increment();
|
||||
|
||||
let addresstypeindex = match addresstype {
|
||||
Addresstype::Empty => idxs.emptyindex.copy_then_increment(),
|
||||
Addresstype::Multisig => idxs.multisigindex.copy_then_increment(),
|
||||
Addresstype::OpReturn => idxs.opreturnindex.copy_then_increment(),
|
||||
Addresstype::PushOnly => idxs.pushonlyindex.copy_then_increment(),
|
||||
Addresstype::Unknown => idxs.unknownindex.copy_then_increment(),
|
||||
Addresstype::P2PK65 => idxs.p2pk65index.copy_then_increment(),
|
||||
Addresstype::P2PK33 => idxs.p2pk33index.copy_then_increment(),
|
||||
Addresstype::P2PKH => idxs.p2pkhindex.copy_then_increment(),
|
||||
Addresstype::P2SH => idxs.p2shindex.copy_then_increment(),
|
||||
Addresstype::P2WPKH => idxs.p2wpkhindex.copy_then_increment(),
|
||||
Addresstype::P2WSH => idxs.p2wshindex.copy_then_increment(),
|
||||
Addresstype::P2TR => idxs.p2trindex.copy_then_increment(),
|
||||
outputtypeindex = match outputtype {
|
||||
OutputType::P2PK65 => {
|
||||
idxs.p2pk65index.copy_then_increment()
|
||||
},
|
||||
OutputType::P2PK33 => {
|
||||
idxs.p2pk33index.copy_then_increment()
|
||||
},
|
||||
OutputType::P2PKH => {
|
||||
idxs.p2pkhindex.copy_then_increment()
|
||||
},
|
||||
OutputType::P2MS => {
|
||||
vecs.p2msindex_to_txindex.push_if_needed(idxs.p2msindex, txindex)?;
|
||||
idxs.p2msindex.copy_then_increment()
|
||||
},
|
||||
OutputType::P2SH => {
|
||||
idxs.p2shindex.copy_then_increment()
|
||||
},
|
||||
OutputType::OpReturn => {
|
||||
vecs.opreturnindex_to_txindex.push_if_needed(idxs.opreturnindex, txindex)?;
|
||||
idxs.opreturnindex.copy_then_increment()
|
||||
},
|
||||
OutputType::P2WPKH => {
|
||||
idxs.p2wpkhindex.copy_then_increment()
|
||||
},
|
||||
OutputType::P2WSH => {
|
||||
idxs.p2wshindex.copy_then_increment()
|
||||
},
|
||||
OutputType::P2TR => {
|
||||
idxs.p2trindex.copy_then_increment()
|
||||
},
|
||||
OutputType::P2A => {
|
||||
idxs.p2aindex.copy_then_increment()
|
||||
},
|
||||
OutputType::Empty => {
|
||||
vecs.emptyoutputindex_to_txindex
|
||||
.push_if_needed(idxs.emptyoutputindex, txindex)?;
|
||||
idxs.emptyoutputindex.copy_then_increment()
|
||||
},
|
||||
OutputType::Unknown => {
|
||||
vecs.unknownoutputindex_to_txindex.push_if_needed(idxs.unknownoutputindex, txindex)?;
|
||||
idxs.unknownoutputindex.copy_then_increment()
|
||||
},
|
||||
};
|
||||
|
||||
vecs.addressindex_to_addresstype
|
||||
.push_if_needed(addressindex, addresstype)?;
|
||||
|
||||
vecs.addressindex_to_addresstypeindex
|
||||
.push_if_needed(addressindex, addresstypeindex)?;
|
||||
|
||||
vecs.addressindex_to_height
|
||||
.push_if_needed(addressindex, height)?;
|
||||
|
||||
if let Ok(addressbytes) = addressbytes_res {
|
||||
let addresshash = addresshash.unwrap();
|
||||
let addressbyteshash = addressbyteshash.unwrap();
|
||||
|
||||
already_added_addresshash
|
||||
.insert(addresshash, addressindex);
|
||||
already_added_addressbyteshash
|
||||
.insert(addressbyteshash, outputtypeindex);
|
||||
|
||||
stores.addresshash_to_addressindex.insert_if_needed(
|
||||
addresshash,
|
||||
addressindex,
|
||||
stores.addressbyteshash_to_outputtypeindex.insert_if_needed(
|
||||
addressbyteshash,
|
||||
outputtypeindex,
|
||||
height,
|
||||
);
|
||||
|
||||
vecs.push_addressbytes_if_needed(addresstypeindex, addressbytes)?;
|
||||
vecs.push_bytes_if_needed(outputtypeindex, addressbytes)?;
|
||||
}
|
||||
}
|
||||
|
||||
new_txindexvout_to_txoutindex
|
||||
.insert((txindex, vout), txoutindex);
|
||||
vecs.outputindex_to_outputtypeindex
|
||||
.push_if_needed(outputindex, outputtypeindex)?;
|
||||
|
||||
vecs.txoutindex_to_addressindex
|
||||
.push_if_needed(txoutindex, addressindex)?;
|
||||
new_txindexvout_to_outputindex
|
||||
.insert((txindex, vout), outputindex);
|
||||
|
||||
Ok(())
|
||||
},
|
||||
)?;
|
||||
|
||||
drop(already_added_addresshash);
|
||||
drop(already_added_addressbyteshash);
|
||||
|
||||
input_source_vec
|
||||
.into_iter()
|
||||
.map(
|
||||
#[allow(clippy::type_complexity)]
|
||||
|(txinindex, input_source)| -> color_eyre::Result<(
|
||||
Txinindex, Vin, Txindex, Txoutindex
|
||||
|(inputindex, input_source)| -> color_eyre::Result<(
|
||||
InputIndex, Vin, TxIndex, OutputIndex
|
||||
)> {
|
||||
match input_source {
|
||||
InputSource::PreviousBlock((vin, txindex, txoutindex)) => Ok((txinindex, vin, txindex, txoutindex)),
|
||||
InputSource::PreviousBlock((vin, txindex, outputindex)) => Ok((inputindex, vin, txindex, outputindex)),
|
||||
InputSource::SameBlock((tx, txindex, txin, vin)) => {
|
||||
if tx.is_coinbase() {
|
||||
return Ok((txinindex, vin, txindex, Txoutindex::COINBASE));
|
||||
return Ok((inputindex, vin, txindex, OutputIndex::COINBASE));
|
||||
}
|
||||
|
||||
let outpoint = txin.previous_output;
|
||||
@@ -559,33 +572,33 @@ impl Indexer {
|
||||
.2;
|
||||
let prev_txindex = idxs.txindex + block_txindex;
|
||||
|
||||
let prev_txoutindex = new_txindexvout_to_txoutindex
|
||||
let prev_outputindex = new_txindexvout_to_outputindex
|
||||
.remove(&(prev_txindex, vout))
|
||||
.context("should have found addressindex from same block")
|
||||
.inspect_err(|_| {
|
||||
dbg!(&new_txindexvout_to_txoutindex, txin, prev_txindex, vout, txid);
|
||||
dbg!(&new_txindexvout_to_outputindex, txin, prev_txindex, vout, txid);
|
||||
})?;
|
||||
|
||||
Ok((txinindex, vin, txindex, prev_txoutindex))
|
||||
Ok((inputindex, vin, txindex, prev_outputindex))
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
.try_for_each(|res| -> color_eyre::Result<()> {
|
||||
let (txinindex, vin, txindex, txoutindex) = res?;
|
||||
let (inputindex, vin, txindex, outputindex) = res?;
|
||||
|
||||
if vin.is_zero() {
|
||||
vecs.txindex_to_first_txinindex.push_if_needed(txindex, txinindex)?;
|
||||
vecs.txindex_to_first_inputindex.push_if_needed(txindex, inputindex)?;
|
||||
}
|
||||
|
||||
vecs.txinindex_to_txoutindex.push_if_needed(txinindex, txoutindex)?;
|
||||
vecs.inputindex_to_outputindex.push_if_needed(inputindex, outputindex)?;
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
drop(new_txindexvout_to_txoutindex);
|
||||
drop(new_txindexvout_to_outputindex);
|
||||
|
||||
let mut txindex_to_tx_and_txid: BTreeMap<Txindex, (&Transaction, Txid)> = BTreeMap::default();
|
||||
let mut txindex_to_tx_and_txid: BTreeMap<TxIndex, (&Transaction, Txid)> = BTreeMap::default();
|
||||
|
||||
txid_prefix_to_txid_and_block_txindex_and_prev_txindex
|
||||
.into_iter()
|
||||
@@ -598,7 +611,7 @@ impl Indexer {
|
||||
match prev_txindex_opt {
|
||||
None => {
|
||||
stores
|
||||
.txid_prefix_to_txindex
|
||||
.txidprefix_to_txindex
|
||||
.insert_if_needed(txid_prefix, txindex, height);
|
||||
}
|
||||
Some(prev_txindex) => {
|
||||
@@ -608,7 +621,7 @@ impl Indexer {
|
||||
}
|
||||
|
||||
if !check_collisions {
|
||||
return Ok(())
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let len = vecs.txindex_to_txid.len();
|
||||
@@ -639,9 +652,7 @@ impl Indexer {
|
||||
let is_dup = only_known_dup_txids.contains(prev_txid);
|
||||
|
||||
if !is_dup {
|
||||
let prev_height =
|
||||
vecs.txindex_to_height.get(prev_txindex)?.expect("To have height");
|
||||
dbg!(height, txindex, prev_height, prev_txid, prev_txindex);
|
||||
dbg!(height, txindex, prev_txid, prev_txindex);
|
||||
return Err(eyre!("Expect none"));
|
||||
}
|
||||
}
|
||||
@@ -656,19 +667,16 @@ impl Indexer {
|
||||
.try_for_each(|(txindex, (tx, txid))| -> color_eyre::Result<()> {
|
||||
vecs.txindex_to_txversion.push_if_needed(txindex, tx.version.into())?;
|
||||
vecs.txindex_to_txid.push_if_needed(txindex, txid)?;
|
||||
vecs.txindex_to_height.push_if_needed(txindex, height)?;
|
||||
vecs.txindex_to_locktime.push_if_needed(txindex, tx.lock_time.into())?;
|
||||
vecs.txindex_to_base_size.push_if_needed(txindex, tx.base_size())?;
|
||||
vecs.txindex_to_total_size.push_if_needed(txindex, tx.total_size())?;
|
||||
vecs.txindex_to_rawlocktime.push_if_needed(txindex, tx.lock_time.into())?;
|
||||
vecs.txindex_to_base_size.push_if_needed(txindex, tx.base_size().into())?;
|
||||
vecs.txindex_to_total_size.push_if_needed(txindex, tx.total_size().into())?;
|
||||
vecs.txindex_to_is_explicitly_rbf.push_if_needed(txindex, tx.is_explicitly_rbf())?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
idxs.txindex += Txindex::from(tx_len);
|
||||
idxs.txinindex += Txinindex::from(inputs_len);
|
||||
idxs.txoutindex += Txoutindex::from(outputs_len);
|
||||
|
||||
idxs.push_future_if_needed(vecs)?;
|
||||
idxs.txindex += TxIndex::from(tx_len);
|
||||
idxs.inputindex += InputIndex::from(inputs_len);
|
||||
idxs.outputindex += OutputIndex::from(outputs_len);
|
||||
|
||||
export_if_needed(stores, vecs, height, false, exit)?;
|
||||
|
||||
@@ -683,10 +691,6 @@ impl Indexer {
|
||||
Ok(starting_indexes)
|
||||
}
|
||||
|
||||
pub fn path(&self) -> &Path {
|
||||
&self.path
|
||||
}
|
||||
|
||||
pub fn vecs(&self) -> &Vecs {
|
||||
self.vecs.as_ref().unwrap()
|
||||
}
|
||||
@@ -702,10 +706,14 @@ impl Indexer {
|
||||
pub fn mut_stores(&mut self) -> &mut Stores {
|
||||
self.stores.as_mut().unwrap()
|
||||
}
|
||||
|
||||
pub fn keyspace(&self) -> &TransactionalKeyspace {
|
||||
&self.stores().keyspace
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum InputSource<'a> {
|
||||
PreviousBlock((Vin, Txindex, Txoutindex)),
|
||||
SameBlock((&'a Transaction, Txindex, &'a TxIn, Vin)),
|
||||
PreviousBlock((Vin, TxIndex, OutputIndex)),
|
||||
SameBlock((&'a Transaction, TxIndex, &'a TxIn, Vin)),
|
||||
}
|
||||
|
||||
@@ -19,8 +19,9 @@ use super::StoreMeta;
|
||||
|
||||
pub struct Store<Key, Value> {
|
||||
meta: StoreMeta,
|
||||
name: String,
|
||||
keyspace: TransactionalKeyspace,
|
||||
part: TransactionalPartitionHandle,
|
||||
partition: TransactionalPartitionHandle,
|
||||
rtx: ReadTransaction,
|
||||
puts: BTreeMap<Key, Value>,
|
||||
dels: BTreeSet<Key>,
|
||||
@@ -35,36 +36,32 @@ where
|
||||
V: Debug + Clone + Into<ByteView> + TryFrom<ByteView>,
|
||||
<V as TryFrom<ByteView>>::Error: error::Error + Send + Sync + 'static,
|
||||
{
|
||||
pub fn import(path: &Path, version: Version) -> color_eyre::Result<Self> {
|
||||
pub fn import(
|
||||
keyspace: TransactionalKeyspace,
|
||||
path: &Path,
|
||||
name: &str,
|
||||
version: Version,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let version = MAJOR_FJALL_VERSION + version;
|
||||
|
||||
let meta = StoreMeta::checked_open(path, version)?;
|
||||
|
||||
let keyspace = match Self::open_keyspace(path) {
|
||||
Ok(keyspace) => keyspace,
|
||||
Err(e) => {
|
||||
dbg!(e);
|
||||
meta.reset()?;
|
||||
return Self::import(path, version);
|
||||
}
|
||||
};
|
||||
|
||||
let part = match Self::open_partition_handle(&keyspace) {
|
||||
Ok(part) => part,
|
||||
Err(e) => {
|
||||
dbg!(e);
|
||||
drop(keyspace);
|
||||
meta.reset()?;
|
||||
return Self::import(path, version);
|
||||
}
|
||||
};
|
||||
let (meta, partition) = StoreMeta::checked_open(
|
||||
&keyspace,
|
||||
&path.join(format!("meta/{name}")),
|
||||
version,
|
||||
|| {
|
||||
Self::open_partition_handle(&keyspace, name).inspect_err(|_| {
|
||||
eprintln!("Delete {path:?} and try again");
|
||||
})
|
||||
},
|
||||
)?;
|
||||
|
||||
let rtx = keyspace.read_tx();
|
||||
|
||||
Ok(Self {
|
||||
meta,
|
||||
name: name.to_owned(),
|
||||
keyspace,
|
||||
part,
|
||||
partition,
|
||||
rtx,
|
||||
puts: BTreeMap::new(),
|
||||
dels: BTreeSet::new(),
|
||||
@@ -74,7 +71,7 @@ where
|
||||
pub fn get(&self, key: &K) -> color_eyre::Result<Option<Value<V>>> {
|
||||
if let Some(v) = self.puts.get(key) {
|
||||
Ok(Some(Value::Ref(v)))
|
||||
} else if let Some(slice) = self.rtx.get(&self.part, key.as_bytes())? {
|
||||
} else if let Some(slice) = self.rtx.get(&self.partition, key.as_bytes())? {
|
||||
Ok(Some(Value::Owned(V::try_from(slice.as_bytes().into())?)))
|
||||
} else {
|
||||
Ok(None)
|
||||
@@ -98,10 +95,10 @@ where
|
||||
|
||||
if !self.puts.is_empty() {
|
||||
unreachable!("Shouldn't reach this");
|
||||
// self.puts.remove(&key);
|
||||
}
|
||||
// dbg!(&key);
|
||||
if !self.dels.insert(key) {
|
||||
|
||||
if !self.dels.insert(key.clone()) {
|
||||
dbg!(key, &self.meta.path());
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
@@ -117,25 +114,25 @@ where
|
||||
|
||||
mem::take(&mut self.dels)
|
||||
.into_iter()
|
||||
.for_each(|key| wtx.remove(&self.part, key.as_bytes()));
|
||||
.for_each(|key| wtx.remove(&self.partition, key.as_bytes()));
|
||||
|
||||
mem::take(&mut self.puts)
|
||||
.into_iter()
|
||||
.for_each(|(key, value)| {
|
||||
if CHECK_COLLISISONS {
|
||||
#[allow(unused_must_use)]
|
||||
if let Ok(Some(value)) = wtx.get(&self.part, key.as_bytes()) {
|
||||
if let Ok(Some(value)) = wtx.get(&self.partition, key.as_bytes()) {
|
||||
dbg!(
|
||||
&key,
|
||||
V::try_from(value.as_bytes().into()).unwrap(),
|
||||
&self.meta,
|
||||
self.rtx.get(&self.part, key.as_bytes())
|
||||
self.rtx.get(&self.partition, key.as_bytes())
|
||||
);
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
wtx.insert(
|
||||
&self.part,
|
||||
&self.partition,
|
||||
key.as_bytes(),
|
||||
&*ByteView::try_from(value).unwrap(),
|
||||
)
|
||||
@@ -143,15 +140,13 @@ where
|
||||
|
||||
wtx.commit()?;
|
||||
|
||||
self.keyspace.persist(PersistMode::SyncAll)?;
|
||||
|
||||
self.rtx = self.keyspace.read_tx();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn rotate_memtable(&self) {
|
||||
let _ = self.part.inner().rotate_memtable();
|
||||
let _ = self.partition.inner().rotate_memtable();
|
||||
}
|
||||
|
||||
pub fn height(&self) -> Option<Height> {
|
||||
@@ -172,23 +167,25 @@ where
|
||||
self.meta.needs(height)
|
||||
}
|
||||
|
||||
fn open_keyspace(path: &Path) -> Result<TransactionalKeyspace> {
|
||||
fjall::Config::new(path.join("fjall"))
|
||||
.max_write_buffer_size(32 * 1024 * 1024)
|
||||
.open_transactional()
|
||||
}
|
||||
|
||||
fn open_partition_handle(
|
||||
keyspace: &TransactionalKeyspace,
|
||||
name: &str,
|
||||
) -> Result<TransactionalPartitionHandle> {
|
||||
keyspace.open_partition(
|
||||
"partition",
|
||||
name,
|
||||
PartitionCreateOptions::default()
|
||||
.bloom_filter_bits(Some(5))
|
||||
.max_memtable_size(8 * 1024 * 1024)
|
||||
.manual_journal_persist(true),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn reset_partition(&mut self) -> Result<()> {
|
||||
self.keyspace.delete_partition(self.partition.clone())?;
|
||||
self.keyspace.persist(PersistMode::SyncAll)?;
|
||||
self.partition = Self::open_partition_handle(&self.keyspace, &self.name)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Key, Value> Clone for Store<Key, Value>
|
||||
@@ -199,8 +196,9 @@ where
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
meta: self.meta.clone(),
|
||||
name: self.name.clone(),
|
||||
keyspace: self.keyspace.clone(),
|
||||
part: self.part.clone(),
|
||||
partition: self.partition.clone(),
|
||||
rtx: self.keyspace.read_tx(),
|
||||
puts: self.puts.clone(),
|
||||
dels: self.dels.clone(),
|
||||
|
||||
@@ -4,6 +4,7 @@ use std::{
|
||||
};
|
||||
|
||||
use brk_vec::Version;
|
||||
use fjall::{TransactionalKeyspace, TransactionalPartitionHandle};
|
||||
use zerocopy::{FromBytes, IntoBytes};
|
||||
|
||||
use super::Height;
|
||||
@@ -17,14 +18,27 @@ pub struct StoreMeta {
|
||||
}
|
||||
|
||||
impl StoreMeta {
|
||||
pub fn checked_open(path: &Path, version: Version) -> color_eyre::Result<Self> {
|
||||
pub fn checked_open<F>(
|
||||
keyspace: &TransactionalKeyspace,
|
||||
path: &Path,
|
||||
version: Version,
|
||||
open_partition_handle: F,
|
||||
) -> color_eyre::Result<(Self, TransactionalPartitionHandle)>
|
||||
where
|
||||
F: Fn() -> fjall::Result<TransactionalPartitionHandle>,
|
||||
{
|
||||
fs::create_dir_all(path)?;
|
||||
|
||||
let is_same_version = Version::try_from(Self::path_version_(path).as_path())
|
||||
.is_ok_and(|prev_version| version == prev_version);
|
||||
|
||||
let mut partition = open_partition_handle()?;
|
||||
|
||||
if !is_same_version {
|
||||
Self::reset_(path)?;
|
||||
keyspace.delete_partition(partition)?;
|
||||
keyspace.persist(fjall::PersistMode::SyncAll)?;
|
||||
partition = open_partition_handle()?;
|
||||
}
|
||||
|
||||
let slf = Self {
|
||||
@@ -36,7 +50,7 @@ impl StoreMeta {
|
||||
|
||||
slf.version.write(&slf.path_version())?;
|
||||
|
||||
Ok(slf)
|
||||
Ok((slf, partition))
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
@@ -46,6 +60,10 @@ impl StoreMeta {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
pub fn version(&self) -> Version {
|
||||
self.version
|
||||
}
|
||||
|
||||
pub fn export(&mut self, len: usize, height: Height) -> io::Result<()> {
|
||||
self.len = len;
|
||||
self.write_length()?;
|
||||
@@ -61,6 +79,10 @@ impl StoreMeta {
|
||||
fs::create_dir(path)
|
||||
}
|
||||
|
||||
pub fn path(&self) -> &Path {
|
||||
&self.pathbuf
|
||||
}
|
||||
|
||||
fn path_version(&self) -> PathBuf {
|
||||
Self::path_version_(&self.pathbuf)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use std::{path::Path, thread};
|
||||
use std::{fs, path::Path, thread};
|
||||
|
||||
use brk_core::{
|
||||
AddressHash, Addressbytes, Addressindex, Addresstype, BlockHashPrefix, Height, TxidPrefix,
|
||||
Txindex,
|
||||
AddressBytes, AddressBytesHash, BlockHashPrefix, Height, OutputType, OutputTypeIndex, TxIndex,
|
||||
TxidPrefix,
|
||||
};
|
||||
use brk_vec::{Value, Version};
|
||||
use fjall::{PersistMode, TransactionalKeyspace};
|
||||
|
||||
use crate::Indexes;
|
||||
|
||||
@@ -18,25 +19,57 @@ use super::Vecs;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Stores {
|
||||
pub addresshash_to_addressindex: Store<AddressHash, Addressindex>,
|
||||
pub blockhash_prefix_to_height: Store<BlockHashPrefix, Height>,
|
||||
pub txid_prefix_to_txindex: Store<TxidPrefix, Txindex>,
|
||||
pub keyspace: TransactionalKeyspace,
|
||||
pub addressbyteshash_to_outputtypeindex: Store<AddressBytesHash, OutputTypeIndex>,
|
||||
pub blockhashprefix_to_height: Store<BlockHashPrefix, Height>,
|
||||
pub txidprefix_to_txindex: Store<TxidPrefix, TxIndex>,
|
||||
}
|
||||
|
||||
impl Stores {
|
||||
pub fn import(path: &Path) -> color_eyre::Result<Self> {
|
||||
pub fn forced_import(path: &Path) -> color_eyre::Result<Self> {
|
||||
fs::create_dir_all(path)?;
|
||||
|
||||
let keyspace = match Self::open_keyspace(path) {
|
||||
Ok(keyspace) => keyspace,
|
||||
Err(_) => {
|
||||
fs::remove_dir_all(path)?;
|
||||
return Self::forced_import(path);
|
||||
}
|
||||
};
|
||||
|
||||
thread::scope(|scope| {
|
||||
let addresshash_to_addressindex = scope
|
||||
.spawn(|| Store::import(&path.join("addresshash_to_addressindex"), Version::ONE));
|
||||
let blockhash_prefix_to_height = scope
|
||||
.spawn(|| Store::import(&path.join("blockhash_prefix_to_height"), Version::ONE));
|
||||
let txid_prefix_to_txindex =
|
||||
scope.spawn(|| Store::import(&path.join("txid_prefix_to_txindex"), Version::ONE));
|
||||
let addressbyteshash_to_outputtypeindex = scope.spawn(|| {
|
||||
Store::import(
|
||||
keyspace.clone(),
|
||||
path,
|
||||
"addressbyteshash_to_outputtypeindex",
|
||||
Version::ZERO,
|
||||
)
|
||||
});
|
||||
let blockhashprefix_to_height = scope.spawn(|| {
|
||||
Store::import(
|
||||
keyspace.clone(),
|
||||
path,
|
||||
"blockhashprefix_to_height",
|
||||
Version::ZERO,
|
||||
)
|
||||
});
|
||||
let txidprefix_to_txindex = scope.spawn(|| {
|
||||
Store::import(
|
||||
keyspace.clone(),
|
||||
path,
|
||||
"txidprefix_to_txindex",
|
||||
Version::ZERO,
|
||||
)
|
||||
});
|
||||
|
||||
Ok(Self {
|
||||
addresshash_to_addressindex: addresshash_to_addressindex.join().unwrap()?,
|
||||
blockhash_prefix_to_height: blockhash_prefix_to_height.join().unwrap()?,
|
||||
txid_prefix_to_txindex: txid_prefix_to_txindex.join().unwrap()?,
|
||||
keyspace: keyspace.clone(),
|
||||
addressbyteshash_to_outputtypeindex: addressbyteshash_to_outputtypeindex
|
||||
.join()
|
||||
.unwrap()?,
|
||||
blockhashprefix_to_height: blockhashprefix_to_height.join().unwrap()?,
|
||||
txidprefix_to_txindex: txidprefix_to_txindex.join().unwrap()?,
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -46,144 +79,179 @@ impl Stores {
|
||||
vecs: &mut Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
) -> color_eyre::Result<()> {
|
||||
if self.addresshash_to_addressindex.is_empty()
|
||||
&& self.blockhash_prefix_to_height.is_empty()
|
||||
&& self.txid_prefix_to_txindex.is_empty()
|
||||
if self.addressbyteshash_to_outputtypeindex.is_empty()
|
||||
&& self.blockhashprefix_to_height.is_empty()
|
||||
&& self.txidprefix_to_txindex.is_empty()
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
vecs.height_to_blockhash
|
||||
.iter_from(starting_indexes.height, |(_, blockhash, ..)| {
|
||||
let blockhash_prefix = BlockHashPrefix::from(blockhash);
|
||||
self.blockhash_prefix_to_height.remove(blockhash_prefix);
|
||||
Ok(())
|
||||
})?;
|
||||
if starting_indexes.height != Height::ZERO {
|
||||
vecs.height_to_blockhash
|
||||
.iter_at(starting_indexes.height)
|
||||
.for_each(|(_, v)| {
|
||||
let blockhashprefix = BlockHashPrefix::from(Value::into_inner(v));
|
||||
self.blockhashprefix_to_height.remove(blockhashprefix);
|
||||
});
|
||||
|
||||
vecs.txindex_to_txid
|
||||
.iter_from(starting_indexes.txindex, |(_txindex, txid, ..)| {
|
||||
let txid_prefix = TxidPrefix::from(txid);
|
||||
self.txid_prefix_to_txindex.remove(txid_prefix);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
if let Some(index) = vecs
|
||||
.height_to_first_p2pk65index
|
||||
.get(starting_indexes.height)?
|
||||
{
|
||||
let mut index = index.into_inner();
|
||||
while let Some(typedbytes) = vecs
|
||||
.p2pk65index_to_p2pk65addressbytes
|
||||
.get(index)?
|
||||
if let Some(mut index) = vecs
|
||||
.height_to_first_p2pk65index
|
||||
.get(starting_indexes.height)?
|
||||
.map(Value::into_inner)
|
||||
{
|
||||
let bytes = Addressbytes::from(typedbytes);
|
||||
let hash = AddressHash::from((&bytes, Addresstype::P2PK65));
|
||||
self.addresshash_to_addressindex.remove(hash);
|
||||
index.increment();
|
||||
while let Some(typedbytes) = vecs
|
||||
.p2pk65index_to_p2pk65bytes
|
||||
.get(index)?
|
||||
.map(Value::into_inner)
|
||||
{
|
||||
let bytes = AddressBytes::from(typedbytes);
|
||||
let hash = AddressBytesHash::from((&bytes, OutputType::P2PK65));
|
||||
self.addressbyteshash_to_outputtypeindex.remove(hash);
|
||||
index.increment();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(mut index) = vecs
|
||||
.height_to_first_p2pk33index
|
||||
.get(starting_indexes.height)?
|
||||
.map(Value::into_inner)
|
||||
{
|
||||
while let Some(typedbytes) = vecs
|
||||
.p2pk33index_to_p2pk33bytes
|
||||
.get(index)?
|
||||
.map(Value::into_inner)
|
||||
{
|
||||
let bytes = AddressBytes::from(typedbytes);
|
||||
let hash = AddressBytesHash::from((&bytes, OutputType::P2PK33));
|
||||
self.addressbyteshash_to_outputtypeindex.remove(hash);
|
||||
index.increment();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(mut index) = vecs
|
||||
.height_to_first_p2pkhindex
|
||||
.get(starting_indexes.height)?
|
||||
.map(Value::into_inner)
|
||||
{
|
||||
while let Some(typedbytes) = vecs
|
||||
.p2pkhindex_to_p2pkhbytes
|
||||
.get(index)?
|
||||
.map(Value::into_inner)
|
||||
{
|
||||
let bytes = AddressBytes::from(typedbytes);
|
||||
let hash = AddressBytesHash::from((&bytes, OutputType::P2PKH));
|
||||
self.addressbyteshash_to_outputtypeindex.remove(hash);
|
||||
index.increment();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(mut index) = vecs
|
||||
.height_to_first_p2shindex
|
||||
.get(starting_indexes.height)?
|
||||
.map(Value::into_inner)
|
||||
{
|
||||
while let Some(typedbytes) = vecs
|
||||
.p2shindex_to_p2shbytes
|
||||
.get(index)?
|
||||
.map(Value::into_inner)
|
||||
{
|
||||
let bytes = AddressBytes::from(typedbytes);
|
||||
let hash = AddressBytesHash::from((&bytes, OutputType::P2SH));
|
||||
self.addressbyteshash_to_outputtypeindex.remove(hash);
|
||||
index.increment();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(mut index) = vecs
|
||||
.height_to_first_p2trindex
|
||||
.get(starting_indexes.height)?
|
||||
.map(Value::into_inner)
|
||||
{
|
||||
while let Some(typedbytes) = vecs
|
||||
.p2trindex_to_p2trbytes
|
||||
.get(index)?
|
||||
.map(Value::into_inner)
|
||||
{
|
||||
let bytes = AddressBytes::from(typedbytes);
|
||||
let hash = AddressBytesHash::from((&bytes, OutputType::P2TR));
|
||||
self.addressbyteshash_to_outputtypeindex.remove(hash);
|
||||
index.increment();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(mut index) = vecs
|
||||
.height_to_first_p2wpkhindex
|
||||
.get(starting_indexes.height)?
|
||||
.map(Value::into_inner)
|
||||
{
|
||||
while let Some(typedbytes) = vecs
|
||||
.p2wpkhindex_to_p2wpkhbytes
|
||||
.get(index)?
|
||||
.map(Value::into_inner)
|
||||
{
|
||||
let bytes = AddressBytes::from(typedbytes);
|
||||
let hash = AddressBytesHash::from((&bytes, OutputType::P2WPKH));
|
||||
self.addressbyteshash_to_outputtypeindex.remove(hash);
|
||||
index.increment();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(mut index) = vecs
|
||||
.height_to_first_p2wshindex
|
||||
.get(starting_indexes.height)?
|
||||
.map(Value::into_inner)
|
||||
{
|
||||
while let Some(typedbytes) = vecs
|
||||
.p2wshindex_to_p2wshbytes
|
||||
.get(index)?
|
||||
.map(Value::into_inner)
|
||||
{
|
||||
let bytes = AddressBytes::from(typedbytes);
|
||||
let hash = AddressBytesHash::from((&bytes, OutputType::P2WSH));
|
||||
self.addressbyteshash_to_outputtypeindex.remove(hash);
|
||||
index.increment();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(mut index) = vecs
|
||||
.height_to_first_p2aindex
|
||||
.get(starting_indexes.height)?
|
||||
.map(Value::into_inner)
|
||||
{
|
||||
while let Some(typedbytes) =
|
||||
vecs.p2aindex_to_p2abytes.get(index)?.map(Value::into_inner)
|
||||
{
|
||||
let bytes = AddressBytes::from(typedbytes);
|
||||
let hash = AddressBytesHash::from((&bytes, OutputType::P2A));
|
||||
self.addressbyteshash_to_outputtypeindex.remove(hash);
|
||||
index.increment();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.blockhashprefix_to_height.reset_partition()?;
|
||||
self.addressbyteshash_to_outputtypeindex.reset_partition()?;
|
||||
}
|
||||
|
||||
if let Some(index) = vecs
|
||||
.height_to_first_p2pk33index
|
||||
.get(starting_indexes.height)?
|
||||
{
|
||||
let mut index = index.into_inner();
|
||||
while let Some(typedbytes) = vecs
|
||||
.p2pk33index_to_p2pk33addressbytes
|
||||
.get(index)?
|
||||
.map(Value::into_inner)
|
||||
{
|
||||
let bytes = Addressbytes::from(typedbytes);
|
||||
let hash = AddressHash::from((&bytes, Addresstype::P2PK33));
|
||||
self.addresshash_to_addressindex.remove(hash);
|
||||
index.increment();
|
||||
}
|
||||
}
|
||||
if starting_indexes.txindex != TxIndex::ZERO {
|
||||
vecs.txindex_to_txid
|
||||
.iter_at(starting_indexes.txindex)
|
||||
.for_each(|(txindex, txid)| {
|
||||
let txidprefix = TxidPrefix::from(&txid.into_inner());
|
||||
|
||||
if let Some(index) = vecs
|
||||
.height_to_first_p2pkhindex
|
||||
.get(starting_indexes.height)?
|
||||
{
|
||||
let mut index = index.into_inner();
|
||||
while let Some(typedbytes) = vecs
|
||||
.p2pkhindex_to_p2pkhaddressbytes
|
||||
.get(index)?
|
||||
.map(Value::into_inner)
|
||||
{
|
||||
let bytes = Addressbytes::from(typedbytes);
|
||||
let hash = AddressHash::from((&bytes, Addresstype::P2PKH));
|
||||
self.addresshash_to_addressindex.remove(hash);
|
||||
index.increment();
|
||||
}
|
||||
}
|
||||
// "d5d27987d2a3dfc724e359870c6644b40e497bdc0589a033220fe15429d88599"
|
||||
let is_not_first_dup = txindex != TxIndex::new(142783)
|
||||
|| txidprefix != TxidPrefix::from([153, 133, 216, 41, 84, 225, 15, 34]);
|
||||
|
||||
if let Some(index) = vecs
|
||||
.height_to_first_p2shindex
|
||||
.get(starting_indexes.height)?
|
||||
{
|
||||
let mut index = index.into_inner();
|
||||
while let Some(typedbytes) = vecs
|
||||
.p2shindex_to_p2shaddressbytes
|
||||
.get(index)?
|
||||
.map(Value::into_inner)
|
||||
{
|
||||
let bytes = Addressbytes::from(typedbytes);
|
||||
let hash = AddressHash::from((&bytes, Addresstype::P2SH));
|
||||
self.addresshash_to_addressindex.remove(hash);
|
||||
index.increment();
|
||||
}
|
||||
}
|
||||
// "e3bf3d07d4b0375638d5f1db5255fe07ba2c4cb067cd81b84ee974b6585fb468"
|
||||
let is_not_second_dup = txindex != TxIndex::new(142841)
|
||||
|| txidprefix != TxidPrefix::from([104, 180, 95, 88, 182, 116, 233, 78]);
|
||||
|
||||
if let Some(index) = vecs
|
||||
.height_to_first_p2trindex
|
||||
.get(starting_indexes.height)?
|
||||
{
|
||||
let mut index = index.into_inner();
|
||||
while let Some(typedbytes) = vecs
|
||||
.p2trindex_to_p2traddressbytes
|
||||
.get(index)?
|
||||
.map(Value::into_inner)
|
||||
{
|
||||
let bytes = Addressbytes::from(typedbytes);
|
||||
let hash = AddressHash::from((&bytes, Addresstype::P2TR));
|
||||
self.addresshash_to_addressindex.remove(hash);
|
||||
index.increment();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(index) = vecs
|
||||
.height_to_first_p2wpkhindex
|
||||
.get(starting_indexes.height)?
|
||||
{
|
||||
let mut index = index.into_inner();
|
||||
while let Some(typedbytes) = vecs
|
||||
.p2wpkhindex_to_p2wpkhaddressbytes
|
||||
.get(index)?
|
||||
.map(Value::into_inner)
|
||||
{
|
||||
let bytes = Addressbytes::from(typedbytes);
|
||||
let hash = AddressHash::from((&bytes, Addresstype::P2WPKH));
|
||||
self.addresshash_to_addressindex.remove(hash);
|
||||
index.increment();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(index) = vecs
|
||||
.height_to_first_p2wshindex
|
||||
.get(starting_indexes.height)?
|
||||
{
|
||||
let mut index = index.into_inner();
|
||||
while let Some(typedbytes) = vecs
|
||||
.p2wshindex_to_p2wshaddressbytes
|
||||
.get(index)?
|
||||
.map(Value::into_inner)
|
||||
{
|
||||
let bytes = Addressbytes::from(typedbytes);
|
||||
let hash = AddressHash::from((&bytes, Addresstype::P2WSH));
|
||||
self.addresshash_to_addressindex.remove(hash);
|
||||
index.increment();
|
||||
}
|
||||
if is_not_first_dup && is_not_second_dup {
|
||||
self.txidprefix_to_txindex.remove(txidprefix);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
self.txidprefix_to_txindex.reset_partition()?;
|
||||
}
|
||||
|
||||
self.commit(starting_indexes.height.decremented().unwrap_or_default())?;
|
||||
@@ -193,9 +261,9 @@ impl Stores {
|
||||
|
||||
pub fn starting_height(&self) -> Height {
|
||||
[
|
||||
self.addresshash_to_addressindex.height(),
|
||||
self.blockhash_prefix_to_height.height(),
|
||||
self.txid_prefix_to_txindex.height(),
|
||||
self.addressbyteshash_to_outputtypeindex.height(),
|
||||
self.blockhashprefix_to_height.height(),
|
||||
self.txidprefix_to_txindex.height(),
|
||||
]
|
||||
.into_iter()
|
||||
.map(|height| height.map(Height::incremented).unwrap_or_default())
|
||||
@@ -204,25 +272,35 @@ impl Stores {
|
||||
}
|
||||
|
||||
pub fn commit(&mut self, height: Height) -> fjall::Result<()> {
|
||||
thread::scope(|scope| {
|
||||
let addresshash_to_addressindex_commit_handle =
|
||||
scope.spawn(|| self.addresshash_to_addressindex.commit(height));
|
||||
let blockhash_prefix_to_height_commit_handle =
|
||||
scope.spawn(|| self.blockhash_prefix_to_height.commit(height));
|
||||
let txid_prefix_to_txindex_commit_handle =
|
||||
scope.spawn(|| self.txid_prefix_to_txindex.commit(height));
|
||||
thread::scope(|scope| -> fjall::Result<()> {
|
||||
let addressbyteshash_to_outputtypeindex_commit_handle =
|
||||
scope.spawn(|| self.addressbyteshash_to_outputtypeindex.commit(height));
|
||||
let blockhashprefix_to_height_commit_handle =
|
||||
scope.spawn(|| self.blockhashprefix_to_height.commit(height));
|
||||
let txidprefix_to_txindex_commit_handle =
|
||||
scope.spawn(|| self.txidprefix_to_txindex.commit(height));
|
||||
|
||||
addresshash_to_addressindex_commit_handle.join().unwrap()?;
|
||||
blockhash_prefix_to_height_commit_handle.join().unwrap()?;
|
||||
txid_prefix_to_txindex_commit_handle.join().unwrap()?;
|
||||
addressbyteshash_to_outputtypeindex_commit_handle
|
||||
.join()
|
||||
.unwrap()?;
|
||||
blockhashprefix_to_height_commit_handle.join().unwrap()?;
|
||||
txidprefix_to_txindex_commit_handle.join().unwrap()?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
})?;
|
||||
|
||||
self.keyspace.persist(PersistMode::SyncAll)
|
||||
}
|
||||
|
||||
pub fn rotate_memtables(&self) {
|
||||
self.addresshash_to_addressindex.rotate_memtable();
|
||||
self.blockhash_prefix_to_height.rotate_memtable();
|
||||
self.txid_prefix_to_txindex.rotate_memtable();
|
||||
self.addressbyteshash_to_outputtypeindex.rotate_memtable();
|
||||
self.blockhashprefix_to_height.rotate_memtable();
|
||||
self.txidprefix_to_txindex.rotate_memtable();
|
||||
}
|
||||
|
||||
fn open_keyspace(path: &Path) -> fjall::Result<TransactionalKeyspace> {
|
||||
fjall::Config::new(path.join("fjall"))
|
||||
.max_write_buffer_size(32 * 1024 * 1024)
|
||||
.open_transactional()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,113 +1,65 @@
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
fmt::Debug,
|
||||
io,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use brk_vec::{
|
||||
AnyStorableVec, Compressed, Error, MAX_CACHE_SIZE, MAX_PAGE_SIZE, Result, StoredIndex,
|
||||
StoredType, Value, Version,
|
||||
Compressed, DynamicVec, Error, GenericVec, Result, StoredIndex, StoredType, StoredVec,
|
||||
StoredVecIterator, Value, Version,
|
||||
};
|
||||
|
||||
use super::Height;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StorableVec<I, T> {
|
||||
height: Option<Height>,
|
||||
vec: brk_vec::StorableVec<I, T>,
|
||||
}
|
||||
|
||||
impl<I, T> StorableVec<I, T>
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IndexedVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
pub const SIZE_OF_T: usize = size_of::<T>();
|
||||
pub const PER_PAGE: usize = MAX_PAGE_SIZE / Self::SIZE_OF_T;
|
||||
pub const PAGE_SIZE: usize = Self::PER_PAGE * Self::SIZE_OF_T;
|
||||
pub const CACHE_LENGTH: usize = MAX_CACHE_SIZE / Self::PAGE_SIZE;
|
||||
height: Option<Height>,
|
||||
inner: StoredVec<I, T>,
|
||||
}
|
||||
|
||||
impl<I, T> IndexedVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
pub fn forced_import(
|
||||
path: &Path,
|
||||
version: Version,
|
||||
compressed: Compressed,
|
||||
) -> brk_vec::Result<Self> {
|
||||
let mut vec = brk_vec::StorableVec::forced_import(path, version, compressed)?;
|
||||
let mut inner = StoredVec::forced_import(path, version, compressed)?;
|
||||
|
||||
vec.enable_large_cache();
|
||||
inner.enable_large_cache_if_needed();
|
||||
|
||||
Ok(Self {
|
||||
height: Height::try_from(Self::path_height_(path).as_path()).ok(),
|
||||
vec,
|
||||
inner,
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get(&self, index: I) -> Result<Option<Value<'_, T>>> {
|
||||
self.get_(index.to_usize()?)
|
||||
}
|
||||
fn get_(&self, index: usize) -> Result<Option<Value<'_, T>>> {
|
||||
match self.vec.index_to_pushed_index(index) {
|
||||
Ok(index) => {
|
||||
if let Some(index) = index {
|
||||
return Ok(self.vec.pushed().get(index).map(|v| Value::Ref(v)));
|
||||
}
|
||||
}
|
||||
Err(Error::IndexTooHigh) => return Ok(None),
|
||||
Err(Error::IndexTooLow) => {}
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
|
||||
let large_cache_len = self.vec.large_cache_len();
|
||||
if large_cache_len != 0 {
|
||||
let page_index = Self::index_to_page_index(index);
|
||||
let last_index = self.vec.stored_len() - 1;
|
||||
let max_page_index = Self::index_to_page_index(last_index);
|
||||
let min_page_index = (max_page_index + 1) - large_cache_len;
|
||||
|
||||
if page_index >= min_page_index {
|
||||
let values = self
|
||||
.vec
|
||||
.pages()
|
||||
.unwrap()
|
||||
.get(page_index - min_page_index)
|
||||
.ok_or(Error::MmapsVecIsTooSmall)?
|
||||
.get_or_init(|| self.vec.decode_page(page_index).unwrap());
|
||||
|
||||
return Ok(values.get(index)?.map(|v| Value::Ref(v)));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(self.vec.read_(index)?.map(|v| Value::Owned(v)))
|
||||
}
|
||||
|
||||
pub fn iter_from<F>(&mut self, index: I, f: F) -> Result<()>
|
||||
where
|
||||
F: FnMut((I, &T)) -> Result<()>,
|
||||
{
|
||||
self.vec.iter_from(index, f)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn index_to_page_index(index: usize) -> usize {
|
||||
index / Self::PER_PAGE
|
||||
self.inner.get(index)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn push_if_needed(&mut self, index: I, value: T) -> Result<()> {
|
||||
match self.vec.len().cmp(&index.to_usize()?) {
|
||||
match self.inner.len().cmp(&index.to_usize()?) {
|
||||
Ordering::Greater => {
|
||||
// dbg!(len, index, &self.pathbuf);
|
||||
// panic!();
|
||||
Ok(())
|
||||
}
|
||||
Ordering::Equal => {
|
||||
self.vec.push(value);
|
||||
self.inner.push(value);
|
||||
Ok(())
|
||||
}
|
||||
Ordering::Less => {
|
||||
dbg!(index, value);
|
||||
dbg!(index, value, self.inner.len(), self.path_height());
|
||||
Err(Error::IndexTooHigh)
|
||||
}
|
||||
}
|
||||
@@ -117,70 +69,67 @@ where
|
||||
if self.height.is_none_or(|self_height| self_height != height) {
|
||||
height.write(&self.path_height())?;
|
||||
}
|
||||
self.vec.truncate_if_needed(index)?;
|
||||
self.inner.truncate_if_needed(index)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn flush(&mut self, height: Height) -> io::Result<()> {
|
||||
pub fn flush(&mut self, height: Height) -> Result<()> {
|
||||
height.write(&self.path_height())?;
|
||||
self.vec.flush()
|
||||
self.inner.flush()
|
||||
}
|
||||
|
||||
pub fn vec(&self) -> &brk_vec::StorableVec<I, T> {
|
||||
&self.vec
|
||||
pub fn vec(&self) -> &StoredVec<I, T> {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub fn mut_vec(&mut self) -> &mut brk_vec::StorableVec<I, T> {
|
||||
&mut self.vec
|
||||
pub fn mut_vec(&mut self) -> &mut StoredVec<I, T> {
|
||||
&mut self.inner
|
||||
}
|
||||
|
||||
pub fn any_vec(&self) -> &dyn AnyStorableVec {
|
||||
&self.vec
|
||||
pub fn any_vec(&self) -> &dyn brk_vec::AnyStoredVec {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.vec.len()
|
||||
self.inner.len()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.vec.is_empty()
|
||||
self.inner.is_empty()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn hasnt(&self, index: I) -> Result<bool> {
|
||||
self.vec.has(index).map(|b| !b)
|
||||
self.inner.has(index).map(|b| !b)
|
||||
}
|
||||
|
||||
pub fn height(&self) -> brk_core::Result<Height> {
|
||||
Height::try_from(self.path_height().as_path())
|
||||
}
|
||||
fn path_height(&self) -> PathBuf {
|
||||
Self::path_height_(self.vec.path())
|
||||
Self::path_height_(self.inner.path())
|
||||
}
|
||||
fn path_height_(path: &Path) -> PathBuf {
|
||||
path.join("height")
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> Clone for StorableVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
height: self.height,
|
||||
vec: self.vec.clone(),
|
||||
}
|
||||
pub fn iter(&self) -> StoredVecIterator<'_, I, T> {
|
||||
self.into_iter()
|
||||
}
|
||||
|
||||
pub fn iter_at(&self, i: I) -> StoredVecIterator<'_, I, T> {
|
||||
let mut iter = self.into_iter();
|
||||
iter.set(i);
|
||||
iter
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AnyIndexedVec: Send + Sync {
|
||||
fn height(&self) -> brk_core::Result<Height>;
|
||||
fn flush(&mut self, height: Height) -> io::Result<()>;
|
||||
fn flush(&mut self, height: Height) -> Result<()>;
|
||||
}
|
||||
|
||||
impl<I, T> AnyIndexedVec for StorableVec<I, T>
|
||||
impl<I, T> AnyIndexedVec for IndexedVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
@@ -189,7 +138,20 @@ where
|
||||
self.height()
|
||||
}
|
||||
|
||||
fn flush(&mut self, height: Height) -> io::Result<()> {
|
||||
fn flush(&mut self, height: Height) -> Result<()> {
|
||||
self.flush(height)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, I, T> IntoIterator for &'a IndexedVec<I, T>
|
||||
where
|
||||
I: StoredIndex,
|
||||
T: StoredType,
|
||||
{
|
||||
type Item = (I, Value<'a, T>);
|
||||
type IntoIter = StoredVecIterator<'a, I, T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.inner.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
+390
-384
@@ -1,13 +1,13 @@
|
||||
use std::{fs, io, path::Path};
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use brk_core::{
|
||||
Addressbytes, Addressindex, Addresstype, Addresstypeindex, BlockHash, Emptyindex, Height,
|
||||
LockTime, Multisigindex, Opreturnindex, P2PK33AddressBytes, P2PK33index, P2PK65AddressBytes,
|
||||
P2PK65index, P2PKHAddressBytes, P2PKHindex, P2SHAddressBytes, P2SHindex, P2TRAddressBytes,
|
||||
P2TRindex, P2WPKHAddressBytes, P2WPKHindex, P2WSHAddressBytes, P2WSHindex, Pushonlyindex, Sats,
|
||||
Timestamp, TxVersion, Txid, Txindex, Txinindex, Txoutindex, Unknownindex, Weight,
|
||||
AddressBytes, BlockHash, EmptyOutputIndex, Height, InputIndex, OpReturnIndex, OutputIndex,
|
||||
OutputType, OutputTypeIndex, P2ABytes, P2AIndex, P2MSIndex, P2PK33Bytes, P2PK33Index,
|
||||
P2PK65Bytes, P2PK65Index, P2PKHBytes, P2PKHIndex, P2SHBytes, P2SHIndex, P2TRBytes, P2TRIndex,
|
||||
P2WPKHBytes, P2WPKHIndex, P2WSHBytes, P2WSHIndex, RawLockTime, Sats, StoredF64, StoredU32,
|
||||
StoredUsize, Timestamp, TxIndex, TxVersion, Txid, UnknownOutputIndex, Weight,
|
||||
};
|
||||
use brk_vec::{AnyStorableVec, Compressed, Version};
|
||||
use brk_vec::{AnyStoredVec, Compressed, Result, Version};
|
||||
use rayon::prelude::*;
|
||||
|
||||
use crate::Indexes;
|
||||
@@ -18,270 +18,277 @@ pub use base::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vecs {
|
||||
pub addressindex_to_addresstype: StorableVec<Addressindex, Addresstype>,
|
||||
pub addressindex_to_addresstypeindex: StorableVec<Addressindex, Addresstypeindex>,
|
||||
pub addressindex_to_height: StorableVec<Addressindex, Height>,
|
||||
pub height_to_blockhash: StorableVec<Height, BlockHash>,
|
||||
pub height_to_difficulty: StorableVec<Height, f64>,
|
||||
pub height_to_first_addressindex: StorableVec<Height, Addressindex>,
|
||||
pub height_to_first_emptyindex: StorableVec<Height, Emptyindex>,
|
||||
pub height_to_first_multisigindex: StorableVec<Height, Multisigindex>,
|
||||
pub height_to_first_opreturnindex: StorableVec<Height, Opreturnindex>,
|
||||
pub height_to_first_pushonlyindex: StorableVec<Height, Pushonlyindex>,
|
||||
pub height_to_first_txindex: StorableVec<Height, Txindex>,
|
||||
pub height_to_first_txinindex: StorableVec<Height, Txinindex>,
|
||||
pub height_to_first_txoutindex: StorableVec<Height, Txoutindex>,
|
||||
pub height_to_first_unknownindex: StorableVec<Height, Unknownindex>,
|
||||
pub height_to_first_p2pk33index: StorableVec<Height, P2PK33index>,
|
||||
pub height_to_first_p2pk65index: StorableVec<Height, P2PK65index>,
|
||||
pub height_to_first_p2pkhindex: StorableVec<Height, P2PKHindex>,
|
||||
pub height_to_first_p2shindex: StorableVec<Height, P2SHindex>,
|
||||
pub height_to_first_p2trindex: StorableVec<Height, P2TRindex>,
|
||||
pub height_to_first_p2wpkhindex: StorableVec<Height, P2WPKHindex>,
|
||||
pub height_to_first_p2wshindex: StorableVec<Height, P2WSHindex>,
|
||||
pub height_to_size: StorableVec<Height, usize>,
|
||||
pub height_to_timestamp: StorableVec<Height, Timestamp>,
|
||||
pub height_to_weight: StorableVec<Height, Weight>,
|
||||
pub p2pk33index_to_p2pk33addressbytes: StorableVec<P2PK33index, P2PK33AddressBytes>,
|
||||
pub p2pk65index_to_p2pk65addressbytes: StorableVec<P2PK65index, P2PK65AddressBytes>,
|
||||
pub p2pkhindex_to_p2pkhaddressbytes: StorableVec<P2PKHindex, P2PKHAddressBytes>,
|
||||
pub p2shindex_to_p2shaddressbytes: StorableVec<P2SHindex, P2SHAddressBytes>,
|
||||
pub p2trindex_to_p2traddressbytes: StorableVec<P2TRindex, P2TRAddressBytes>,
|
||||
pub p2wpkhindex_to_p2wpkhaddressbytes: StorableVec<P2WPKHindex, P2WPKHAddressBytes>,
|
||||
pub p2wshindex_to_p2wshaddressbytes: StorableVec<P2WSHindex, P2WSHAddressBytes>,
|
||||
pub txindex_to_first_txinindex: StorableVec<Txindex, Txinindex>,
|
||||
pub txindex_to_first_txoutindex: StorableVec<Txindex, Txoutindex>,
|
||||
pub txindex_to_height: StorableVec<Txindex, Height>,
|
||||
pub txindex_to_locktime: StorableVec<Txindex, LockTime>,
|
||||
pub txindex_to_txid: StorableVec<Txindex, Txid>,
|
||||
pub txindex_to_base_size: StorableVec<Txindex, usize>,
|
||||
pub txindex_to_total_size: StorableVec<Txindex, usize>,
|
||||
pub txindex_to_is_explicitly_rbf: StorableVec<Txindex, bool>,
|
||||
pub txindex_to_txversion: StorableVec<Txindex, TxVersion>,
|
||||
/// If txoutindex == Txoutindex MAX then is it's coinbase
|
||||
pub txinindex_to_txoutindex: StorableVec<Txinindex, Txoutindex>,
|
||||
pub txoutindex_to_addressindex: StorableVec<Txoutindex, Addressindex>,
|
||||
pub txoutindex_to_value: StorableVec<Txoutindex, Sats>,
|
||||
pub emptyoutputindex_to_txindex: IndexedVec<EmptyOutputIndex, TxIndex>,
|
||||
pub height_to_blockhash: IndexedVec<Height, BlockHash>,
|
||||
pub height_to_difficulty: IndexedVec<Height, StoredF64>,
|
||||
pub height_to_first_emptyoutputindex: IndexedVec<Height, EmptyOutputIndex>,
|
||||
pub height_to_first_inputindex: IndexedVec<Height, InputIndex>,
|
||||
pub height_to_first_opreturnindex: IndexedVec<Height, OpReturnIndex>,
|
||||
pub height_to_first_outputindex: IndexedVec<Height, OutputIndex>,
|
||||
pub height_to_first_p2aindex: IndexedVec<Height, P2AIndex>,
|
||||
pub height_to_first_p2msindex: IndexedVec<Height, P2MSIndex>,
|
||||
pub height_to_first_p2pk33index: IndexedVec<Height, P2PK33Index>,
|
||||
pub height_to_first_p2pk65index: IndexedVec<Height, P2PK65Index>,
|
||||
pub height_to_first_p2pkhindex: IndexedVec<Height, P2PKHIndex>,
|
||||
pub height_to_first_p2shindex: IndexedVec<Height, P2SHIndex>,
|
||||
pub height_to_first_p2trindex: IndexedVec<Height, P2TRIndex>,
|
||||
pub height_to_first_p2wpkhindex: IndexedVec<Height, P2WPKHIndex>,
|
||||
pub height_to_first_p2wshindex: IndexedVec<Height, P2WSHIndex>,
|
||||
pub height_to_first_txindex: IndexedVec<Height, TxIndex>,
|
||||
pub height_to_first_unknownoutputindex: IndexedVec<Height, UnknownOutputIndex>,
|
||||
/// Doesn't guarantee continuity due to possible reorgs
|
||||
pub height_to_timestamp: IndexedVec<Height, Timestamp>,
|
||||
pub height_to_total_size: IndexedVec<Height, StoredUsize>,
|
||||
pub height_to_weight: IndexedVec<Height, Weight>,
|
||||
/// If outputindex == Outputindex::MAX then it's coinbase
|
||||
pub inputindex_to_outputindex: IndexedVec<InputIndex, OutputIndex>,
|
||||
pub opreturnindex_to_txindex: IndexedVec<OpReturnIndex, TxIndex>,
|
||||
pub outputindex_to_outputtype: IndexedVec<OutputIndex, OutputType>,
|
||||
pub outputindex_to_outputtypeindex: IndexedVec<OutputIndex, OutputTypeIndex>,
|
||||
pub outputindex_to_value: IndexedVec<OutputIndex, Sats>,
|
||||
pub p2aindex_to_p2abytes: IndexedVec<P2AIndex, P2ABytes>,
|
||||
pub p2msindex_to_txindex: IndexedVec<P2MSIndex, TxIndex>,
|
||||
pub p2pk33index_to_p2pk33bytes: IndexedVec<P2PK33Index, P2PK33Bytes>,
|
||||
pub p2pk65index_to_p2pk65bytes: IndexedVec<P2PK65Index, P2PK65Bytes>,
|
||||
pub p2pkhindex_to_p2pkhbytes: IndexedVec<P2PKHIndex, P2PKHBytes>,
|
||||
pub p2shindex_to_p2shbytes: IndexedVec<P2SHIndex, P2SHBytes>,
|
||||
pub p2trindex_to_p2trbytes: IndexedVec<P2TRIndex, P2TRBytes>,
|
||||
pub p2wpkhindex_to_p2wpkhbytes: IndexedVec<P2WPKHIndex, P2WPKHBytes>,
|
||||
pub p2wshindex_to_p2wshbytes: IndexedVec<P2WSHIndex, P2WSHBytes>,
|
||||
pub txindex_to_base_size: IndexedVec<TxIndex, StoredU32>,
|
||||
pub txindex_to_first_inputindex: IndexedVec<TxIndex, InputIndex>,
|
||||
pub txindex_to_first_outputindex: IndexedVec<TxIndex, OutputIndex>,
|
||||
pub txindex_to_is_explicitly_rbf: IndexedVec<TxIndex, bool>,
|
||||
pub txindex_to_rawlocktime: IndexedVec<TxIndex, RawLockTime>,
|
||||
pub txindex_to_total_size: IndexedVec<TxIndex, StoredU32>,
|
||||
pub txindex_to_txid: IndexedVec<TxIndex, Txid>,
|
||||
pub txindex_to_txversion: IndexedVec<TxIndex, TxVersion>,
|
||||
pub unknownoutputindex_to_txindex: IndexedVec<UnknownOutputIndex, TxIndex>,
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
pub fn import(path: &Path, compressed: Compressed) -> color_eyre::Result<Self> {
|
||||
pub fn forced_import(path: &Path, compressed: Compressed) -> color_eyre::Result<Self> {
|
||||
fs::create_dir_all(path)?;
|
||||
|
||||
Ok(Self {
|
||||
addressindex_to_addresstype: StorableVec::forced_import(
|
||||
&path.join("addressindex_to_addresstype"),
|
||||
Version::ONE,
|
||||
emptyoutputindex_to_txindex: IndexedVec::forced_import(
|
||||
&path.join("emptyoutputindex_to_txindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
addressindex_to_addresstypeindex: StorableVec::forced_import(
|
||||
&path.join("addressindex_to_addresstypeindex"),
|
||||
Version::ONE,
|
||||
compressed,
|
||||
)?,
|
||||
addressindex_to_height: StorableVec::forced_import(
|
||||
&path.join("addressindex_to_height"),
|
||||
Version::ONE,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_blockhash: StorableVec::forced_import(
|
||||
height_to_blockhash: IndexedVec::forced_import(
|
||||
&path.join("height_to_blockhash"),
|
||||
Version::ONE,
|
||||
Compressed::NO,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_difficulty: StorableVec::forced_import(
|
||||
height_to_difficulty: IndexedVec::forced_import(
|
||||
&path.join("height_to_difficulty"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_addressindex: StorableVec::forced_import(
|
||||
&path.join("height_to_first_addressindex"),
|
||||
Version::ONE,
|
||||
height_to_first_emptyoutputindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_emptyoutputindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_emptyindex: StorableVec::forced_import(
|
||||
&path.join("height_to_first_emptyindex"),
|
||||
Version::ONE,
|
||||
height_to_first_inputindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_inputindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_multisigindex: StorableVec::forced_import(
|
||||
&path.join("height_to_first_multisigindex"),
|
||||
Version::ONE,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_opreturnindex: StorableVec::forced_import(
|
||||
height_to_first_opreturnindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_opreturnindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_pushonlyindex: StorableVec::forced_import(
|
||||
&path.join("height_to_first_pushonlyindex"),
|
||||
Version::ONE,
|
||||
height_to_first_outputindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_outputindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_txindex: StorableVec::forced_import(
|
||||
&path.join("height_to_first_txindex"),
|
||||
Version::ONE,
|
||||
height_to_first_p2aindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_p2aindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_txinindex: StorableVec::forced_import(
|
||||
&path.join("height_to_first_txinindex"),
|
||||
Version::ONE,
|
||||
height_to_first_p2msindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_p2msindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_txoutindex: StorableVec::forced_import(
|
||||
&path.join("height_to_first_txoutindex"),
|
||||
Version::ONE,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_unknownindex: StorableVec::forced_import(
|
||||
&path.join("height_to_first_unkownindex"),
|
||||
Version::ONE,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_p2pk33index: StorableVec::forced_import(
|
||||
height_to_first_p2pk33index: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_p2pk33index"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_p2pk65index: StorableVec::forced_import(
|
||||
height_to_first_p2pk65index: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_p2pk65index"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_p2pkhindex: StorableVec::forced_import(
|
||||
height_to_first_p2pkhindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_p2pkhindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_p2shindex: StorableVec::forced_import(
|
||||
height_to_first_p2shindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_p2shindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_p2trindex: StorableVec::forced_import(
|
||||
height_to_first_p2trindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_p2trindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_p2wpkhindex: StorableVec::forced_import(
|
||||
height_to_first_p2wpkhindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_p2wpkhindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_first_p2wshindex: StorableVec::forced_import(
|
||||
height_to_first_p2wshindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_p2wshindex"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_size: StorableVec::forced_import(
|
||||
&path.join("height_to_size"),
|
||||
Version::ONE,
|
||||
height_to_first_txindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_txindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_timestamp: StorableVec::forced_import(
|
||||
height_to_first_unknownoutputindex: IndexedVec::forced_import(
|
||||
&path.join("height_to_first_unknownoutputindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_timestamp: IndexedVec::forced_import(
|
||||
&path.join("height_to_timestamp"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_weight: StorableVec::forced_import(
|
||||
height_to_total_size: IndexedVec::forced_import(
|
||||
&path.join("height_to_total_size"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
height_to_weight: IndexedVec::forced_import(
|
||||
&path.join("height_to_weight"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2pk33index_to_p2pk33addressbytes: StorableVec::forced_import(
|
||||
&path.join("p2pk33index_to_p2pk33addressbytes"),
|
||||
Version::ONE,
|
||||
Compressed::NO,
|
||||
)?,
|
||||
p2pk65index_to_p2pk65addressbytes: StorableVec::forced_import(
|
||||
&path.join("p2pk65index_to_p2pk65addressbytes"),
|
||||
Version::ONE,
|
||||
Compressed::NO,
|
||||
)?,
|
||||
p2pkhindex_to_p2pkhaddressbytes: StorableVec::forced_import(
|
||||
&path.join("p2pkhindex_to_p2pkhaddressbytes"),
|
||||
Version::ONE,
|
||||
Compressed::NO,
|
||||
)?,
|
||||
p2shindex_to_p2shaddressbytes: StorableVec::forced_import(
|
||||
&path.join("p2shindex_to_p2shaddressbytes"),
|
||||
Version::ONE,
|
||||
Compressed::NO,
|
||||
)?,
|
||||
p2trindex_to_p2traddressbytes: StorableVec::forced_import(
|
||||
&path.join("p2trindex_to_p2traddressbytes"),
|
||||
Version::ONE,
|
||||
Compressed::NO,
|
||||
)?,
|
||||
p2wpkhindex_to_p2wpkhaddressbytes: StorableVec::forced_import(
|
||||
&path.join("p2wpkhindex_to_p2wpkhaddressbytes"),
|
||||
Version::ONE,
|
||||
Compressed::NO,
|
||||
)?,
|
||||
p2wshindex_to_p2wshaddressbytes: StorableVec::forced_import(
|
||||
&path.join("p2wshindex_to_p2wshaddressbytes"),
|
||||
Version::ONE,
|
||||
Compressed::NO,
|
||||
)?,
|
||||
txindex_to_first_txinindex: StorableVec::forced_import(
|
||||
&path.join("txindex_to_first_txinindex"),
|
||||
Version::ONE,
|
||||
inputindex_to_outputindex: IndexedVec::forced_import(
|
||||
&path.join("inputindex_to_outputindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_first_txoutindex: StorableVec::forced_import(
|
||||
&path.join("txindex_to_first_txoutindex"),
|
||||
Version::ONE,
|
||||
Compressed::NO,
|
||||
)?,
|
||||
txindex_to_height: StorableVec::forced_import(
|
||||
&path.join("txindex_to_height"),
|
||||
Version::ONE,
|
||||
opreturnindex_to_txindex: IndexedVec::forced_import(
|
||||
&path.join("opreturnindex_to_txindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_locktime: StorableVec::forced_import(
|
||||
&path.join("txindex_to_locktime"),
|
||||
Version::ONE,
|
||||
outputindex_to_outputtype: IndexedVec::forced_import(
|
||||
&path.join("outputindex_to_outputtype"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_txid: StorableVec::forced_import(
|
||||
&path.join("txindex_to_txid"),
|
||||
Version::ONE,
|
||||
Compressed::NO,
|
||||
outputindex_to_outputtypeindex: IndexedVec::forced_import(
|
||||
&path.join("outputindex_to_outputtypeindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_base_size: StorableVec::forced_import(
|
||||
outputindex_to_value: IndexedVec::forced_import(
|
||||
&path.join("outputindex_to_value"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2aindex_to_p2abytes: IndexedVec::forced_import(
|
||||
&path.join("p2aindex_to_p2abytes"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2msindex_to_txindex: IndexedVec::forced_import(
|
||||
&path.join("p2msindex_to_txindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2pk33index_to_p2pk33bytes: IndexedVec::forced_import(
|
||||
&path.join("p2pk33index_to_p2pk33bytes"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2pk65index_to_p2pk65bytes: IndexedVec::forced_import(
|
||||
&path.join("p2pk65index_to_p2pk65bytes"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2pkhindex_to_p2pkhbytes: IndexedVec::forced_import(
|
||||
&path.join("p2pkhindex_to_p2pkhbytes"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2shindex_to_p2shbytes: IndexedVec::forced_import(
|
||||
&path.join("p2shindex_to_p2shbytes"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2trindex_to_p2trbytes: IndexedVec::forced_import(
|
||||
&path.join("p2trindex_to_p2trbytes"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2wpkhindex_to_p2wpkhbytes: IndexedVec::forced_import(
|
||||
&path.join("p2wpkhindex_to_p2wpkhbytes"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
p2wshindex_to_p2wshbytes: IndexedVec::forced_import(
|
||||
&path.join("p2wshindex_to_p2wshbytes"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_base_size: IndexedVec::forced_import(
|
||||
&path.join("txindex_to_base_size"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_total_size: StorableVec::forced_import(
|
||||
&path.join("txindex_to_total_size"),
|
||||
Version::ONE,
|
||||
txindex_to_first_inputindex: IndexedVec::forced_import(
|
||||
&path.join("txindex_to_first_inputindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_is_explicitly_rbf: StorableVec::forced_import(
|
||||
txindex_to_first_outputindex: IndexedVec::forced_import(
|
||||
&path.join("txindex_to_first_outputindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_is_explicitly_rbf: IndexedVec::forced_import(
|
||||
&path.join("txindex_to_is_explicitly_rbf"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_txversion: StorableVec::forced_import(
|
||||
txindex_to_rawlocktime: IndexedVec::forced_import(
|
||||
&path.join("txindex_to_rawlocktime"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_total_size: IndexedVec::forced_import(
|
||||
&path.join("txindex_to_total_size"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_txid: IndexedVec::forced_import(
|
||||
&path.join("txindex_to_txid"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txindex_to_txversion: IndexedVec::forced_import(
|
||||
&path.join("txindex_to_txversion"),
|
||||
Version::ONE,
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
txinindex_to_txoutindex: StorableVec::forced_import(
|
||||
&path.join("txinindex_to_txoutindex"),
|
||||
Version::ONE,
|
||||
compressed,
|
||||
)?,
|
||||
txoutindex_to_addressindex: StorableVec::forced_import(
|
||||
&path.join("txoutindex_to_addressindex"),
|
||||
Version::ONE,
|
||||
compressed,
|
||||
)?,
|
||||
txoutindex_to_value: StorableVec::forced_import(
|
||||
&path.join("txoutindex_to_value"),
|
||||
Version::ONE,
|
||||
unknownoutputindex_to_txindex: IndexedVec::forced_import(
|
||||
&path.join("unknownoutputindex_to_txindex"),
|
||||
Version::ZERO,
|
||||
compressed,
|
||||
)?,
|
||||
})
|
||||
@@ -290,17 +297,43 @@ impl Vecs {
|
||||
pub fn rollback_if_needed(&mut self, starting_indexes: &Indexes) -> brk_vec::Result<()> {
|
||||
let saved_height = starting_indexes.height.decremented().unwrap_or_default();
|
||||
|
||||
// We don't want to override the starting indexes so we cut from n + 1
|
||||
let height = starting_indexes.height.incremented();
|
||||
let &Indexes {
|
||||
emptyoutputindex,
|
||||
height,
|
||||
inputindex,
|
||||
opreturnindex,
|
||||
outputindex,
|
||||
p2aindex,
|
||||
p2msindex,
|
||||
p2pk33index,
|
||||
p2pk65index,
|
||||
p2pkhindex,
|
||||
p2shindex,
|
||||
p2trindex,
|
||||
p2wpkhindex,
|
||||
p2wshindex,
|
||||
txindex,
|
||||
unknownoutputindex,
|
||||
} = starting_indexes;
|
||||
|
||||
self.height_to_first_addressindex
|
||||
self.emptyoutputindex_to_txindex
|
||||
.truncate_if_needed(emptyoutputindex, saved_height)?;
|
||||
self.height_to_blockhash
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_first_emptyindex
|
||||
self.height_to_difficulty
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_first_multisigindex
|
||||
self.height_to_first_emptyoutputindex
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_first_inputindex
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_first_opreturnindex
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_first_outputindex
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_first_p2aindex
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_first_p2msindex
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_first_p2pk33index
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_first_p2pk65index
|
||||
@@ -315,173 +348,144 @@ impl Vecs {
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_first_p2wshindex
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_first_pushonlyindex
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_first_txindex
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_first_txinindex
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_first_txoutindex
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_first_unknownindex
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
|
||||
// Now we can cut everything that's out of date
|
||||
let &Indexes {
|
||||
addressindex,
|
||||
height,
|
||||
p2pk33index,
|
||||
p2pk65index,
|
||||
p2pkhindex,
|
||||
p2shindex,
|
||||
p2trindex,
|
||||
p2wpkhindex,
|
||||
p2wshindex,
|
||||
txindex,
|
||||
txinindex,
|
||||
txoutindex,
|
||||
..
|
||||
} = starting_indexes;
|
||||
|
||||
self.height_to_blockhash
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_difficulty
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_size
|
||||
self.height_to_first_unknownoutputindex
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_timestamp
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_total_size
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
self.height_to_weight
|
||||
.truncate_if_needed(height, saved_height)?;
|
||||
|
||||
self.addressindex_to_addresstype
|
||||
.truncate_if_needed(addressindex, saved_height)?;
|
||||
self.addressindex_to_addresstypeindex
|
||||
.truncate_if_needed(addressindex, saved_height)?;
|
||||
self.addressindex_to_height
|
||||
.truncate_if_needed(addressindex, saved_height)?;
|
||||
|
||||
self.p2pk33index_to_p2pk33addressbytes
|
||||
self.inputindex_to_outputindex
|
||||
.truncate_if_needed(inputindex, saved_height)?;
|
||||
self.opreturnindex_to_txindex
|
||||
.truncate_if_needed(opreturnindex, saved_height)?;
|
||||
self.outputindex_to_outputtype
|
||||
.truncate_if_needed(outputindex, saved_height)?;
|
||||
self.outputindex_to_outputtypeindex
|
||||
.truncate_if_needed(outputindex, saved_height)?;
|
||||
self.outputindex_to_value
|
||||
.truncate_if_needed(outputindex, saved_height)?;
|
||||
self.p2aindex_to_p2abytes
|
||||
.truncate_if_needed(p2aindex, saved_height)?;
|
||||
self.p2msindex_to_txindex
|
||||
.truncate_if_needed(p2msindex, saved_height)?;
|
||||
self.p2pk33index_to_p2pk33bytes
|
||||
.truncate_if_needed(p2pk33index, saved_height)?;
|
||||
self.p2pk65index_to_p2pk65addressbytes
|
||||
self.p2pk65index_to_p2pk65bytes
|
||||
.truncate_if_needed(p2pk65index, saved_height)?;
|
||||
self.p2pkhindex_to_p2pkhaddressbytes
|
||||
self.p2pkhindex_to_p2pkhbytes
|
||||
.truncate_if_needed(p2pkhindex, saved_height)?;
|
||||
self.p2shindex_to_p2shaddressbytes
|
||||
self.p2shindex_to_p2shbytes
|
||||
.truncate_if_needed(p2shindex, saved_height)?;
|
||||
self.p2trindex_to_p2traddressbytes
|
||||
self.p2trindex_to_p2trbytes
|
||||
.truncate_if_needed(p2trindex, saved_height)?;
|
||||
self.p2wpkhindex_to_p2wpkhaddressbytes
|
||||
self.p2wpkhindex_to_p2wpkhbytes
|
||||
.truncate_if_needed(p2wpkhindex, saved_height)?;
|
||||
self.p2wshindex_to_p2wshaddressbytes
|
||||
self.p2wshindex_to_p2wshbytes
|
||||
.truncate_if_needed(p2wshindex, saved_height)?;
|
||||
|
||||
self.txindex_to_first_txinindex
|
||||
self.txindex_to_base_size
|
||||
.truncate_if_needed(txindex, saved_height)?;
|
||||
self.txindex_to_first_txoutindex
|
||||
self.txindex_to_first_inputindex
|
||||
.truncate_if_needed(txindex, saved_height)?;
|
||||
self.txindex_to_height
|
||||
self.txindex_to_first_outputindex
|
||||
.truncate_if_needed(txindex, saved_height)?;
|
||||
self.txindex_to_locktime
|
||||
self.txindex_to_is_explicitly_rbf
|
||||
.truncate_if_needed(txindex, saved_height)?;
|
||||
self.txindex_to_rawlocktime
|
||||
.truncate_if_needed(txindex, saved_height)?;
|
||||
self.txindex_to_total_size
|
||||
.truncate_if_needed(txindex, saved_height)?;
|
||||
self.txindex_to_txid
|
||||
.truncate_if_needed(txindex, saved_height)?;
|
||||
self.txindex_to_txversion
|
||||
.truncate_if_needed(txindex, saved_height)?;
|
||||
self.txindex_to_base_size
|
||||
.truncate_if_needed(txindex, saved_height)?;
|
||||
self.txindex_to_total_size
|
||||
.truncate_if_needed(txindex, saved_height)?;
|
||||
self.txindex_to_is_explicitly_rbf
|
||||
.truncate_if_needed(txindex, saved_height)?;
|
||||
|
||||
self.txinindex_to_txoutindex
|
||||
.truncate_if_needed(txinindex, saved_height)?;
|
||||
|
||||
self.txoutindex_to_addressindex
|
||||
.truncate_if_needed(txoutindex, saved_height)?;
|
||||
self.txoutindex_to_value
|
||||
.truncate_if_needed(txoutindex, saved_height)?;
|
||||
self.unknownoutputindex_to_txindex
|
||||
.truncate_if_needed(unknownoutputindex, saved_height)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_addressbytes(
|
||||
&self,
|
||||
addresstype: Addresstype,
|
||||
addresstypeindex: Addresstypeindex,
|
||||
) -> brk_vec::Result<Option<Addressbytes>> {
|
||||
Ok(match addresstype {
|
||||
Addresstype::P2PK65 => self
|
||||
.p2pk65index_to_p2pk65addressbytes
|
||||
.get(addresstypeindex.into())?
|
||||
// .map(|v| Addressbytes::from(v.clone())),
|
||||
.map(|v| Addressbytes::from(v.into_inner())),
|
||||
Addresstype::P2PK33 => self
|
||||
.p2pk33index_to_p2pk33addressbytes
|
||||
.get(addresstypeindex.into())?
|
||||
// .map(|v| Addressbytes::from(v.clone())),
|
||||
.map(|v| Addressbytes::from(v.into_inner())),
|
||||
Addresstype::P2PKH => self
|
||||
.p2pkhindex_to_p2pkhaddressbytes
|
||||
.get(addresstypeindex.into())?
|
||||
// .map(|v| Addressbytes::from(v.clone())),
|
||||
.map(|v| Addressbytes::from(v.into_inner())),
|
||||
Addresstype::P2SH => self
|
||||
.p2shindex_to_p2shaddressbytes
|
||||
.get(addresstypeindex.into())?
|
||||
// .map(|v| Addressbytes::from(v.clone())),
|
||||
.map(|v| Addressbytes::from(v.into_inner())),
|
||||
Addresstype::P2WPKH => self
|
||||
.p2wpkhindex_to_p2wpkhaddressbytes
|
||||
.get(addresstypeindex.into())?
|
||||
// .map(|v| Addressbytes::from(v.clone())),
|
||||
.map(|v| Addressbytes::from(v.into_inner())),
|
||||
Addresstype::P2WSH => self
|
||||
.p2wshindex_to_p2wshaddressbytes
|
||||
.get(addresstypeindex.into())?
|
||||
// .map(|v| Addressbytes::from(v.clone())),
|
||||
.map(|v| Addressbytes::from(v.into_inner())),
|
||||
Addresstype::P2TR => self
|
||||
.p2trindex_to_p2traddressbytes
|
||||
.get(addresstypeindex.into())?
|
||||
// .map(|v| Addressbytes::from(v.clone())),
|
||||
.map(|v| Addressbytes::from(v.into_inner())),
|
||||
_ => unreachable!(),
|
||||
outputtype: OutputType,
|
||||
outputtypeindex: OutputTypeIndex,
|
||||
) -> brk_vec::Result<Option<AddressBytes>> {
|
||||
Ok(match outputtype {
|
||||
OutputType::P2PK65 => self
|
||||
.p2pk65index_to_p2pk65bytes
|
||||
.get(outputtypeindex.into())?
|
||||
.map(|v| AddressBytes::from(v.into_inner())),
|
||||
OutputType::P2PK33 => self
|
||||
.p2pk33index_to_p2pk33bytes
|
||||
.get(outputtypeindex.into())?
|
||||
.map(|v| AddressBytes::from(v.into_inner())),
|
||||
OutputType::P2PKH => self
|
||||
.p2pkhindex_to_p2pkhbytes
|
||||
.get(outputtypeindex.into())?
|
||||
.map(|v| AddressBytes::from(v.into_inner())),
|
||||
OutputType::P2SH => self
|
||||
.p2shindex_to_p2shbytes
|
||||
.get(outputtypeindex.into())?
|
||||
.map(|v| AddressBytes::from(v.into_inner())),
|
||||
OutputType::P2WPKH => self
|
||||
.p2wpkhindex_to_p2wpkhbytes
|
||||
.get(outputtypeindex.into())?
|
||||
.map(|v| AddressBytes::from(v.into_inner())),
|
||||
OutputType::P2WSH => self
|
||||
.p2wshindex_to_p2wshbytes
|
||||
.get(outputtypeindex.into())?
|
||||
.map(|v| AddressBytes::from(v.into_inner())),
|
||||
OutputType::P2TR => self
|
||||
.p2trindex_to_p2trbytes
|
||||
.get(outputtypeindex.into())?
|
||||
.map(|v| AddressBytes::from(v.into_inner())),
|
||||
OutputType::P2A => self
|
||||
.p2aindex_to_p2abytes
|
||||
.get(outputtypeindex.into())?
|
||||
.map(|v| AddressBytes::from(v.into_inner())),
|
||||
OutputType::Empty | OutputType::OpReturn | OutputType::P2MS | OutputType::Unknown => {
|
||||
unreachable!()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn push_addressbytes_if_needed(
|
||||
pub fn push_bytes_if_needed(
|
||||
&mut self,
|
||||
index: Addresstypeindex,
|
||||
addressbytes: Addressbytes,
|
||||
index: OutputTypeIndex,
|
||||
bytes: AddressBytes,
|
||||
) -> brk_vec::Result<()> {
|
||||
match addressbytes {
|
||||
Addressbytes::P2PK65(bytes) => self
|
||||
.p2pk65index_to_p2pk65addressbytes
|
||||
match bytes {
|
||||
AddressBytes::P2PK65(bytes) => self
|
||||
.p2pk65index_to_p2pk65bytes
|
||||
.push_if_needed(index.into(), bytes),
|
||||
Addressbytes::P2PK33(bytes) => self
|
||||
.p2pk33index_to_p2pk33addressbytes
|
||||
AddressBytes::P2PK33(bytes) => self
|
||||
.p2pk33index_to_p2pk33bytes
|
||||
.push_if_needed(index.into(), bytes),
|
||||
Addressbytes::P2PKH(bytes) => self
|
||||
.p2pkhindex_to_p2pkhaddressbytes
|
||||
AddressBytes::P2PKH(bytes) => self
|
||||
.p2pkhindex_to_p2pkhbytes
|
||||
.push_if_needed(index.into(), bytes),
|
||||
Addressbytes::P2SH(bytes) => self
|
||||
.p2shindex_to_p2shaddressbytes
|
||||
AddressBytes::P2SH(bytes) => self
|
||||
.p2shindex_to_p2shbytes
|
||||
.push_if_needed(index.into(), bytes),
|
||||
Addressbytes::P2WPKH(bytes) => self
|
||||
.p2wpkhindex_to_p2wpkhaddressbytes
|
||||
AddressBytes::P2WPKH(bytes) => self
|
||||
.p2wpkhindex_to_p2wpkhbytes
|
||||
.push_if_needed(index.into(), bytes),
|
||||
Addressbytes::P2WSH(bytes) => self
|
||||
.p2wshindex_to_p2wshaddressbytes
|
||||
AddressBytes::P2WSH(bytes) => self
|
||||
.p2wshindex_to_p2wshbytes
|
||||
.push_if_needed(index.into(), bytes),
|
||||
Addressbytes::P2TR(bytes) => self
|
||||
.p2trindex_to_p2traddressbytes
|
||||
AddressBytes::P2TR(bytes) => self
|
||||
.p2trindex_to_p2trbytes
|
||||
.push_if_needed(index.into(), bytes),
|
||||
AddressBytes::P2A(bytes) => self
|
||||
.p2aindex_to_p2abytes
|
||||
.push_if_needed(index.into(), bytes),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flush(&mut self, height: Height) -> io::Result<()> {
|
||||
pub fn flush(&mut self, height: Height) -> Result<()> {
|
||||
self.as_mut_any_vecs()
|
||||
.into_par_iter()
|
||||
.try_for_each(|vec| vec.flush(height))
|
||||
@@ -495,22 +499,17 @@ impl Vecs {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
|
||||
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStoredVec> {
|
||||
vec![
|
||||
self.addressindex_to_addresstype.any_vec(),
|
||||
self.addressindex_to_addresstypeindex.any_vec(),
|
||||
self.addressindex_to_height.any_vec(),
|
||||
self.emptyoutputindex_to_txindex.any_vec(),
|
||||
self.height_to_blockhash.any_vec(),
|
||||
self.height_to_difficulty.any_vec(),
|
||||
self.height_to_first_addressindex.any_vec(),
|
||||
self.height_to_first_emptyindex.any_vec(),
|
||||
self.height_to_first_multisigindex.any_vec(),
|
||||
self.height_to_first_emptyoutputindex.any_vec(),
|
||||
self.height_to_first_inputindex.any_vec(),
|
||||
self.height_to_first_opreturnindex.any_vec(),
|
||||
self.height_to_first_pushonlyindex.any_vec(),
|
||||
self.height_to_first_txindex.any_vec(),
|
||||
self.height_to_first_txinindex.any_vec(),
|
||||
self.height_to_first_txoutindex.any_vec(),
|
||||
self.height_to_first_unknownindex.any_vec(),
|
||||
self.height_to_first_outputindex.any_vec(),
|
||||
self.height_to_first_p2aindex.any_vec(),
|
||||
self.height_to_first_p2msindex.any_vec(),
|
||||
self.height_to_first_p2pk33index.any_vec(),
|
||||
self.height_to_first_p2pk65index.any_vec(),
|
||||
self.height_to_first_p2pkhindex.any_vec(),
|
||||
@@ -518,47 +517,48 @@ impl Vecs {
|
||||
self.height_to_first_p2trindex.any_vec(),
|
||||
self.height_to_first_p2wpkhindex.any_vec(),
|
||||
self.height_to_first_p2wshindex.any_vec(),
|
||||
self.height_to_size.any_vec(),
|
||||
self.height_to_first_txindex.any_vec(),
|
||||
self.height_to_first_unknownoutputindex.any_vec(),
|
||||
self.height_to_timestamp.any_vec(),
|
||||
self.height_to_total_size.any_vec(),
|
||||
self.height_to_weight.any_vec(),
|
||||
self.p2pk33index_to_p2pk33addressbytes.any_vec(),
|
||||
self.p2pk65index_to_p2pk65addressbytes.any_vec(),
|
||||
self.p2pkhindex_to_p2pkhaddressbytes.any_vec(),
|
||||
self.p2shindex_to_p2shaddressbytes.any_vec(),
|
||||
self.p2trindex_to_p2traddressbytes.any_vec(),
|
||||
self.p2wpkhindex_to_p2wpkhaddressbytes.any_vec(),
|
||||
self.p2wshindex_to_p2wshaddressbytes.any_vec(),
|
||||
self.txindex_to_first_txinindex.any_vec(),
|
||||
self.txindex_to_first_txoutindex.any_vec(),
|
||||
self.txindex_to_height.any_vec(),
|
||||
self.txindex_to_locktime.any_vec(),
|
||||
self.txindex_to_txid.any_vec(),
|
||||
self.inputindex_to_outputindex.any_vec(),
|
||||
self.opreturnindex_to_txindex.any_vec(),
|
||||
self.outputindex_to_outputtype.any_vec(),
|
||||
self.outputindex_to_outputtypeindex.any_vec(),
|
||||
self.outputindex_to_value.any_vec(),
|
||||
self.p2aindex_to_p2abytes.any_vec(),
|
||||
self.p2msindex_to_txindex.any_vec(),
|
||||
self.p2pk33index_to_p2pk33bytes.any_vec(),
|
||||
self.p2pk65index_to_p2pk65bytes.any_vec(),
|
||||
self.p2pkhindex_to_p2pkhbytes.any_vec(),
|
||||
self.p2shindex_to_p2shbytes.any_vec(),
|
||||
self.p2trindex_to_p2trbytes.any_vec(),
|
||||
self.p2wpkhindex_to_p2wpkhbytes.any_vec(),
|
||||
self.p2wshindex_to_p2wshbytes.any_vec(),
|
||||
self.txindex_to_base_size.any_vec(),
|
||||
self.txindex_to_total_size.any_vec(),
|
||||
self.txindex_to_first_inputindex.any_vec(),
|
||||
self.txindex_to_first_outputindex.any_vec(),
|
||||
self.txindex_to_is_explicitly_rbf.any_vec(),
|
||||
self.txindex_to_rawlocktime.any_vec(),
|
||||
self.txindex_to_total_size.any_vec(),
|
||||
self.txindex_to_txid.any_vec(),
|
||||
self.txindex_to_txversion.any_vec(),
|
||||
self.txinindex_to_txoutindex.any_vec(),
|
||||
self.txoutindex_to_addressindex.any_vec(),
|
||||
self.txoutindex_to_value.any_vec(),
|
||||
self.unknownoutputindex_to_txindex.any_vec(),
|
||||
]
|
||||
}
|
||||
|
||||
fn as_mut_any_vecs(&mut self) -> Vec<&mut dyn AnyIndexedVec> {
|
||||
vec![
|
||||
&mut self.addressindex_to_addresstype,
|
||||
&mut self.addressindex_to_addresstypeindex,
|
||||
&mut self.addressindex_to_height,
|
||||
&mut self.emptyoutputindex_to_txindex,
|
||||
&mut self.height_to_blockhash,
|
||||
&mut self.height_to_difficulty,
|
||||
&mut self.height_to_first_addressindex,
|
||||
&mut self.height_to_first_emptyindex,
|
||||
&mut self.height_to_first_multisigindex,
|
||||
&mut self.height_to_first_emptyoutputindex,
|
||||
&mut self.height_to_first_inputindex,
|
||||
&mut self.height_to_first_opreturnindex,
|
||||
&mut self.height_to_first_pushonlyindex,
|
||||
&mut self.height_to_first_txindex,
|
||||
&mut self.height_to_first_txinindex,
|
||||
&mut self.height_to_first_txoutindex,
|
||||
&mut self.height_to_first_unknownindex,
|
||||
&mut self.height_to_first_outputindex,
|
||||
&mut self.height_to_first_p2aindex,
|
||||
&mut self.height_to_first_p2msindex,
|
||||
&mut self.height_to_first_p2pk33index,
|
||||
&mut self.height_to_first_p2pk65index,
|
||||
&mut self.height_to_first_p2pkhindex,
|
||||
@@ -566,28 +566,34 @@ impl Vecs {
|
||||
&mut self.height_to_first_p2trindex,
|
||||
&mut self.height_to_first_p2wpkhindex,
|
||||
&mut self.height_to_first_p2wshindex,
|
||||
&mut self.height_to_size,
|
||||
&mut self.height_to_first_txindex,
|
||||
&mut self.height_to_first_unknownoutputindex,
|
||||
&mut self.height_to_timestamp,
|
||||
&mut self.height_to_total_size,
|
||||
&mut self.height_to_weight,
|
||||
&mut self.p2pk33index_to_p2pk33addressbytes,
|
||||
&mut self.p2pk65index_to_p2pk65addressbytes,
|
||||
&mut self.p2pkhindex_to_p2pkhaddressbytes,
|
||||
&mut self.p2shindex_to_p2shaddressbytes,
|
||||
&mut self.p2trindex_to_p2traddressbytes,
|
||||
&mut self.p2wpkhindex_to_p2wpkhaddressbytes,
|
||||
&mut self.p2wshindex_to_p2wshaddressbytes,
|
||||
&mut self.txindex_to_first_txinindex,
|
||||
&mut self.txindex_to_first_txoutindex,
|
||||
&mut self.txindex_to_height,
|
||||
&mut self.txindex_to_locktime,
|
||||
&mut self.txindex_to_txid,
|
||||
&mut self.inputindex_to_outputindex,
|
||||
&mut self.opreturnindex_to_txindex,
|
||||
&mut self.outputindex_to_outputtype,
|
||||
&mut self.outputindex_to_outputtypeindex,
|
||||
&mut self.outputindex_to_value,
|
||||
&mut self.p2aindex_to_p2abytes,
|
||||
&mut self.p2msindex_to_txindex,
|
||||
&mut self.p2pk33index_to_p2pk33bytes,
|
||||
&mut self.p2pk65index_to_p2pk65bytes,
|
||||
&mut self.p2pkhindex_to_p2pkhbytes,
|
||||
&mut self.p2shindex_to_p2shbytes,
|
||||
&mut self.p2trindex_to_p2trbytes,
|
||||
&mut self.p2wpkhindex_to_p2wpkhbytes,
|
||||
&mut self.p2wshindex_to_p2wshbytes,
|
||||
&mut self.txindex_to_base_size,
|
||||
&mut self.txindex_to_total_size,
|
||||
&mut self.txindex_to_first_inputindex,
|
||||
&mut self.txindex_to_first_outputindex,
|
||||
&mut self.txindex_to_is_explicitly_rbf,
|
||||
&mut self.txindex_to_rawlocktime,
|
||||
&mut self.txindex_to_total_size,
|
||||
&mut self.txindex_to_txid,
|
||||
&mut self.txindex_to_txversion,
|
||||
&mut self.txinindex_to_txoutindex,
|
||||
&mut self.txoutindex_to_addressindex,
|
||||
&mut self.txoutindex_to_value,
|
||||
&mut self.unknownoutputindex_to_txindex,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<a href="https://deps.rs/crate/brk_logger">
|
||||
<img src="https://deps.rs/crate/brk_logger/latest/status.svg" alt="Dependency status">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cvrwpv3zEG">
|
||||
<a href="https://discord.gg/HaR3wpH3nr">
|
||||
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
|
||||
@@ -29,7 +29,7 @@
|
||||
<a href="https://bsky.app/profile/bitcoinresearchkit.org">
|
||||
<img src="https://img.shields.io/badge/bluesky-blue?link=https%3A%2F%2Fbsky.app%2Fprofile%2Fbitcoinresearchkit.org" alt="Bluesky" />
|
||||
</a>
|
||||
<a href="https://x.com/0xbrk">
|
||||
<a href="https://x.com/brkdotorg">
|
||||
<img src="https://img.shields.io/badge/x.com-black" alt="X" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<a href="https://deps.rs/crate/brk_parser">
|
||||
<img src="https://deps.rs/crate/brk_parser/latest/status.svg" alt="Dependency status">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cvrwpv3zEG">
|
||||
<a href="https://discord.gg/HaR3wpH3nr">
|
||||
<img src="https://img.shields.io/discord/1350431684562124850?label=discord" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
|
||||
@@ -29,7 +29,7 @@
|
||||
<a href="https://bsky.app/profile/bitcoinresearchkit.org">
|
||||
<img src="https://img.shields.io/badge/bluesky-blue?link=https%3A%2F%2Fbsky.app%2Fprofile%2Fbitcoinresearchkit.org" alt="Bluesky" />
|
||||
</a>
|
||||
<a href="https://x.com/0xbrk">
|
||||
<a href="https://x.com/brkdotorg">
|
||||
<img src="https://img.shields.io/badge/x.com-black" alt="X" />
|
||||
</a>
|
||||
</p>
|
||||
@@ -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*
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user