Compare commits

...

69 Commits

Author SHA1 Message Date
nym21 f5e5bbefb2 changelog: update 2024-12-04 11:22:28 +01:00
nym21 d4323fb5e0 website: dca sim: improve reactivity 2024-12-04 11:15:18 +01:00
nym21 8af1ddd10d website: moved more code to lc wrapper 2024-12-04 10:28:30 +01:00
nym21 62f6d9a413 website: lc: moved markers to container 2024-12-03 19:04:21 +01:00
nym21 783aed5826 website: start containing lc code in wrapper 2024-12-03 17:31:56 +01:00
k 141cd819a1 website: reorg 2024-12-02 10:03:41 +01:00
k 44fa96eb49 website: sim: wording 2024-11-28 21:52:40 +01:00
k 778b514b65 website: simulation: fix sats added 2024-11-28 18:36:22 +01:00
k afd58d69e4 website: simulation: fix 'days ago' 2024-11-28 18:34:01 +01:00
k 4af9849b2b website: simulation: small changes 2024-11-28 18:31:15 +01:00
k 4dac44e720 website: simulation: small fixes 2024-11-28 15:58:11 +01:00
k 71871901ef website: update 2024-11-27 18:36:43 +01:00
k d39e7584c0 website: update 2024-11-27 12:56:04 +01:00
k 4e9c5612ca website: small fixes 2024-11-25 11:28:28 +01:00
k c8510dd45b changelog: update 2024-11-23 16:18:57 +01:00
k c234c17352 general: snapshot 2024-11-23 16:17:06 +01:00
k cfae483d9d parser: fix gnericmap multi_insert_simple_average 2024-11-20 11:42:06 +01:00
k d01ea13de4 global: snapshot 2024-11-20 10:50:14 +01:00
k 9a73ee6952 readme: fix link 2024-11-15 13:44:14 +01:00
k 28eb9e8c17 readme: update 2024-11-15 13:41:16 +01:00
k 749c91f662 readme: removed the fluff 2024-11-15 13:15:30 +01:00
k 97ac17a12a website: delete useless logs 2024-11-11 15:23:07 +01:00
k 32fd4fa8ed website: big update 2024-11-11 15:20:31 +01:00
k 12fe4c6ba5 parser: fix metadata bug 2024-11-08 22:53:39 +01:00
k b1e9fd95ca readme: typos 2024-11-05 09:36:49 +01:00
k d83043d8f2 server: readd content disposition attachement if ext present 2024-11-04 12:44:15 +01:00
k 2abeca6220 readme: update 2024-11-04 12:35:48 +01:00
k 781810ed9c parser: databases: small changes 2024-11-04 11:09:54 +01:00
k 2142847de3 website: moved packages + added ratio charts to compare folders 2024-11-02 12:42:40 +01:00
k ca42c266ef website: update cohorts colors 2024-11-02 00:59:57 +01:00
k f258ef1011 website: readd ratio to individual cohort folders 2024-11-01 20:52:43 +01:00
k 38cb763fd3 website: add compare to liquidity 2024-11-01 20:47:23 +01:00
k 3fa78241ef parser: exit inside global defrag 2024-11-01 20:23:06 +01:00
k 3c7bc13be9 Merge branch 'main' of github.com:kibo-money/kibo 2024-11-01 20:20:54 +01:00
k 2441ca35b3 website: up signals + added compare folder to all groups 2024-11-01 20:19:43 +01:00
k 216a3977be parser: reactivate 'first_defragment' option 2024-10-31 11:39:36 +01:00
k 647a51af15 parser: fix defrag 2024-10-31 09:57:06 +01:00
k 530d4ce717 general: temp rollback 2024-10-30 19:22:42 +01:00
k e5d81b4d5c parser: added databases defragmentation 2024-10-30 19:13:41 +01:00
k 6eaeca1f3d parser: db: improve iter function 2024-10-29 19:38:52 +01:00
k 4220034eab parser: crates upgrade && remove ram from config 2024-10-29 15:22:44 +01:00
k 76a8ddd354 server: tried oxc vs swc, kept swc 2024-10-29 14:40:12 +01:00
k 0bad38a815 iterable: added custom version 2024-10-28 16:51:20 +01:00
k 48a8aad20e parser: AnyDataset DX improvements 2024-10-28 16:48:27 +01:00
k 36ad0b3014 parser: revert save logic 2024-10-27 12:10:22 +01:00
k 95fc103eaf parser: fix metadata versioning 2024-10-27 10:52:42 +01:00
k f5754780a8 global: snapshot 2024-10-26 16:41:38 +02:00
k 7114c3bdf9 general: fixes 2024-10-21 14:36:02 +02:00
k 5b9d599e83 global: snapshot 2024-10-20 18:31:43 +02:00
k ffa4871035 readme: update instances 2024-10-19 11:49:01 +02:00
k 01832ac139 server: add .json option to last value routes 2024-10-19 11:04:32 +02:00
k cb7ff2bb37 changelog: update 2024-10-19 10:46:00 +02:00
k 35dd194b28 general: snapshot 2024-10-19 10:34:12 +02:00
k 7dac857135 docker: snapshot 2024-10-17 19:53:00 +02:00
k 608ccafc70 server: add support for .json .csv and ?all=true 2024-10-16 18:38:43 +02:00
k 4cdc9ef9b3 changelog: update 2024-10-09 00:39:25 +02:00
k db60d4e453 parser: compress empty_address_data 2024-10-09 00:33:14 +02:00
k f5d427a04f parser: cargo cleanup 2024-10-08 22:37:36 +02:00
k e4893e446c cargo: update 2024-10-08 21:53:38 +02:00
k 79ffbf3d1d global: snapshot 2024-10-08 21:47:46 +02:00
k 068bb07d6e global: snapshot 2024-10-04 19:09:09 +02:00
k 1c9d118ba2 changelog: update 2024-10-03 18:37:00 +02:00
k 5308796bac parser: removed liquidity split for everything but all addresses 2024-10-03 17:38:43 +02:00
k 669205aa4d general: snapshot 2024-10-02 10:48:05 +02:00
k 9d2c2f7945 global: snapshot 2024-09-29 20:39:51 +02:00
k e3b44b0adb website: refactor 2024-09-24 17:13:29 +02:00
k 1a303a9c38 docker: init 2024-09-23 18:44:55 +02:00
k 2befa58fce global: add sell side risk ratio 2024-09-21 14:22:27 +02:00
k c8ded4ddb3 general: add /api/last route 2024-09-20 16:56:36 +02:00
309 changed files with 22743 additions and 17507 deletions
+13
View File
@@ -14,7 +14,11 @@ in
out
.log
/datasets
/datasets2
/price
*..*
/txout_*
/db
# Sync
.stfolder
@@ -44,3 +48,12 @@ benches
# Snapshots
snapshots*/
# Docker
docker/kibo
# Types
website/scripts/types/paths.d.ts
# Misc
OPENSATS.md
+55 -3
View File
@@ -5,20 +5,72 @@
![Image of the kibō Web App version 0.X.Y](./assets/v0.X.Y.jpg)
-->
## v. 0.4.1 | WIP
## v. 0.5.0 | [873199](https://mempool.space/block/0000000000000000000270925aa6a565be92e13164565a3f7994ca1966e48050) - 2024/12/04
<!-- ![Image of the kibō Web App version 0.4.1](./assets/v0.4.1.jpg) -->
![Image of the kibō Web App version 0.5.0](./assets/v0.5.0.jpg)
## Datasets
- Added `Sell Side Risk Ratio` to all entities
- Added `Open`, `High` and `Low` datasets
- Added `Satoshis Per Dollar`
- Added `All Time High`
- Added `All Time High Date`
- Added `Days Since All Time High`
- Added `Max Days Between All Time Highs`
- Added `Max Years Between All Time Highs`
- Added `Drawdown`
- Added `Adjusted Value Created`, `Adjusted Value Destroyed` and `Adjusted Spent Output Profit Ratio` to all entities
- Added `Realized Profit To Loss Ratio` to all entities
- Added `Hash Price Min`
- Added `Hash Price Rebound`
- Removed all year datasets (25) in favor for epoch datasets (5), the former was too granular to be really useful
- Removed datasets split by liquidity for all datasets **already split by any address kind**, while fun to have, they took time to compute, ram, and space to store and no one was actually checking them
- Fixed a lot of values in split by liquidity datasets
## Website
- Updated the design yet again which made the website for something more minimal and easier on the eyes
- Added a *Save In Bitcoin* (DCA) simulation page
- ~Added a dashboard~ Added the latest values to the tree next to each option instead, while less values are visible at a time, it's much more readable and organised
- Added a library of PDFs
- Fixed service worker not passing 304 (not modified) response and instead serving cached responses
- Fixed history not being properly registered
- Fixed prices on charts not having a wide enough background due to the font not being fully loaded during the creation of the chart
- Fixed window being moveable on iOS when in standalone mode when it shouldn't be
- Added `Compare` section to all groups, to compare all datasets within a group
- Updated `Solid Signals` library, which had an important breaking change on the `createEffect` function which might bring some bugs
- Fixed some datasets paths
- A lot of code reorg and file splits
- Adopted a framework like approach to load pages while still being pure JS without a build step
- Probably more that was forgotten
## Parser
- Added a `/datasets/last` json file with all the latest values
- Added `--rpcconnect` parameter to the config
- Added handling of SIGINT and SIGTERM terminal signals which menas you can now safely CTRL+C or kill the parser while it's exporting
- Added config print at the start of the program
- Compressed `empty_address_data` struct to save space (should shave of between up to 50% of the `address_index_to_empty_address_data` database)
- Doubled the number of `txid_to_tx_data` databases from 4096 to 8192
- ~Added `--recompute_computed true` argument, to allow recomputation of computed datasets in case of a bug~ Buggy for now
- Fixed not saved arguments, not being processed properly
- Fixed bug in `generic_map.multi_insert_simple_average`
- Added defragmentation option `--first-defragment true` of databases to save space (which can save up to 50%)
- Fixed bug in the computation of averages in `GenericMap`
- Added support and paramer for cookie files with `--rpccookiefile`, and auto find if the path is `--datadir/.cookie`
- Increased number of retries and time between them when fetching price from exchanges APIs
## Server
- Fixed links in several places missing the `/api` part and thus not working
- Fixed broken last values routes
- Added support for the `/datasets/last` file via the `/api/last` route
- Added support for `.json` (won't change anything) and `.csv` (will download a csv file) extension at the end of datasets routes
- Added `all=true` query parameter to dataset routes to get to full history
## Biter
- Moved back to this repo
## v. 0.4.0 | [861950](https://mempool.space/block/00000000000000000000530d0e30ccf7deeace122dcc99f2668a06c6dad83629) - 2024/09/19
+69 -91
View File
@@ -1,64 +1,61 @@
<p align="center">
<a href="https://kibo.money" target="_blank">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/kibo-money/kibo/main/assets/logo-full-dark.svg">
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/kibo-money/kibo/main/assets/logo-full-light.svg">
<img alt="kibō" src="https://raw.githubusercontent.com/kibo-money/kibo/main/assets/logo-full-light.svg" width="300" height="auto" style="max-width: 100%;">
</picture>
</a>
</p>
<p align="center">
<span>Bitcoin is our only <b><i>hope</i></b> for a better future.</span>
</p>
<a href="https://kibo.money" target="_blank">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/kibo-money/kibo/main/assets/logo-long-text-dark.svg">
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/kibo-money/kibo/main/assets/logo-long-text-light.svg">
<img alt="kibō" src="https://raw.githubusercontent.com/kibo-money/kibo/main/assets/logo-long-text-light.svg" width="210" height="auto">
</picture>
</a>
## Description
**kibō** (*hope* in japanese, formerly Satonomics) is a suite of tools that aims to help you understand Bitcoin's various dynamics. To do that, there is a wide number of charts and datasets with a scale by date but also by height free for you to explore. Which allows you to verify an incredible number of things, from the number of UTXOs to the repartition of the supply between different groups over time, with many things in between and it's all made possible thanks to Bitcoin's transparency. Whether you're an enthusiast, a researcher, a miner, an analyst, a trader, a skeptic or just curious, there is something new to learn for everyone !
[**kibō**](https://kibo.money) (_hope_ in japanese) is primarily an open source Bitcoin Core data extractor and visualizer (similar to [Glassnode](https://glassnode.com)) which goal is to empower anybody with data about Bitcoin for free.
While it's not the first tool trying to solve this problem, it's the first that is completely free, open-source and self-hostable. Which is very important as, just like for Bitcoin itself, I strongly believe that everyone should have access to this kind of data.
The project is split in 3 parts:
If you are a user of [mempool.space](https://mempool.space), you'll find this to be very complimentary, as it's a global and macro view of the chain over time instead.
- First you have the extractor (parser), which parses the block data files from your Bitcoin Core node and computes a very wide range of datasets which are stored in compressed binary files
> For the curious, it takes at the very least 24 hours to parse all the blocks and compute all datasets. After that it will wait for a new block and take between 1 and 3 minutes to be up to date
- Then there is the website on which you can view, among other things, all datasets in various charts
- Finally there is the server which serves the website and the generated data via an [API](https://github.com/kibo-money/kibo/tree/main#endpoints)
If we want the world to move towards and, in the end, to be on a Bitcoin standard, we must have tools like this at our disposal.
Whether you're an enthusiast, a researcher, a miner, an analyst, a trader, a skeptic or just curious, there is something for everyone !
## Donations
This project was created out of frustration by all the alternatives that were either very expensive and thus discriminatory and against bitcoin values or just very limited and none were open-source and verifiable. So while it's not the first tool trying to solve these problems, it's the first that is completely free, open-source and self-hostable.
This project was started as an answer to the outrageous pricing from Glassnode (and their third tier starting at $833.33/month !).
But it is a lot of work and has been worked on **full-time since November of 2023** and has also been operational since then without any ads.
**At the time of writing (2024-09-12), this project has made around 2,200,000 sats, which is around $1300 or $120/month. While I'm very grateful for all donations, it's sadly unsustainable.**
So if you find this project useful, [please send some sats](https://geyser.fund/project/kibo/), it would be really appreciated.
If you're a potential sponsor, feel free to contact me in Nostr !
[Geyser Fund](https://geyser.fund/project/kibo/)
## Warning
This project is still in an early stage. Until more people look at the code and check the various computations in it, the datasets might be, in the worst case, completely false.
If you are a user of [mempool.space](https://mempool.space), you'll find this to be very complimentary, as it offers a macro view of the chain over time instead of a detailed one.
## Instances
- [kibo.money](https://kibo.money)
- [backup.kibo.money](https://backup.kibo.money)
| URL | Type | Version | Status | Last Height | Up Time Ratio |
| ------------------------------------------------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| [kibo.money](https://kibo.money) | Main | ![Version](https://img.shields.io/badge/dynamic/toml?url=https%3A%2F%2Fkibo.money%2FCargo.toml&query=%24.package.version&style=for-the-badge&label=%20&color=%23db9e03) | ![Status](https://img.shields.io/uptimerobot/status/m797259009-043f6b92d4cc2deef7d13f50?style=for-the-badge&label=%20&up_color=%231cb454&down_color=%23e63636) | ![Height](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fkibo.money%2Fapi%2Flast-height.json&query=%24.value&style=for-the-badge&label=%20&color=%23f26610) | ![Ratio](https://img.shields.io/uptimerobot/ratio/m797259009-043f6b92d4cc2deef7d13f50?style=for-the-badge&label=%20&color=%232f73f1) |
| [backup.kibo.money](https://backup.kibo.money) | Backup | ![Version](https://img.shields.io/badge/dynamic/toml?url=https%3A%2F%2Fbackup.kibo.money%2FCargo.toml&query=%24.package.version&style=for-the-badge&label=%20&color=%23db9e03) | ![Status](https://img.shields.io/uptimerobot/status/m797259013-bb29a8264fab8786fb80c5ed?style=for-the-badge&label=%20&up_color=%231cb454&down_color=%23e63636) | ![Height](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fbackup.kibo.money%2Fapi%2Flast-height.json&query=%24.value&style=for-the-badge&label=%20&color=%23f26610) | ![Ratio](https://img.shields.io/uptimerobot/ratio/m797259013-bb29a8264fab8786fb80c5ed?style=for-the-badge&label=%20&color=%232f73f1) |
| [preview.kibo.money](https://preview.kibo.money) | Dev | ![Version](https://img.shields.io/badge/dynamic/toml?url=https%3A%2F%2Fpreview.kibo.money%2FCargo.toml&query=%24.package.version&style=for-the-badge&label=%20&color=%23db9e03) | ![Status](https://img.shields.io/uptimerobot/status/m797869753-d40fc161bcb34624857a8082?style=for-the-badge&label=%20&up_color=%231cb454&down_color=%23e63636) | ![Height](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fpreview.kibo.money%2Fapi%2Flast-height.json&query=%24.value&style=for-the-badge&label=%20&color=%23f26610) | ![Ratio](https://img.shields.io/uptimerobot/ratio/m797869753-d40fc161bcb34624857a8082?style=for-the-badge&label=%20&color=%232f73f1) |
## Structure
Please open an issue if you want to add another instance
- `parser`: The backbone of the project, it does most of the work by parsing and then computing datasets from the timechain
- `website`: A web app which displays the generated datasets in various charts
- `server`: A small server which will serve both the website and the computed datasets via an API
## Endpoints
> If you running locally, you can replace `https://kibo.money` by `http://localhost:3110`
- [/](https://kibo.money/): Website
- [/api](https://kibo.money/api): A JSON with all available datasets, with their respective id and endpoint, better viewed in a Firefox based browser
- /api/TIMESCALE-to-ID: `TIMESCALE` can be `date` or `height`, and `ID` is the id with `_` replaced by `-`, let's take `date-to-close` (price at the end of each day) as an example
- [/api/date-to-close](https://kibo.money/api/date-to-close): current year's values in a json format
- [/api/date-to-close?chunk=2009](https://kibo.money/api/date-to-close?chunk=2009): values from the year 2009 in a json format
- [/api/date-to-close?all=true](https://kibo.money/api/date-to-close?all=true): all values in a json format
- You can also specify the extension to download a file, either `.json` or `.csv` to get the dataset in a CSV format; like so:
- [/api/date-to-close.csv](https://kibo.money/api/date-to-close.csv)
- [/api/date-to-close.csv?chunk=2009](https://kibo.money/api/date-to-close.csv?chunk=2009)
- [/api/date-to-close.csv?all=true](https://kibo.money/api/date-to-close.csv?all=true)
## Roadmap
- **More Datasets/Charts**
- **Simulations**
- **Dashboards**
- **Nostr integration**
- **API Documentation**
- **Descriptions**
- **Docker support**
- **Start9 support**
## Setup
@@ -66,16 +63,18 @@ This project is still in an early stage. Until more people look at the code and
### Requirements
- At least 16 GB of RAM
- 1 TB of free space (will use 60-80% of that)
- A running instance of bitcoin-core with txindex=1 and rpc credentials
- 1 TB of free space (will use 70% of that without defragmentation and 40% after)
- A running instance of bitcoin-core with:
- `-txindex=1`
- `-blocksxor=0`
- RPC credentials
- Example: `bitcoind -datadir="$HOME/.bitcoin" -blocksonly -txindex=1 -blocksxor=0`
- Git
### Docker
Coming soon
### Manual
_Mac OS and Linux only, Windows is unsupported_
First we need to install Rust (https://www.rust-lang.org/tools/install)
```bash
@@ -88,6 +87,12 @@ If you already had Rust installed you could update it just in case
rustup update
```
> If you're on Ubuntu you'll probably also need to install `open-ssl` with
>
> ```bash
> sudo apt install libssl-dev pkg-config
> ```
Optionally, you can also install `cargo-watch` for the server to automatically restart it on file change, which will be triggered by new code and new datasets from the parser (https://github.com/watchexec/cargo-watch?tab=readme-ov-file#install)
```bash
@@ -115,19 +120,26 @@ cd ???/kibo/parser
Now we can finally start by running the parser, you need to use the `./run.sh` script instead of `cargo run -r` as we need to set various system variables for the program to run smoothly
For the first launch, the parser will need several information such as:
- `--datadir`: which is bitcoin data directory path
- `--rpcuser`: the username of the RPC credentials to talk to the bitcoin server
- `--rpcpassword`: the password of the RPC credentials
- `--datadir`: which is bitcoin data directory path, prefer `$HOME` to `~` as the latter might not work
Optionally you can also specify:
- `--rpccookiefile`: the path to the cookie file if not default
- `--rpcuser`: the username of the RPC credentials to talk to the bitcoin server if set
- `--rpcpassword`: the password of the RPC credentials if set
- `--rpcconnect`: if the bitcoin core server's IP is different than `localhost`
- `--rpcport`: if the port is different than `8332`
Everything will be saved in a `config.toml` file, which will allow you to simply run `./run.sh` next time
Here's an example
```bash
./run.sh --datadir=$HOME/Developer/bitcoin --rpcuser=satoshi --rpcpassword=nakamoto
./run.sh --datadir=$HOME/Developer/bitcoin
```
In a new terminal, go to the `server`'s folder of the repository
In a **new** terminal, go to the `server`'s folder of the repository
```bash
cd ???/kibo/server
@@ -141,48 +153,14 @@ And start it also with the `run.sh` script instead of `cargo run -r`
Then the easiest to let others access your server is to use `cloudflared` which will also cache requests. For more information go to: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/
## Brand
## Donate
### Name
<img width="159" alt="image" src="https://github.com/user-attachments/assets/8bbb759f-4874-46cb-b093-b30cb30f5828">
kibō means _**hope**_ in japanese which is what Bitcoin ultimately is for many, hope for a better future.
[bc1q950q4ukpxxm6wjjkv6cpq8jzpazaxrrwftctkt](bitcoin:bc1q950q4ukpxxm6wjjkv6cpq8jzpazaxrrwftctkt)
### Logo
<img width="159" alt="image" src="https://github.com/user-attachments/assets/745e39c7-be26-4f2a-90f2-54786e62ba35">
The dove (borrowed from [svgrepo](https://www.svgrepo.com/svg/351969/dove) for now) is known to represent hope in many cultures.
[lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkxmmww3jkuar8d35kgetj8yuq363hv4](lightning:lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkxmmww3jkuar8d35kgetj8yuq363hv4)
The orange background is a wink to Bitcoin and when in a circle, it also represents the sun, which means that while it's our hope for a better future, we still have to be careful with our collective goals and actions, to not end up like Icarus.
## Infrastructure
Here's the current infrastructure of the main instance and its backup.
It uses 2 servers, a full and a light one without the parser running but with still datasets syncronized via Syncthing.
Cloudflare is used for their tunnel + CDN services.
Though it's recommended to change to default **Browser Cache TTL** configuration from `4 Hours` to `Respect Existing Headers` (in `Websites / YOUR_DOMAIN / Caching / Configuration / Browser Cache TTL`) and activate `Always use https`.
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/kibo-money/kibo/main/assets/infrastructure-dark.svg">
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/kibo-money/kibo/main/assets/infrastructure-light.svg">
<img alt="kibō" src="https://raw.githubusercontent.com/kibo-money/kibo/main/assets/infrastructure-light.svg" width="768" height="auto" style="max-width: 100%;">
</picture>
</p>
## Iterations
A list of all the previous versions and ideas:
- https://github.com/drgarlic/satonomics
- https://github.com/drgarlic/satonomics-parser
- https://github.com/drgarlic/satonomics-explorer
- https://github.com/drgarlic/satonomics-server
- https://github.com/drgarlic/satonomics-app
- https://github.com/drgarlic/bitalisys
- https://github.com/drgarlic/bitesque-app
- https://github.com/drgarlic/bitesque-back
- https://github.com/drgarlic/bitesque-front
- https://github.com/drgarlic/bitesque-assets
- https://github.com/drgarlic/syf
[Geyser Fund](https://geyser.fund/project/kibo/)
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 32 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 32 KiB

File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -2,7 +2,7 @@
<svg viewBox="0 0 500 180" xmlns="http://www.w3.org/2000/svg">
<defs/>
<g transform="matrix(1, 0, 0, 1, -252.158997, 0)">
<path d="M 278.049 146.789 L 278.049 127.527 L 287.141 117.972 L 304.4 146.789 L 331.83 146.789 L 303.784 100.251 L 332.755 69.739 L 303.013 69.739 L 278.049 97.477 L 278.049 30.598 L 254.318 30.598 L 254.318 146.789 L 278.049 146.789 Z M 354.169 57.719 C 361.565 57.719 367.575 51.709 367.575 44.158 C 367.575 36.608 361.565 30.752 354.169 30.752 C 346.618 30.752 340.608 36.608 340.608 44.158 C 340.608 51.709 346.618 57.719 354.169 57.719 Z M 342.457 146.789 L 366.188 146.789 L 366.188 69.739 L 342.457 69.739 L 342.457 146.789 Z M 406.407 146.789 L 407.64 136.927 C 411.801 144.015 421.047 148.792 431.834 148.792 C 453.716 148.792 468.972 132.92 468.972 109.035 C 468.972 83.916 455.257 67.119 433.683 67.119 C 422.588 67.119 412.417 71.742 407.794 78.677 L 407.794 30.598 L 384.063 30.598 L 384.063 146.789 L 406.407 146.789 Z M 407.948 107.802 C 407.948 96.244 415.653 88.539 426.749 88.539 C 437.998 88.539 445.087 96.398 445.087 107.802 C 445.087 119.205 437.998 127.064 426.749 127.064 C 415.653 127.064 407.948 119.359 407.948 107.802 Z M 498.713 56.332 L 543.402 56.332 L 543.402 40.306 L 498.713 40.306 L 498.713 56.332 Z M 478.526 108.11 C 478.526 132.458 496.402 148.638 521.058 148.638 C 545.56 148.638 563.435 132.458 563.435 108.11 C 563.435 83.762 545.56 67.428 521.058 67.428 C 496.402 67.428 478.526 83.762 478.526 108.11 Z M 502.412 107.956 C 502.412 96.398 509.963 88.693 521.058 88.693 C 531.999 88.693 539.55 96.398 539.55 107.956 C 539.55 119.667 531.999 127.372 521.058 127.372 C 509.963 127.372 502.412 119.667 502.412 107.956 Z" style="fill: rgb(16, 16, 14);"/>
<path d="M 589.19 97.802 L 589.19 106.23 L 610.948 106.23 C 605.1 112.938 597.446 119.044 587.986 124.376 L 593.404 131.514 C 597.532 128.934 601.488 126.268 605.186 123.43 L 605.186 146.048 L 614.13 146.048 L 614.13 123.43 L 626.944 123.43 L 626.944 149.402 L 635.974 149.402 L 635.974 123.43 L 649.82 123.43 L 649.82 134.008 C 649.82 136.072 649.046 137.104 647.498 137.104 L 640.36 136.674 L 642.768 145.188 L 650.422 145.188 C 655.926 145.188 658.678 142.092 658.678 135.986 L 658.678 115.174 L 635.974 115.174 L 635.974 108.638 L 626.944 108.638 L 626.944 115.174 L 614.388 115.174 C 617.054 112.336 619.548 109.326 621.784 106.23 L 665.128 106.23 L 665.128 97.802 L 626.858 97.802 C 627.89 95.824 628.836 93.76 629.696 91.61 L 620.838 90.492 C 619.806 92.9 618.516 95.394 617.14 97.802 L 589.19 97.802 Z M 648.1 68.734 C 642.338 72.088 636.232 75.098 629.868 77.678 C 621.612 75.012 612.926 72.518 603.896 70.282 L 599.252 77.248 C 605.272 78.624 611.206 80.258 617.226 82.15 C 610.088 84.386 602.606 86.106 594.78 87.482 L 599.596 95.308 C 612.324 92.04 622.472 89.116 630.04 86.364 C 638.124 89.116 646.122 92.298 654.034 95.824 L 658.936 88.428 C 653.26 86.02 647.412 83.698 641.392 81.548 C 646.208 79.226 651.11 76.56 655.926 73.55 L 648.1 68.734 Z M 675.438 77.85 L 675.438 85.848 L 682.404 85.848 L 682.404 98.92 C 682.404 101.5 681.114 103.22 678.62 104.166 L 680.684 110.874 C 692.036 108.896 701.926 106.66 710.182 104.08 L 708.634 96.426 C 703.474 98.146 697.454 99.608 690.574 100.984 L 690.574 85.848 L 712.332 85.848 L 712.332 77.85 L 698.916 77.85 C 698.4 74.668 697.884 71.744 697.368 69.164 L 688.338 70.712 C 688.94 72.862 689.542 75.27 690.144 77.85 L 675.438 77.85 Z M 724.028 89.632 L 739.25 89.632 L 739.25 93.502 L 723.856 93.502 C 723.942 92.47 724.028 91.352 724.028 90.32 L 724.028 89.632 Z M 739.25 83.096 L 724.028 83.096 L 724.028 79.226 L 739.25 79.226 L 739.25 83.096 Z M 722.652 100.038 L 739.25 100.038 L 739.25 100.898 C 739.25 103.048 738.218 104.166 736.24 104.166 C 733.918 104.166 731.424 103.994 728.758 103.822 L 730.822 111.562 L 738.734 111.562 C 744.582 111.562 747.506 108.982 747.506 103.908 L 747.506 72.002 L 715.6 72.002 L 715.6 90.922 C 715.428 97.286 713.192 102.532 708.892 106.746 L 715.342 112.594 C 718.782 109.068 721.276 104.854 722.652 100.038 Z M 708.462 121.452 L 708.462 126.784 L 683.608 126.784 L 683.608 134.352 L 708.462 134.352 L 708.462 139.598 L 675.524 139.598 L 675.524 147.51 L 750 147.51 L 750 139.598 L 717.062 139.598 L 717.062 134.352 L 742.174 134.352 L 742.174 126.784 L 717.062 126.784 L 717.062 121.452 L 746.216 121.452 L 746.216 113.712 L 679.308 113.712 L 679.308 121.452 L 708.462 121.452 Z" style="fill: rgb(192, 192, 171);"/>
<path d="M 278.049 146.789 L 278.049 127.527 L 287.141 117.972 L 304.4 146.789 L 331.83 146.789 L 303.784 100.251 L 332.755 69.739 L 303.013 69.739 L 278.049 97.477 L 278.049 30.598 L 254.318 30.598 L 254.318 146.789 L 278.049 146.789 Z M 354.169 57.719 C 361.565 57.719 367.575 51.709 367.575 44.158 C 367.575 36.608 361.565 30.752 354.169 30.752 C 346.618 30.752 340.608 36.608 340.608 44.158 C 340.608 51.709 346.618 57.719 354.169 57.719 Z M 342.457 146.789 L 366.188 146.789 L 366.188 69.739 L 342.457 69.739 L 342.457 146.789 Z M 406.407 146.789 L 407.64 136.927 C 411.801 144.015 421.047 148.792 431.834 148.792 C 453.716 148.792 468.972 132.92 468.972 109.035 C 468.972 83.916 455.257 67.119 433.683 67.119 C 422.588 67.119 412.417 71.742 407.794 78.677 L 407.794 30.598 L 384.063 30.598 L 384.063 146.789 L 406.407 146.789 Z M 407.948 107.802 C 407.948 96.244 415.653 88.539 426.749 88.539 C 437.998 88.539 445.087 96.398 445.087 107.802 C 445.087 119.205 437.998 127.064 426.749 127.064 C 415.653 127.064 407.948 119.359 407.948 107.802 Z M 498.713 56.332 L 543.402 56.332 L 543.402 40.306 L 498.713 40.306 L 498.713 56.332 Z M 478.526 108.11 C 478.526 132.458 496.402 148.638 521.058 148.638 C 545.56 148.638 563.435 132.458 563.435 108.11 C 563.435 83.762 545.56 67.428 521.058 67.428 C 496.402 67.428 478.526 83.762 478.526 108.11 Z M 502.412 107.956 C 502.412 96.398 509.963 88.693 521.058 88.693 C 531.999 88.693 539.55 96.398 539.55 107.956 C 539.55 119.667 531.999 127.372 521.058 127.372 C 509.963 127.372 502.412 119.667 502.412 107.956 Z" style="fill: #fffaf6;"/>
<path d="M 589.19 97.802 L 589.19 106.23 L 610.948 106.23 C 605.1 112.938 597.446 119.044 587.986 124.376 L 593.404 131.514 C 597.532 128.934 601.488 126.268 605.186 123.43 L 605.186 146.048 L 614.13 146.048 L 614.13 123.43 L 626.944 123.43 L 626.944 149.402 L 635.974 149.402 L 635.974 123.43 L 649.82 123.43 L 649.82 134.008 C 649.82 136.072 649.046 137.104 647.498 137.104 L 640.36 136.674 L 642.768 145.188 L 650.422 145.188 C 655.926 145.188 658.678 142.092 658.678 135.986 L 658.678 115.174 L 635.974 115.174 L 635.974 108.638 L 626.944 108.638 L 626.944 115.174 L 614.388 115.174 C 617.054 112.336 619.548 109.326 621.784 106.23 L 665.128 106.23 L 665.128 97.802 L 626.858 97.802 C 627.89 95.824 628.836 93.76 629.696 91.61 L 620.838 90.492 C 619.806 92.9 618.516 95.394 617.14 97.802 L 589.19 97.802 Z M 648.1 68.734 C 642.338 72.088 636.232 75.098 629.868 77.678 C 621.612 75.012 612.926 72.518 603.896 70.282 L 599.252 77.248 C 605.272 78.624 611.206 80.258 617.226 82.15 C 610.088 84.386 602.606 86.106 594.78 87.482 L 599.596 95.308 C 612.324 92.04 622.472 89.116 630.04 86.364 C 638.124 89.116 646.122 92.298 654.034 95.824 L 658.936 88.428 C 653.26 86.02 647.412 83.698 641.392 81.548 C 646.208 79.226 651.11 76.56 655.926 73.55 L 648.1 68.734 Z M 675.438 77.85 L 675.438 85.848 L 682.404 85.848 L 682.404 98.92 C 682.404 101.5 681.114 103.22 678.62 104.166 L 680.684 110.874 C 692.036 108.896 701.926 106.66 710.182 104.08 L 708.634 96.426 C 703.474 98.146 697.454 99.608 690.574 100.984 L 690.574 85.848 L 712.332 85.848 L 712.332 77.85 L 698.916 77.85 C 698.4 74.668 697.884 71.744 697.368 69.164 L 688.338 70.712 C 688.94 72.862 689.542 75.27 690.144 77.85 L 675.438 77.85 Z M 724.028 89.632 L 739.25 89.632 L 739.25 93.502 L 723.856 93.502 C 723.942 92.47 724.028 91.352 724.028 90.32 L 724.028 89.632 Z M 739.25 83.096 L 724.028 83.096 L 724.028 79.226 L 739.25 79.226 L 739.25 83.096 Z M 722.652 100.038 L 739.25 100.038 L 739.25 100.898 C 739.25 103.048 738.218 104.166 736.24 104.166 C 733.918 104.166 731.424 103.994 728.758 103.822 L 730.822 111.562 L 738.734 111.562 C 744.582 111.562 747.506 108.982 747.506 103.908 L 747.506 72.002 L 715.6 72.002 L 715.6 90.922 C 715.428 97.286 713.192 102.532 708.892 106.746 L 715.342 112.594 C 718.782 109.068 721.276 104.854 722.652 100.038 Z M 708.462 121.452 L 708.462 126.784 L 683.608 126.784 L 683.608 134.352 L 708.462 134.352 L 708.462 139.598 L 675.524 139.598 L 675.524 147.51 L 750 147.51 L 750 139.598 L 717.062 139.598 L 717.062 134.352 L 742.174 134.352 L 742.174 126.784 L 717.062 126.784 L 717.062 121.452 L 746.216 121.452 L 746.216 113.712 L 679.308 113.712 L 679.308 121.452 L 708.462 121.452 Z" style="fill: #867e7b;"/>
</g>
</svg>
</svg>

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.8 MiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.8 MiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 386 KiB

+466
View File
@@ -0,0 +1,466 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "arrayvec"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
[[package]]
name = "base58ck"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f"
dependencies = [
"bitcoin-internals",
"bitcoin_hashes",
]
[[package]]
name = "base64"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "bech32"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d"
[[package]]
name = "bitcoin"
version = "0.32.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea507acc1cd80fc084ace38544bbcf7ced7c2aa65b653b102de0ce718df668f6"
dependencies = [
"base58ck",
"bech32",
"bitcoin-internals",
"bitcoin-io",
"bitcoin-units",
"bitcoin_hashes",
"hex-conservative",
"hex_lit",
"secp256k1",
"serde",
]
[[package]]
name = "bitcoin-internals"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2"
dependencies = [
"serde",
]
[[package]]
name = "bitcoin-io"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56"
[[package]]
name = "bitcoin-units"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2"
dependencies = [
"bitcoin-internals",
"serde",
]
[[package]]
name = "bitcoin_hashes"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16"
dependencies = [
"bitcoin-io",
"hex-conservative",
"serde",
]
[[package]]
name = "bitcoincore-rpc"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aedd23ae0fd321affb4bbbc36126c6f49a32818dc6b979395d24da8c9d4e80ee"
dependencies = [
"bitcoincore-rpc-json",
"jsonrpc",
"log",
"serde",
"serde_json",
]
[[package]]
name = "bitcoincore-rpc-json"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8909583c5fab98508e80ef73e5592a651c954993dc6b7739963257d19f0e71a"
dependencies = [
"bitcoin",
"serde",
"serde_json",
]
[[package]]
name = "biter"
version = "0.1.1"
dependencies = [
"bitcoin",
"bitcoincore-rpc",
"crossbeam",
"derived-deref",
"rayon",
"serde",
"serde_json",
]
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cc"
version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crossbeam"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-epoch",
"crossbeam-queue",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-queue"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
[[package]]
name = "derived-deref"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "805ef2023ccd65425743a91ecd11fc020979a0b01921db3104fb606d18a7b43e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hex-conservative"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd"
dependencies = [
"arrayvec",
]
[[package]]
name = "hex_lit"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd"
[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "jsonrpc"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3662a38d341d77efecb73caf01420cfa5aa63c0253fd7bc05289ef9f6616e1bf"
dependencies = [
"base64",
"minreq",
"serde",
"serde_json",
]
[[package]]
name = "libc"
version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "log"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "minreq"
version = "2.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "763d142cdff44aaadd9268bebddb156ef6c65a0e13486bb81673cf2d8739f9b0"
dependencies = [
"log",
"serde",
"serde_json",
]
[[package]]
name = "ppv-lite86"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dee4364d9f3b902ef14fab8a1ddffb783a1cb6b4bba3bfc1fa3922732c7de97f"
dependencies = [
"zerocopy",
]
[[package]]
name = "proc-macro2"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "rayon"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
]
[[package]]
name = "ryu"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "secp256k1"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3"
dependencies = [
"bitcoin_hashes",
"rand",
"secp256k1-sys",
"serde",
]
[[package]]
name = "secp256k1-sys"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b"
dependencies = [
"cc",
]
[[package]]
name = "serde"
version = "1.0.204"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.204"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]]
name = "syn"
version = "2.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "zerocopy"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "854e949ac82d619ee9a14c66a1b674ac730422372ccb759ce0c39cabcf2bf8e6"
dependencies = [
"byteorder",
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "125139de3f6b9d625c39e2efdd73d41bdac468ccd556556440e322be0e1bbd91"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
+19
View File
@@ -0,0 +1,19 @@
[package]
name = "biter"
description = "A very fast Bitcoin block iterator"
version = "0.1.1"
license = "MIT"
repository = "https://github.com/kibo-money/kibo/tree/main/biter"
keywords = ["bitcoin", "block", "iterator"]
categories = ["cryptography::cryptocurrencies", "encoding"]
edition = "2021"
[dependencies]
bitcoin = { version = "0.32.2", features = ["serde"] }
rayon = "1.10.0"
crossbeam = { version = "0.8.4", features = ["crossbeam-channel"] }
serde = { version = "1.0.204", features = ["derive"] }
serde_json = "1.0.122"
derived-deref = "2.1.0"
bitcoincore-rpc = "0.19.0"
# tokio = { version = "1.39.2", features = ["rt-multi-thread"] }
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Biter
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+62
View File
@@ -0,0 +1,62 @@
# Biter
Biter (Bitcoin Block Iterator) is a very fast and simple Rust library which reads raw block files (*blkXXXXX.dat*) from Bitcoin Core Node and creates an iterator over all the requested blocks in sequential order (0, 1, 2, ...).
The element returned by the iterator is a tuple which includes the:
- Height: `usize`
- Block: `Block` (from `bitcoin-rust`)
- Block's Hash: `BlockHash` (also from `bitcoin-rust`)
## Example
```rust
use bitcoincore_rpc::{Auth, Client};
fn main() {
let i = std::time::Instant::now();
// Path to the Bitcoin data directory
let data_dir = "../../bitcoin";
// Path to the export directory where a mini blk indexer will be exported
let export_dir = "./target";
// Inclusive starting height of the blocks received, `None` for 0
let start = Some(850_000);
// Inclusive ending height of the blocks received, `None` for the last one
let end = None;
// RPC client to filter out forks
let url = "http://localhost:8332";
let auth = Auth::UserPass("satoshi".to_string(), "nakamoto".to_string());
let rpc = Client::new(url, auth).unwrap();
// Create channel receiver then iterate over the blocks
biter::new(data_dir, export_dir, start, end, rpc)
.iter()
.for_each(|(height, _block, hash)| {
println!("{height}: {hash}");
});
dbg!(i.elapsed());
}
```
## Requirements
Even though it reads *blkXXXXX.dat* files, it **needs** `bitcoind` to run with the RPC server to filter out block forks.
Peak memory should be around 500MB.
## Comparaison
| | [biter](https://crates.io/crates/biter) | [bitcoin-explorer](https://crates.io/crates/bitcoin-explorer) | [blocks_iterator](https://crates.io/crates/blocks_iterator) |
| --- | --- | --- | --- |
| Run **with** `bitcoind` | Yes ✅ | No ❌ | Yes ✅ |
| Run **without** `bitcoind` | No ❌ | Yes ✅ | Yes ✅ |
| `0..=855_000` | 16mn40s | 17mn 46s | > 2h |
| `800_000..=855_000` | 2mn 53s (16mn40s if first run) | 3mn 2s | > 2h |
*Benchmarked on a Macbook Pro M3 Pro*
+105
View File
@@ -0,0 +1,105 @@
use std::{
cmp::Ordering,
collections::BTreeMap,
fs::{self, File},
io::{BufReader, BufWriter},
path::PathBuf,
};
use derived_deref::{Deref, DerefMut};
use crate::{blk_recap::BlkRecap, BlkMetadataAndBlock};
#[derive(Deref, DerefMut, Debug)]
pub struct BlkIndexToBlkRecap {
path: String,
#[target]
tree: BTreeMap<usize, BlkRecap>,
}
impl BlkIndexToBlkRecap {
pub fn import(blocks_dir: &BTreeMap<usize, PathBuf>, export_dir: &str) -> Self {
let path = format!("{export_dir}/blk_index_to_blk_recap.json");
let tree = {
fs::create_dir_all(export_dir).unwrap();
if let Ok(file) = File::open(&path) {
let reader = BufReader::new(file);
serde_json::from_reader(reader).unwrap_or_default()
} else {
BTreeMap::default()
}
};
let mut this = Self { path, tree };
this.clean_outdated(blocks_dir);
this
}
pub fn clean_outdated(&mut self, blocks_dir: &BTreeMap<usize, PathBuf>) {
blocks_dir.iter().for_each(|(blk_index, blk_path)| {
if let Some(blk_recap) = self.get(blk_index) {
if blk_recap.has_different_modified_time(blk_path) {
self.remove(blk_index);
}
}
});
}
pub fn get_start_recap(&self, start: Option<usize>) -> Option<(usize, BlkRecap)> {
if let Some(start) = start {
let (last_key, last_value) = self.last_key_value()?;
if last_value.height() < start {
return Some((*last_key, *last_value));
} else if let Some((blk_index, _)) = self
.iter()
.find(|(_, blk_recap)| blk_recap.is_younger_than(start))
{
if *blk_index != 0 {
let blk_index = *blk_index - 1;
return Some((blk_index, *self.get(&blk_index).unwrap()));
}
}
}
None
}
pub fn update(&mut self, blk_metadata_and_block: &BlkMetadataAndBlock, height: usize) {
let blk_index = blk_metadata_and_block.blk_metadata.index;
if let Some(last_entry) = self.last_entry() {
// if last_entry.get().is_older_than(height) {
match last_entry.key().cmp(&blk_index) {
Ordering::Greater => {
last_entry.remove_entry();
}
Ordering::Less => {
self.insert(blk_index, BlkRecap::from(height, blk_metadata_and_block));
}
Ordering::Equal => {}
};
// }
} else {
if blk_index != 0 || height != 0 {
// dbg!(blk_index, height);
unreachable!();
}
self.insert(blk_index, BlkRecap::first(blk_metadata_and_block));
}
}
pub fn export(&self) {
let file = File::create(&self.path).unwrap_or_else(|_| {
dbg!(&self.path);
panic!("No such file or directory")
});
serde_json::to_writer_pretty(&mut BufWriter::new(file), &self.tree).unwrap();
}
}
+18
View File
@@ -0,0 +1,18 @@
use std::path::PathBuf;
use crate::path_to_modified_time;
#[derive(Clone, Copy)]
pub struct BlkMetadata {
pub index: usize,
pub modified_time: u64,
}
impl BlkMetadata {
pub fn new(index: usize, path: &PathBuf) -> Self {
Self {
index,
modified_time: path_to_modified_time(path),
}
}
}
+17
View File
@@ -0,0 +1,17 @@
use bitcoin::Block;
use crate::BlkMetadata;
pub struct BlkMetadataAndBlock {
pub blk_metadata: BlkMetadata,
pub block: Block,
}
impl BlkMetadataAndBlock {
pub fn new(blk_metadata: BlkMetadata, block: Block) -> Self {
Self {
blk_metadata,
block,
}
}
}
+47
View File
@@ -0,0 +1,47 @@
use std::path::PathBuf;
use bitcoin::{hashes::Hash, BlockHash};
use serde::{Deserialize, Serialize};
use crate::{path_to_modified_time, BlkMetadataAndBlock};
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct BlkRecap {
min_continuous_height: usize,
min_continuous_prev_hash: BlockHash,
modified_time: u64,
}
impl BlkRecap {
pub fn first(blk_metadata_and_block: &BlkMetadataAndBlock) -> Self {
Self {
min_continuous_height: 0,
min_continuous_prev_hash: BlockHash::all_zeros(),
modified_time: blk_metadata_and_block.blk_metadata.modified_time,
}
}
pub fn from(height: usize, blk_metadata_and_block: &BlkMetadataAndBlock) -> Self {
Self {
min_continuous_height: height,
min_continuous_prev_hash: blk_metadata_and_block.block.header.prev_blockhash,
modified_time: blk_metadata_and_block.blk_metadata.modified_time,
}
}
pub fn has_different_modified_time(&self, blk_path: &PathBuf) -> bool {
self.modified_time != path_to_modified_time(blk_path)
}
pub fn is_younger_than(&self, height: usize) -> bool {
self.min_continuous_height > height
}
pub fn height(&self) -> usize {
self.min_continuous_height
}
pub fn prev_hash(&self) -> &BlockHash {
&self.min_continuous_prev_hash
}
}
+384
View File
@@ -0,0 +1,384 @@
use std::{
collections::{BTreeMap, BTreeSet, VecDeque},
fs::{self},
ops::ControlFlow,
thread,
};
use bitcoin::{
consensus::{Decodable, ReadExt},
hashes::Hash,
io::{Cursor, Read},
Block, BlockHash,
};
use bitcoincore_rpc::RpcApi;
use crossbeam::channel::{bounded, Receiver};
use rayon::prelude::*;
pub use bitcoin;
pub use bitcoincore_rpc;
mod blk_index_to_blk_recap;
mod blk_metadata;
mod blk_metadata_and_block;
mod blk_recap;
mod utils;
use blk_index_to_blk_recap::*;
use blk_metadata::*;
use blk_metadata_and_block::*;
use utils::*;
pub const NUMBER_OF_UNSAFE_BLOCKS: usize = 100;
const MAGIC_BYTES: [u8; 4] = [249, 190, 180, 217];
const BOUND_CAP: usize = 210;
enum BlockState {
Raw(Vec<u8>),
Decoded(Block),
}
///
/// Returns a crossbeam channel receiver that receives `(usize, Block, BlockHash)` tuples (with `usize` being the height) in sequential order.
///
/// # Arguments
///
/// * `data_dir` - Path to the Bitcoin data directory
/// * `export_dir` - Path to the export directory where a mini blk indexer will be exported
/// * `start` - Inclusive starting height of the blocks received, `None` for 0
/// * `end` - Inclusive ending height of the blocks received, `None` for the last one
/// * `rpc` - RPC client to filter out forks
///
/// # Example
///
/// ```rust
/// use bitcoincore_rpc::{Auth, Client};
///
/// fn main() {
/// let i = std::time::Instant::now();
///
/// let url = "http://localhost:8332";
/// let auth = Auth::UserPass("satoshi".to_string(), "nakamoto".to_string());
/// let rpc = Client::new(url, auth).unwrap();
///
/// let data_dir = "../../bitcoin";
/// let export_dir = "./target";
/// let start = Some(850_000);
/// let end = None;
///
/// biter::new(data_dir, export_dir, start, end, rpc)
/// .iter()
/// .for_each(|(height, _block, hash)| {
/// println!("{height}: {hash}");
/// });
///
/// dbg!(i.elapsed());
///}
/// ```
///
pub fn new(
data_dir: &str,
export_dir: &str,
start: Option<usize>,
end: Option<usize>,
rpc: bitcoincore_rpc::Client,
) -> Receiver<(usize, Block, BlockHash)> {
let (send_block_reader, recv_block_reader) = bounded(BOUND_CAP);
let (send_block, recv_block) = bounded(BOUND_CAP);
let (send_height_block_hash, recv_height_block_hash) = bounded(BOUND_CAP);
let blocks_dir = scan_blocks_dir(data_dir);
let mut blk_index_to_blk_recap = BlkIndexToBlkRecap::import(&blocks_dir, export_dir);
let start_recap = blk_index_to_blk_recap.get_start_recap(start);
let starting_blk_index = start_recap.as_ref().map_or(0, |(index, _)| *index);
thread::spawn(move || {
blocks_dir
.into_iter()
.filter(|(blk_index, _)| blk_index >= &starting_blk_index)
.try_for_each(move |(blk_index, blk_path)| {
let blk_metadata = BlkMetadata::new(blk_index, &blk_path);
let blk_bytes = fs::read(&blk_path).unwrap();
let blk_bytes_len = blk_bytes.len() as u64;
let mut cursor = Cursor::new(blk_bytes.as_slice());
let mut current_4bytes = [0; 4];
'parent: loop {
if cursor.position() == blk_bytes_len {
break;
}
// Read until we find a valid suite of MAGIC_BYTES
loop {
current_4bytes.rotate_left(1);
if let Ok(byte) = cursor.read_u8() {
current_4bytes[3] = byte;
} else {
break 'parent;
}
if current_4bytes == MAGIC_BYTES {
break;
}
}
let block_size = cursor.read_u32().unwrap();
let mut raw_block = vec![0u8; block_size as usize];
cursor.read_exact(&mut raw_block).unwrap();
if send_block_reader
.send((blk_metadata, BlockState::Raw(raw_block)))
.is_err()
{
return ControlFlow::Break(());
}
}
ControlFlow::Continue(())
})
});
// thread::spawn(move || {
// recv_block_reader.iter().par_bridge().try_for_each(
// move |(blk_metadata, mut block_state)| {
// let raw_block = match block_state {
// BlockState::Raw(vec) => vec,
// _ => unreachable!(),
// };
// let mut cursor = Cursor::new(raw_block);
// block_state = BlockState::Decoded(Block::consensus_decode(&mut cursor).unwrap());
// if send_block
// .send(BlkMetadataAndBlock::new(
// blk_metadata,
// match block_state {
// BlockState::Decoded(block) => block,
// _ => unreachable!(),
// },
// ))
// .is_err()
// {
// return ControlFlow::Break(());
// }
// ControlFlow::Continue(())
// },
// );
// });
// Can't use the previous code because .send() blocks all the threads if full
// And other .par_iter() are also stuck because of that
thread::spawn(move || {
let mut bulk = vec![];
let drain_and_send = |bulk: &mut Vec<_>| {
// Using a vec and sending after to not end up with stuck threads in par iter
bulk.par_iter_mut().for_each(|(_, block_state)| {
let raw_block = match block_state {
BlockState::Raw(vec) => vec,
_ => unreachable!(),
};
let mut cursor = Cursor::new(raw_block);
*block_state = BlockState::Decoded(Block::consensus_decode(&mut cursor).unwrap());
});
bulk.drain(..).try_for_each(|(blk_metadata, block_state)| {
let block = match block_state {
BlockState::Decoded(block) => block,
_ => unreachable!(),
};
if send_block
.send(BlkMetadataAndBlock::new(blk_metadata, block))
.is_err()
{
return ControlFlow::Break(());
}
ControlFlow::Continue(())
})
};
recv_block_reader.iter().try_for_each(|tuple| {
bulk.push(tuple);
if bulk.len() < BOUND_CAP / 2 {
return ControlFlow::Continue(());
}
drain_and_send(&mut bulk)
});
drain_and_send(&mut bulk)
});
// Tokio version: 1022s
// Slighlty slower than rayon version
// thread::spawn(move || {
// let rt = tokio::runtime::Runtime::new().unwrap();
// let _guard = rt.enter();
// let mut tasks = VecDeque::with_capacity(BOUND);
// recv_block_reader
// .iter()
// .try_for_each(move |(blk_metadata, block_state)| {
// let raw_block = match block_state {
// BlockState::Raw(vec) => vec,
// _ => unreachable!(),
// };
// tasks.push_back(tokio::task::spawn(async move {
// let block = Block::consensus_decode(&mut Cursor::new(raw_block)).unwrap();
// (blk_metadata, block)
// }));
// while tasks.len() > BOUND {
// let (blk_metadata, block) = rt.block_on(tasks.pop_front().unwrap()).unwrap();
// if send_block
// .send(BlkMetadataAndBlock::new(blk_metadata, block))
// .is_err()
// {
// return ControlFlow::Break(());
// }
// }
// ControlFlow::Continue(())
// });
//
// todo!("Send the rest")
// });
thread::spawn(move || {
let mut height = start_recap.map_or(0, |(_, recap)| recap.height());
let mut future_blocks = BTreeMap::default();
let mut recent_chain: VecDeque<(BlockHash, BlkMetadataAndBlock)> = VecDeque::default();
let mut recent_hashes: BTreeSet<BlockHash> = BTreeSet::default();
let mut prev_hash =
start_recap.map_or_else(BlockHash::all_zeros, |(_, recap)| *recap.prev_hash());
let mut prepare_and_send = |(hash, tuple): (BlockHash, BlkMetadataAndBlock)| {
blk_index_to_blk_recap.update(&tuple, height);
if start.map_or(true, |start| start <= height) {
send_height_block_hash
.send((height, tuple.block, hash))
.unwrap();
}
if end.map_or(false, |end| height == end) {
return ControlFlow::Break(());
}
height += 1;
ControlFlow::Continue(())
};
let mut update_tip = |prev_hash: &mut BlockHash,
recent_hashes: &mut BTreeSet<BlockHash>,
recent_chain: &mut VecDeque<(BlockHash, BlkMetadataAndBlock)>,
future_blocks: &mut BTreeMap<BlockHash, BlkMetadataAndBlock>,
tuple: BlkMetadataAndBlock| {
let mut tuple = Some(tuple);
while let Some(tuple) = tuple.take().or_else(|| future_blocks.remove(prev_hash)) {
let hash = tuple.block.block_hash();
*prev_hash = hash;
recent_hashes.insert(hash);
recent_chain.push_back((hash, tuple));
}
while recent_chain.len() > NUMBER_OF_UNSAFE_BLOCKS {
let (hash, tuple) = recent_chain.pop_front().unwrap();
recent_hashes.remove(&hash);
if prepare_and_send((hash, tuple)).is_break() {
return ControlFlow::Break(());
}
}
ControlFlow::Continue(())
};
let flow = recv_block.iter().try_for_each(|tuple| {
// block isn't next after current tip
if prev_hash != tuple.block.header.prev_blockhash {
let is_block_active =
|hash| rpc.get_block_header_info(hash).unwrap().confirmations > 0;
// block prev has already been processed
if recent_hashes.contains(&tuple.block.header.prev_blockhash) {
let hash = tuple.block.block_hash();
if is_block_active(&hash) {
let prev_index = recent_chain
.iter()
.position(|(hash, ..)| hash == &tuple.block.header.prev_blockhash)
.unwrap();
let bad_index_start = prev_index + 1;
recent_chain.drain(bad_index_start..).for_each(|(hash, _)| {
recent_hashes.remove(&hash);
});
return update_tip(
&mut prev_hash,
&mut recent_hashes,
&mut recent_chain,
&mut future_blocks,
tuple,
);
}
// Check if there was already a future block with the same prev hash
} else if let Some(prev_tuple) =
future_blocks.insert(tuple.block.header.prev_blockhash, tuple)
{
// If the previous was the active one
if is_block_active(&prev_tuple.block.block_hash()) {
// Rollback the insert
future_blocks.insert(prev_tuple.block.header.prev_blockhash, prev_tuple);
}
}
} else {
return update_tip(
&mut prev_hash,
&mut recent_hashes,
&mut recent_chain,
&mut future_blocks,
tuple,
);
}
ControlFlow::Continue(())
});
if flow.is_continue() {
// Send the last (up to 100) blocks
recent_chain.into_iter().try_for_each(prepare_and_send);
}
blk_index_to_blk_recap.export();
});
recv_height_block_hash
}
+22
View File
@@ -0,0 +1,22 @@
use bitcoincore_rpc::{Auth, Client};
fn main() {
let i = std::time::Instant::now();
let url = "http://localhost:8332";
let auth = Auth::UserPass("satoshi".to_string(), "nakamoto".to_string());
let rpc = Client::new(url, auth).unwrap();
let data_dir = "../bitcoin";
let export_dir = "./target";
let start = None;
let end = None;
biter::new(data_dir, export_dir, start, end, rpc)
.iter()
.for_each(|(height, _block, hash)| {
println!("{height}: {hash}");
});
dbg!(i.elapsed());
}
+43
View File
@@ -0,0 +1,43 @@
use std::{collections::BTreeMap, fs, path::PathBuf, time::UNIX_EPOCH};
const BLK: &str = "blk";
const DAT: &str = ".dat";
pub fn scan_blocks_dir(data_dir_path: &str) -> BTreeMap<usize, PathBuf> {
let blocks_dir_path = &format!("{data_dir_path}/blocks");
fs::read_dir(blocks_dir_path)
.unwrap()
.map(|entry| entry.unwrap().path())
.filter(|path| {
let is_file = path.is_file();
if is_file {
let file_name = path.file_name().unwrap().to_str().unwrap();
file_name.starts_with(BLK) && file_name.ends_with(DAT)
} else {
false
}
})
.map(|path| {
let file_name = path.file_name().unwrap().to_str().unwrap();
let blk_index = file_name[BLK.len()..(file_name.len() - DAT.len())]
.parse::<usize>()
.unwrap();
(blk_index, path)
})
.collect::<BTreeMap<_, _>>()
}
pub fn path_to_modified_time(path: &PathBuf) -> u64 {
fs::metadata(path)
.unwrap()
.modified()
.unwrap()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
}
+11
View File
@@ -0,0 +1,11 @@
FROM rust:1.81
ENV rpcconnect=localhost
ENV rpcport=8332
ENV rpcuser=satoshi
ENV rpcpassword=nakamoto
WORKDIR /
COPY . .
CMD exec cargo run -r --manifest-path /kibo/parser/Cargo.toml -- --datadir=/bitcoin --rpcconnect=${rpcconnect} --rpcport=${rpcport} --rpcuser=${rpcuser} --rpcpassword=${rpcpassword}
+6
View File
@@ -0,0 +1,6 @@
# !/usr/bin/env bash
[[ -d "./kibo" ]] && sudo rm -r ./kibo
git clone https://github.com/kibo-money/kibo.git
docker build -t kibo-parser .
Executable
+13
View File
@@ -0,0 +1,13 @@
#!/usr/bin/env bash
cd kibo/parser
./run.sh \
--datadir=/bitcoin \
--rpcconnect=$1 \
--rpcport=$2 \
--rpcuser=$3 \
--rpcpassword=$4
# cd ../server
# ./run.sh &
Executable
+11
View File
@@ -0,0 +1,11 @@
docker run \
--env rpcuser=satoshi \
--env rpcpassword=nakamoto \
--env rpcport=localhost \
--env rpcport=8332 \
--volume /tmp/kibo/datasets:/kibo/datasets \
--volume /tmp/kibo/price:/kibo/price \
--volume /tmp/kibo/outputs:/kibo/parser/out \
--volume $HOME/Developer/bitcoin:/bitcoin \
--net=host \
kibo-parser
+60
View File
@@ -0,0 +1,60 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "proc-macro2"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "struct_iterable"
version = "0.1.2"
dependencies = [
"struct_iterable_derive",
"struct_iterable_internal",
]
[[package]]
name = "struct_iterable_derive"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"struct_iterable_internal",
"syn",
]
[[package]]
name = "struct_iterable_internal"
version = "0.1.1"
[[package]]
name = "syn"
version = "2.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
+26
View File
@@ -0,0 +1,26 @@
[package]
name = "struct_iterable"
version = "0.1.2"
authors = ["André de Moraes <deco.moraes@icloud.com>"]
edition = "2021"
description = "A Rust library providing a proc macro to make a struct iterable."
license = "MIT"
repository = "https://github.com/decomoraes/rust_struct_iterable"
readme = "README.md"
keywords = ["proc-macro", "struct", "iterable"]
categories = ["development-tools::cargo-plugins"]
homepage = "https://github.com/decomoraes/rust_struct_iterable"
documentation = "https://docs.rs/struct_iterable"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
struct_iterable_derive = { path = "./struct_iterable_derive" }
struct_iterable_internal = { path = "./struct_iterable_internal" }
[lib]
name = "struct_iterable"
path = "src/lib.rs"
[package.metadata.docs.rs]
all-features = true
+105
View File
@@ -0,0 +1,105 @@
# Struct Iterable
`Struct Iterable` is a Rust library that provides a proc macro to make a struct iterable. This allows you to iterate over the fields of your struct in a generic way, with each iteration returning a tuple containing the name of the field as a static string and a reference to the field's value as a `dyn Any`.
## How to Use
First, add `Struct Iterable` to your `Cargo.toml`:
```toml
[dependencies]
struct_iterable = "0.1.1"
```
Next, include the library at the top of your Rust file:
```rust
use struct_iterable::Iterable;
```
Finally, add the `#[derive(Iterable)]` attribute to your struct:
```rust
#[derive(Iterable)]
struct MyStruct {
field1: u32,
field2: String,
// etc.
}
```
Now, you can iterate over the fields of an instance of your struct:
```rust
let my_instance = MyStruct {
field1: 42,
field2: "Hello, world!".to_string(),
};
for (field_name, field_value) in my_instance.iter() {
println!("{}: {:?}", field_name, field_value);
}
```
## Limitations
- Only structs with named fields are supported.
- Only structs are supported, not enums or unions.
## Implementation
Here is the implementation of the proc macro:
```rust
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Fields};
use iterable_structs::Iterable;
#[proc_macro_derive(Iterable)]
pub fn derive_iterable(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let struct_name = input.ident;
let fields = match input.data {
Data::Struct(data_struct) => match data_struct.fields {
Fields::Named(fields_named) => fields_named.named,
_ => panic!("Only structs with named fields are supported"),
},
_ => panic!("Only structs are supported"),
};
let fields_iter = fields.iter().map(|field| {
let field_ident = &field.ident;
let field_name = field_ident.as_ref().unwrap().to_string();
quote! {
(#field_name, &(self.#field_ident) as &dyn std::any::Any)
}
});
let expanded = quote! {
impl Iterable for #struct_name {
fn iter<'a>(&'a self) -> std::vec::IntoIter<(&'static str, &'a dyn std::any::Any)> {
vec![
#(#fields_iter),*
].into_iter()
}
}
};
TokenStream::from(expanded)
}
```
The macro takes in the TokenStream of a struct and expands it into an implementation of the Iterable trait for that struct. This trait provides an iter method that returns an iterator over tuples of field names and values.
## Contributing and License
`Struct Iterable` is an open-source project, and contributions are warmly welcomed. Whether you're fixing bugs, improving the documentation, or proposing new features, your efforts are highly appreciated!
If you're interested in contributing, please feel free to submit a pull request. For major changes, please open an issue first to discuss what you would like to change.
Please note that this project is released with a Contributor Code of Conduct. By participating in this project, you agree to abide by its terms.
`Struct Iterable` is distributed under the terms of the MIT license. As such, you're free to use, modify, distribute, and privately use it in any way you see fit, in accordance with the terms of the license.
+91
View File
@@ -0,0 +1,91 @@
/// The `Iterable` proc macro.
///
/// This macro provides a convenient way to make a struct iterable.
/// The struct fields' names are returned as static strings and their values as `dyn Any`.
/// This allows to iterate over the struct fields in a generic way.
///
/// Note that only structs with named fields are supported.
///
/// # Example
///
/// ```
/// use struct_iterable::Iterable;
///
/// #[derive(Iterable)]
/// struct MyStruct {
/// field1: i32,
/// field2: String,
/// // etc.
/// }
///
/// let my_instance = MyStruct {
/// field1: 42,
/// field2: "Hello, world!".to_string(),
/// };
///
/// for (field_name, field_value) in my_instance.iter() {
/// println!("{}: {:?}", field_name, field_value);
/// }
/// ```
pub use struct_iterable_derive::Iterable;
/// The `Iterable` trait.
///
/// This trait is implemented by the struct once the `Iterable` proc macro is derived.
/// It provides an `iter` method that returns an iterator over tuples of field names and values.
///
/// # Example
///
/// ```
/// use struct_iterable::Iterable;
///
/// #[derive(Iterable)]
/// struct MyStruct {
/// field1: i32,
/// field2: String,
/// // etc.
/// }
///
/// let my_instance = MyStruct {
/// field1: 42,
/// field2: "Hello, world!".to_string(),
/// };
///
/// for (field_name, field_value) in my_instance.iter() {
/// println!("{}: {:?}", field_name, field_value);
/// }
/// ```
pub use struct_iterable_internal::Iterable;
#[cfg(test)]
mod tests {
use super::*;
#[derive(Iterable)]
struct MyStruct {
field1: i32,
field2: String,
// etc.
}
#[test]
fn it_works() {
let mut my_instance = MyStruct {
field1: 42,
field2: "Hello, world!".to_string(),
};
for (field_name, field_value) in my_instance.iter() {
dbg!("{}: {:?}", field_name, field_value);
}
for (field_name, field_value) in my_instance.iter_mut() {
dbg!("{}: {:?}", field_name, &field_value);
if let Some(i32) = field_value.downcast_mut::<i32>() {
*i32 += 1;
dbg!(i32);
}
dbg!("{}: {:?}", field_name, &field_value);
}
}
}
@@ -0,0 +1,17 @@
[package]
name = "struct_iterable_derive"
version = "0.1.0"
authors = ["André de Moraes <deco.moraes@icloud.com>"]
edition = "2021"
description = "An internal crate for struct_iterable"
license = "MIT"
[lib]
proc-macro = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
syn = "2.0.85"
quote = "1.0.37"
proc-macro2 = "1.0.89"
struct_iterable_internal = { path = "../struct_iterable_internal" }
@@ -0,0 +1,7 @@
# Struct Iterable Derive
This crate is a supporting library for the `struct_iterable` crate. It provides the proc macro `Iterable` which is used in conjunction with the `struct_iterable_internal` crate to provide an easy way to make a struct iterable in Rust.
**Please note:** This crate is not intended to be used directly. If you want to make your structs iterable, please use the `struct_iterable` crate instead.
Please visit the [`struct_iterable` crate on crates.io](https://crates.io/crates/struct_iterable) for more information and usage examples.
@@ -0,0 +1,88 @@
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Fields};
/// The `Iterable` proc macro.
///
/// Deriving this macro for your struct will make it "iterable". An iterable struct allows you to iterate over its fields, returning a tuple containing the field name as a static string and a reference to the field's value as `dyn Any`.
///
/// # Limitations
///
/// - Only structs are supported, not enums or unions.
/// - Only structs with named fields are supported.
///
/// # Usage
///
/// Add the derive attribute (`#[derive(Iterable)]`) above your struct definition.
///
/// ```
/// use struct_iterable::Iterable;
///
/// #[derive(Iterable)]
/// struct MyStruct {
/// field1: i32,
/// field2: String,
/// }
/// ```
///
/// You can now call the `iter` method on instances of your struct to get an iterator over its fields:
///
/// ```
/// let my_instance = MyStruct {
/// field1: 42,
/// field2: "Hello, world!".to_string(),
/// };
///
/// for (field_name, field_value) in my_instance.iter() {
/// println!("{}: {:?}", field_name, field_value);
/// }
/// ```
#[proc_macro_derive(Iterable)]
pub fn derive_iterable(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let struct_name = input.ident;
let fields = match input.data {
Data::Struct(data_struct) => match data_struct.fields {
Fields::Named(fields_named) => fields_named.named,
_ => panic!("Only structs with named fields are supported"),
},
_ => panic!("Only structs are supported"),
};
let fields_iter = fields.iter().map(|field| {
let field_ident = &field.ident;
let field_name = field_ident.as_ref().unwrap().to_string();
quote! {
(#field_name, &(self.#field_ident) as &dyn std::any::Any)
}
});
let fields_iter_mut = fields.iter().map(|field| {
let field_ident = &field.ident;
let field_name = field_ident.as_ref().unwrap().to_string();
quote! {
(#field_name, &mut (self.#field_ident) as &mut dyn std::any::Any)
}
});
let expanded = quote! {
impl Iterable for #struct_name {
fn iter<'a>(&'a self) -> std::vec::IntoIter<(&'static str, &'a dyn std::any::Any)> {
vec![
#(#fields_iter),*
].into_iter()
}
fn iter_mut<'a>(&'a mut self) -> std::vec::IntoIter<(&'static str, &'a mut dyn std::any::Any)> {
vec![
#(#fields_iter_mut),*
].into_iter()
}
}
};
TokenStream::from(expanded)
}
@@ -0,0 +1,11 @@
[package]
name = "struct_iterable_internal"
version = "0.1.1"
authors = ["André de Moraes <deco.moraes@icloud.com>"]
edition = "2021"
description = "An internal crate for struct_iterable"
license = "MIT"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
@@ -0,0 +1,7 @@
# Struct Iterable Internal
This crate is a supporting library for the `struct_iterable` crate. It provides the `Iterable` trait which is used in conjunction with the `struct_iterable_derive` crate to provide an easy way to make a struct iterable in Rust.
**Please note:** This crate is not intended to be used directly. If you want to make your structs iterable, please use the `struct_iterable` crate instead.
Please visit the [`struct_iterable` crate on crates.io](https://crates.io/crates/struct_iterable) for more information and usage examples.
@@ -0,0 +1,58 @@
/// The `Iterable` trait.
///
/// This trait is implemented for structs that derive the `Iterable` proc macro.
/// It provides the `iter` method which returns an iterator over the struct's fields as tuples, containing the field name as a static string and a reference to the field's value as `dyn Any`.
///
/// You usually don't need to implement this trait manually, as it is automatically derived when using the `#[derive(Iterable)]` proc macro.
///
/// # Example
///
/// ```
/// use struct_iterable::Iterable;
///
/// #[derive(Iterable)]
/// struct MyStruct {
/// field1: i32,
/// field2: String,
/// }
///
/// let my_instance = MyStruct {
/// field1: 42,
/// field2: "Hello, world!".to_string(),
/// };
///
/// // Iterate over the fields of `my_instance`:
/// for (field_name, field_value) in my_instance.iter() {
/// println!("{}: {:?}", field_name, field_value);
/// }
/// ```
pub trait Iterable {
/// Returns an iterator over the struct's fields as tuples.
///
/// Each tuple contains a field's name as a static string and a reference to the field's value as `dyn Any`.
///
/// # Example
///
/// ```
/// use struct_iterable::Iterable;
///
/// #[derive(Iterable)]
/// struct MyStruct {
/// field1: i32,
/// field2: String,
/// }
///
/// let my_instance = MyStruct {
/// field1: 42,
/// field2: "Hello, world!".to_string(),
/// };
///
/// // Iterate over the fields of `my_instance`:
/// for (field_name, field_value) in my_instance.iter() {
/// println!("{}: {:?}", field_name, field_value);
/// }
/// ```
fn iter(&self) -> std::vec::IntoIter<(&'static str, &'_ dyn std::any::Any)>;
fn iter_mut(&mut self) -> std::vec::IntoIter<(&'static str, &'_ mut dyn std::any::Any)>;
}
+244 -255
View File
File diff suppressed because it is too large Load Diff
+15 -10
View File
@@ -1,27 +1,32 @@
[package]
name = "parser"
version = "0.4.1"
version = "0.5.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
allocative = "0.3.3"
bincode = { git = "https://github.com/bincode-org/bincode.git" }
biter = "0.1.0"
bincode = { git = "https://github.com/bincode-org/bincode.git", features = [
"serde",
] }
bitcoin_hashes = { version = "0.14.0" }
biter = { path = "../biter" }
chrono = { version = "0.4.38", features = ["serde"] }
clap = { version = "4.5.16", features = ["derive"] }
clap = { version = "4.5.20", features = ["derive"] }
color-eyre = "0.6.3"
ctrlc = { version = "3.4.5", features = ["termination"] }
derive_deref = "1.1.1"
inferno = "0.11.21"
itertools = "0.13.0"
memory-stats = "1.2.0"
ordered-float = "4.2.2"
ordered-float = "4.4.0"
rayon = "1.10.0"
reqwest = { version = "0.12.7", features = ["blocking", "json"] }
sanakirja = "1.4.2"
serde = { version = "1.0.208", features = ["derive"] }
serde_json = "1.0.125"
reqwest = { version = "0.12.9", features = ["blocking", "json"] }
sanakirja = "1.4.3"
serde = { version = "1.0.214", features = ["derive"] }
serde_json = "1.0.132"
struct_iterable = { path = "../iterable" }
toml = "0.8.19"
zstd = "0.13.2"
# memory-stats = "1.2.0"
# sysinfo = "0.32.0"
+7
View File
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
echo "Deleting datasets..."
rm -r ../datasets
echo "Deleting states and databases..."
rm -r ./out
echo "Done."
+2
View File
@@ -1,3 +1,5 @@
#!/usr/bin/env bash
echo "Increasing limit of opened files..."
ulimit -n 1000000
+12 -3
View File
@@ -1,4 +1,4 @@
use std::thread;
use std::thread::{self};
use crate::{
databases::Databases,
@@ -6,6 +6,7 @@ use crate::{
states::States,
structs::{Date, Height},
utils::{log, time},
Exit,
};
pub struct ExportedData<'a> {
@@ -14,6 +15,7 @@ pub struct ExportedData<'a> {
pub date: Date,
pub height: Height,
pub states: Option<&'a States>,
pub exit: Exit,
}
pub fn export(
@@ -23,10 +25,17 @@ pub fn export(
states,
height,
date,
exit,
}: ExportedData,
) -> color_eyre::Result<()> {
if exit.active() {
log("Exit in progress, skipping export");
return Ok(());
}
exit.block();
log("Exporting...");
log("WARNING: NOT SAFE TO STOP !!!");
time("Total save time", || -> color_eyre::Result<()> {
time("Datasets saved", || datasets.export())?;
@@ -44,7 +53,7 @@ pub fn export(
Ok(())
})?;
log("Export done - Safe to stop now");
exit.unblock();
Ok(())
}
+29 -24
View File
@@ -1,6 +1,5 @@
use std::{collections::BTreeSet, time::Instant};
use chrono::Datelike;
use export::ExportedData;
use itertools::Itertools;
@@ -13,29 +12,29 @@ use crate::{
datasets::{AllDatasets, ComputeData},
io::OUTPUTS_FOLDER_PATH,
states::{AddressCohortsDurableStates, States, UTXOCohortsDurableStates},
structs::{Date, DateData, MapKey},
structs::{DateData, MapKey, Timestamp},
utils::{generate_allocation_files, log, time},
Config, Height,
Config, Exit, Height,
};
pub fn iter_blocks(
config: &Config,
config: &mut Config,
rpc: &biter::bitcoincore_rpc::Client,
approx_block_count: usize,
exit: Exit,
) -> color_eyre::Result<()> {
let should_insert = true;
let should_export = true;
let study_ram_usage = false;
log("Starting...");
let mut datasets = AllDatasets::import()?;
// RAM: 200MB at this point
let mut datasets = AllDatasets::import(config)?;
log("Imported datasets");
let mut databases = Databases::import();
// RAM: 200MB too
if config.first_defragment() {
databases.defragment(&exit);
config.disable_defragment();
}
log("Imported databases");
@@ -84,9 +83,9 @@ pub fn iter_blocks(
if let Some((_current_block_height, current_block, _current_block_hash)) =
current_block_opt
{
let timestamp = current_block.header.time;
let timestamp = Timestamp::wrap(current_block.header.time);
let current_block_date = Date::from_timestamp(timestamp);
let current_block_date = timestamp.to_date();
let current_block_height: Height = height + blocks_loop_i;
if current_block_height.to_usize() != _current_block_height {
@@ -94,9 +93,9 @@ pub fn iter_blocks(
panic!()
}
let next_block_date = next_block_opt
.as_ref()
.map(|(_, next_block, _)| Date::from_timestamp(next_block.header.time));
let next_block_date = next_block_opt.as_ref().map(|(_, next_block, _)| {
Timestamp::wrap(next_block.header.time).to_date()
});
// Always run for the first block of the loop
if blocks_loop_date.is_none() {
@@ -132,7 +131,7 @@ pub fn iter_blocks(
processed_heights.insert(current_block_height);
if should_insert && first_unsafe_heights.inserted <= current_block_height {
if first_unsafe_heights.inserted <= current_block_height {
let compute_addresses = databases.check_if_needs_to_compute_addresses(
current_block_height,
blocks_loop_date,
@@ -171,7 +170,6 @@ pub fn iter_blocks(
height: current_block_height,
is_date_last_block,
states: &mut states,
timestamp,
});
}
@@ -180,10 +178,15 @@ pub fn iter_blocks(
if is_date_last_block {
height += blocks_loop_i;
let is_new_month = next_block_date
.map_or(true, |next_block_date| next_block_date.day() == 1);
let is_check_point = next_block_date
.as_ref()
.map_or(true, |date| date.is_first_of_month());
if is_new_month || height.is_close_to_end(approx_block_count) {
let ran_for_at_least_a_minute = instant.elapsed().as_secs() >= 60;
if (is_check_point && ran_for_at_least_a_minute)
|| height.is_close_to_end(approx_block_count)
{
break 'days;
}
@@ -199,11 +202,12 @@ pub fn iter_blocks(
let last_height = height - 1_u32;
log(&format!(
"Parsing month took {} seconds (last height: {last_height})\n",
"Parsing group took {} seconds (last height: {last_height})\n",
instant.elapsed().as_secs_f32(),
));
if first_unsafe_heights.computed <= last_height {
log("Computing datasets...");
time("Computing datasets", || {
let dates = processed_dates.into_iter().collect_vec();
@@ -216,7 +220,7 @@ pub fn iter_blocks(
});
}
if should_export {
if !config.dry_run() {
let is_safe = height.is_safe(approx_block_count);
export(ExportedData {
@@ -225,9 +229,10 @@ pub fn iter_blocks(
date: blocks_loop_date.unwrap(),
height: last_height,
states: is_safe.then_some(&states),
exit: exit.clone(),
})?;
if study_ram_usage {
if config.record_ram_usage() {
time("Exporing allocation files", || {
generate_allocation_files(&datasets, &databases, &states, last_height)
})?;
+2 -2
View File
@@ -67,7 +67,7 @@ pub fn find_first_inserted_unsafe_height(
let inserted_last_date_is_older_than_saved_state = min_datasets_inserted_last_date.map_or(true, |min_datasets_last_date| min_datasets_last_date < last_safe_date);
if inserted_last_date_is_older_than_saved_state {
dbg!(min_datasets_inserted_last_date , *last_safe_date);
// dbg!(min_datasets_inserted_last_date , *last_safe_date);
return None;
}
@@ -87,7 +87,7 @@ pub fn find_first_inserted_unsafe_height(
let computed = datasets_min_initial_states.computed.last_date.and_then(
|last_date| datasets.date_metadata
.last_height
.get(&last_date)
.get_or_import(&last_date)
.and_then(|last_date_height| {
if datasets_min_initial_states.computed.last_height.map_or(true, |last_height| {
last_height < last_date_height
+15 -12
View File
@@ -20,7 +20,7 @@ use crate::{
},
structs::{
Address, AddressData, AddressRealizedData, Amount, BlockData, BlockPath, Counter, Date,
EmptyAddressData, Height, PartialTxoutData, Price, SentData, TxData, TxoutIndex,
EmptyAddressData, Height, PartialTxoutData, Price, SentData, Timestamp, TxData, TxoutIndex,
},
};
@@ -37,7 +37,6 @@ pub struct ParseData<'a> {
pub is_date_last_block: bool,
pub rpc: &'a biter::bitcoincore_rpc::Client,
pub states: &'a mut States,
pub timestamp: u32,
}
pub fn parse(
@@ -53,11 +52,12 @@ pub fn parse(
is_date_last_block,
rpc,
states,
timestamp,
}: ParseData,
) {
// log(&format!("{height}"));
let timestamp = Timestamp::wrap(block.header.time);
// If false, expect that the code is flawless
// or create a 0 value txid database
let enable_check_if_txout_value_is_zero_in_db: bool = true;
@@ -89,9 +89,9 @@ pub fn parse(
let block_size = block.total_size();
let block_weight = block.weight().to_wu();
let block_vbytes = block.weight().to_vbytes_floor();
let block_interval = previous_timestamp.map_or(0, |previous_timestamp| {
let block_interval = previous_timestamp.map_or(Timestamp::ZERO, |previous_timestamp| {
if previous_timestamp >= timestamp {
0
Timestamp::ZERO
} else {
timestamp - previous_timestamp
}
@@ -126,7 +126,7 @@ pub fn parse(
(mut txid_to_tx_data, mut txout_index_to_amount_and_address_index),
) = thread::scope(|scope| {
let output_handle = scope.spawn(|| {
let mut txouts_parsing_results = pre_process_outputs(
let mut txouts_parsing_results = prepare_outputs(
&block,
compute_addresses,
&mut states.address_counters.multisig_addresses,
@@ -144,7 +144,7 @@ pub fn parse(
});
let input_handle = scope.spawn(|| {
pre_process_inputs(
prepare_inputs(
&block,
&mut databases.txid_to_tx_data,
&mut databases.txout_index_to_amount,
@@ -519,6 +519,8 @@ pub fn parse(
input_amount,
block_price,
previous_price,
timestamp,
input_block_data.timestamp,
);
};
@@ -645,6 +647,7 @@ pub fn parse(
&states.date_data_vec,
&block_path_to_sent_data,
block_price,
timestamp,
);
});
}
@@ -780,7 +783,7 @@ pub struct TxoutsParsingResults {
}
#[allow(clippy::too_many_arguments)]
fn pre_process_outputs(
fn prepare_outputs(
block: &Block,
compute_addresses: bool,
multisig_addresses: &mut Counter,
@@ -811,6 +814,7 @@ fn pre_process_outputs(
// Op Return
// https://mempool.space/tx/139c004f477101c468767983536caaeef568613fab9c2ed9237521f5ff530afd
// Provably unspendable https://mempool.space/tx/8a68c461a2473653fe0add786f0ca6ebb99b257286166dfb00707be24716af3a#flow=&vout=0
#[allow(deprecated)]
if script.is_op_return() {
// TODO: Count fee paid to write said OP_RETURN, beware of coinbase transactions
// For coinbase transactions, count miners
@@ -818,9 +822,8 @@ fn pre_process_outputs(
provably_unspendable += amount;
// return None;
}
// https://mempool.space/tx/8a68c461a2473653fe0add786f0ca6ebb99b257286166dfb00707be24716af3a#flow=&vout=0
else if script.is_provably_unspendable() {
// https://mempool.space/tx/8a68c461a2473653fe0add786f0ca6ebb99b257286166dfb00707be24716af3a#flow=&vout=0
} else if script.is_provably_unspendable() {
provably_unspendable += amount;
// return None;
}
@@ -866,7 +869,7 @@ fn pre_process_outputs(
}
#[allow(clippy::type_complexity)]
fn pre_process_inputs<'a>(
fn prepare_inputs<'a>(
block: &'a Block,
txid_to_tx_data_db: &mut TxidToTxData,
txout_index_to_amount_db: &mut TxoutIndexToAmount,
+97 -71
View File
@@ -1,11 +1,11 @@
use std::{
collections::{BTreeMap, BTreeSet},
fmt::Debug,
fs,
fs, mem,
path::PathBuf,
};
use allocative::Allocative;
use derive_deref::{Deref, DerefMut};
// https://docs.rs/sanakirja/latest/sanakirja/index.html
// https://pijul.org/posts/2021-02-06-rethinking-sanakirja/
@@ -15,12 +15,10 @@ use derive_deref::{Deref, DerefMut};
//
// Possible compression: https://pijul.org/posts/sanakirja-zstd/
use sanakirja::{
btree::{self, page, Db_},
direct_repr, Commit, Env, Error, MutTxn, RootDb, Storable, UnsizedStorable,
btree::{self, page, Db_, Iter},
Commit, Env, Error, MutTxn, RootDb, Storable,
};
use crate::io::OUTPUTS_FOLDER_PATH;
#[derive(Allocative)]
#[allocative(bound = "Key: Allocative, Value: Allocative")]
/// There is no `cached_gets` since it's much cheaper and faster to do a parallel search first using `unsafe_get` than caching gets along the way.
@@ -31,6 +29,7 @@ where
{
pub cached_puts: BTreeMap<Key, Value>,
pub cached_dels: BTreeSet<Key>,
path: PathBuf,
#[allocative(skip)]
db: Db_<Key, Value, page::Page<Key, Value>>,
#[allocative(skip)]
@@ -45,14 +44,17 @@ where
Key: Ord + Clone + Debug + Storable,
Value: Storable + PartialEq,
{
pub fn open(folder: &str, file: &str) -> color_eyre::Result<Self> {
let mut txn = Self::init_txn(folder, file)?;
pub fn open(path: PathBuf) -> color_eyre::Result<Self> {
let env = unsafe { Env::new_nolock(&path, PAGE_SIZE, 1)? };
let mut txn = Env::mut_txn_begin(env)?;
let db = txn
.root_db(ROOT_DB)
.unwrap_or_else(|| unsafe { btree::create_db_(&mut txn).unwrap() });
Ok(Self {
path,
cached_puts: BTreeMap::default(),
cached_dels: BTreeSet::default(),
db,
@@ -60,13 +62,18 @@ where
})
}
pub fn iter<F>(&self, callback: &mut F)
pub fn iter(&self) -> Iter<'_, MutTxn<Env, ()>, Key, Value, page::Page<Key, Value>> {
btree::iter(&self.txn, &self.db, None).unwrap()
}
pub fn iter_collect(&self) -> BTreeMap<Key, Value>
where
F: FnMut((&Key, &Value)),
Value: Clone,
{
btree::iter(&self.txn, &self.db, None)
.unwrap()
.for_each(|entry| callback(entry.unwrap()));
self.iter()
.map(|r| r.unwrap())
.map(|(key, value)| (key.clone(), value.clone()))
.collect::<_>()
}
pub fn get(&self, key: &Key) -> Option<&Value> {
@@ -108,99 +115,118 @@ where
})
}
#[inline(always)]
#[inline]
pub fn db_remove(&mut self, key: &Key) {
self.cached_dels.insert(key.clone());
}
#[inline]
pub fn update(&mut self, key: Key, value: Value) -> Option<Value> {
self.cached_dels.insert(key.clone());
self.cached_puts.insert(key, value)
}
#[inline(always)]
#[inline]
pub fn is_empty(&self) -> bool {
self.iter().next().is_none()
}
#[inline]
pub fn remove_from_puts(&mut self, key: &Key) -> Option<Value> {
self.cached_puts.remove(key)
}
#[inline(always)]
#[inline]
pub fn insert(&mut self, key: Key, value: Value) -> Option<Value> {
self.cached_dels.remove(&key);
self.unsafe_insert(key, value)
}
#[inline(always)]
#[inline]
pub fn unsafe_insert(&mut self, key: Key, value: Value) -> Option<Value> {
self.cached_puts.insert(key, value)
}
fn init_txn(folder: &str, file: &str) -> color_eyre::Result<MutTxn<Env, ()>> {
let path = databases_folder_path(folder);
fs::create_dir_all(&path)?;
let env = unsafe { Env::new_nolock(format!("{path}/{file}"), PAGE_SIZE, 1).unwrap() };
let txn = Env::mut_txn_begin(env)?;
Ok(txn)
fn db_multi_put(&mut self, tree: BTreeMap<Key, Value>) -> Result<(), Error> {
tree.into_iter()
.try_for_each(|(key, value)| -> Result<(), Error> {
btree::put(&mut self.txn, &mut self.db, &key, &value)?;
Ok(())
})
}
pub fn export(mut self) -> color_eyre::Result<(), Error> {
fn db_multi_del(&mut self, tree: BTreeSet<Key>) -> Result<(), Error> {
tree.into_iter().try_for_each(|key| -> Result<(), Error> {
btree::del(&mut self.txn, &mut self.db, &key, None)?;
Ok(())
})
}
}
pub trait AnyDatabase {
fn export(self) -> color_eyre::Result<(), Error>;
fn boxed_export(self: Box<Self>) -> color_eyre::Result<(), Error>;
#[allow(unused)]
fn defragment(self);
fn boxed_defragment(self: Box<Self>);
fn destroy(self);
}
impl<Key, Value> AnyDatabase for Database<Key, Value>
where
Key: Ord + Clone + Debug + Storable,
Value: Storable + PartialEq + Clone,
{
fn export(self) -> color_eyre::Result<(), Error> {
Box::new(self).boxed_export()
}
fn boxed_export(mut self: Box<Self>) -> color_eyre::Result<(), Error> {
if self.cached_dels.is_empty() && self.cached_puts.is_empty() {
return Ok(());
}
self.cached_dels
.into_iter()
.try_for_each(|key| -> Result<(), Error> {
btree::del(&mut self.txn, &mut self.db, &key, None)?;
let cached_dels = mem::take(&mut self.cached_dels);
self.db_multi_del(cached_dels)?;
Ok(())
})?;
self.cached_puts
.into_iter()
.try_for_each(|(key, value)| -> Result<(), Error> {
btree::put(&mut self.txn, &mut self.db, &key, &value)?;
Ok(())
})?;
let cached_puts = mem::take(&mut self.cached_puts);
self.db_multi_put(cached_puts)?;
self.txn.set_root(ROOT_DB, self.db.db.into());
self.txn.commit()
}
}
#[derive(
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Deref, DerefMut, Default, Copy, Allocative,
)]
pub struct U8x19([u8; 19]);
direct_repr!(U8x19);
impl From<&[u8]> for U8x19 {
fn from(slice: &[u8]) -> Self {
let mut arr = Self::default();
arr.copy_from_slice(slice);
arr
fn defragment(self) {
Box::new(self).boxed_defragment()
}
fn boxed_defragment(self: Box<Self>) {
let btree = self.iter_collect();
let path = self.path.to_owned();
self.destroy();
let mut db = Self::open(path).unwrap();
if !db.is_empty() {
panic!()
}
db.cached_puts = btree;
db.export().unwrap();
}
fn destroy(self) {
let path = self.path.to_owned();
drop(self);
fs::remove_file(&path).unwrap_or_else(|_| {
dbg!(path);
panic!("Error");
});
}
}
#[derive(
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Deref, DerefMut, Default, Copy, Allocative,
)]
pub struct U8x31([u8; 31]);
direct_repr!(U8x31);
impl From<&[u8]> for U8x31 {
fn from(slice: &[u8]) -> Self {
let mut arr = Self::default();
arr.copy_from_slice(slice);
arr
}
}
pub fn databases_folder_path(folder: &str) -> String {
format!("{OUTPUTS_FOLDER_PATH}/databases/{folder}")
}
+27 -10
View File
@@ -1,35 +1,52 @@
use std::{fs, io};
use std::{fs, io, path::PathBuf};
use crate::{
io::OUTPUTS_FOLDER_PATH,
structs::{Date, Height},
utils::log,
};
use super::databases_folder_path;
use super::AnyDatabase;
pub trait AnyDatabaseGroup
where
Self: Sized,
{
fn init() -> Self {
let s = Self::import();
s.create_dir_all().unwrap();
s
}
fn import() -> Self;
fn export(&mut self, height: Height, date: Date) -> color_eyre::Result<()>;
fn folder<'a>() -> &'a str;
fn drain_to_vec(&mut self) -> Vec<Box<dyn AnyDatabase + Send>>;
fn open_all(&mut self);
fn export_metadata(&mut self, height: Height, date: Date) -> color_eyre::Result<()>;
fn create_dir_all(&self) -> color_eyre::Result<(), io::Error>;
fn remove_dir_all(&self) -> color_eyre::Result<(), io::Error> {
fs::remove_dir_all(Self::root())
}
fn reset(&mut self) -> color_eyre::Result<(), io::Error> {
log(&format!("Reset {}", Self::folder()));
self.reset_metadata();
fs::remove_dir_all(Self::full_path())?;
self.remove_dir_all()?;
self.create_dir_all()?;
Ok(())
}
fn full_path() -> String {
databases_folder_path(Self::folder())
}
fn reset_metadata(&mut self);
fn root() -> PathBuf {
let folder = Self::folder();
PathBuf::from(format!("{OUTPUTS_FOLDER_PATH}/databases/{folder}"))
}
}
@@ -5,14 +5,16 @@ use std::{
};
use allocative::Allocative;
use itertools::Itertools;
use rayon::prelude::*;
use crate::{
states::AddressCohortsDurableStates,
structs::{AddressData, Date, Height},
utils::time,
};
use super::{AnyDatabaseGroup, Database as _Database, Metadata};
use super::{AnyDatabase, AnyDatabaseGroup, Database as _Database, Metadata};
type Key = u32;
type Value = AddressData;
@@ -22,7 +24,7 @@ type Database = _Database<Key, Value>;
pub struct AddressIndexToAddressData {
pub metadata: Metadata,
map: BTreeMap<usize, Database>,
pub map: BTreeMap<usize, Database>,
}
impl Deref for AddressIndexToAddressData {
@@ -78,30 +80,69 @@ impl AddressIndexToAddressData {
(db_index + 1) * ADDRESS_INDEX_DB_MAX_SIZE
);
Database::open(Self::folder(), &db_name).unwrap()
let path = Self::root().join(db_name);
Database::open(path).unwrap()
})
}
pub fn iter<F>(&mut self, callback: &mut F)
where
F: FnMut((&Key, &Value)),
{
pub fn compute_addres_cohorts_durable_states(&mut self) -> AddressCohortsDurableStates {
time("Iter through address_index_to_address_data", || {
self.open_all();
// MUST CLEAR MAP, otherwise some weird shit in happening later in the export I think
// MUST CLEAR MAP, otherwise some weird things are happening later in the export I think
mem::take(&mut self.map)
.values()
.for_each(|database| database.iter(callback));
});
.par_iter()
.map(|(_, database)| {
let mut s = AddressCohortsDurableStates::default();
database
.iter()
.map(|r| r.unwrap().1)
.for_each(|address_data| s.increment(address_data).unwrap());
s
})
.sum()
})
}
fn db_index(key: &Key) -> usize {
*key as usize / ADDRESS_INDEX_DB_MAX_SIZE
}
}
impl AnyDatabaseGroup for AddressIndexToAddressData {
fn import() -> Self {
Self {
metadata: Metadata::import(Self::root(), 1),
map: BTreeMap::default(),
}
}
fn create_dir_all(&self) -> color_eyre::Result<(), std::io::Error> {
fs::create_dir_all(Self::root())
}
fn reset_metadata(&mut self) {
self.metadata.reset();
}
fn folder<'a>() -> &'a str {
"address_index_to_address_data"
}
fn open_all(&mut self) {
let path = Self::full_path();
let path = Self::root();
fs::create_dir_all(&path).unwrap();
let folder = fs::read_dir(path);
fs::read_dir(path)
if folder.is_err() {
return;
}
folder
.unwrap()
.map(|entry| {
entry
@@ -119,34 +160,14 @@ impl AddressIndexToAddressData {
});
}
fn db_index(key: &Key) -> usize {
*key as usize / ADDRESS_INDEX_DB_MAX_SIZE
}
}
impl AnyDatabaseGroup for AddressIndexToAddressData {
fn import() -> Self {
Self {
map: BTreeMap::default(),
metadata: Metadata::import(&Self::full_path()),
}
}
fn export(&mut self, height: Height, date: Date) -> color_eyre::Result<()> {
fn drain_to_vec(&mut self) -> Vec<Box<dyn AnyDatabase + Send>> {
mem::take(&mut self.map)
.into_par_iter()
.try_for_each(|(_, db)| db.export())?;
self.metadata.export(height, date).unwrap();
Ok(())
.into_values()
.map(|db| Box::new(db) as Box<dyn AnyDatabase + Send>)
.collect_vec()
}
fn reset_metadata(&mut self) {
self.metadata.reset();
}
fn folder<'a>() -> &'a str {
"address_index_to_address_data"
fn export_metadata(&mut self, height: Height, date: Date) -> color_eyre::Result<()> {
self.metadata.export(height, date)
}
}
@@ -1,15 +1,17 @@
use std::{
collections::BTreeMap,
mem,
fs, mem,
ops::{Deref, DerefMut},
};
use allocative::Allocative;
use rayon::prelude::*;
use itertools::Itertools;
use crate::structs::{Date, EmptyAddressData, Height};
use super::{AnyDatabaseGroup, Database as _Database, Metadata, ADDRESS_INDEX_DB_MAX_SIZE};
use super::{
AnyDatabase, AnyDatabaseGroup, Database as _Database, Metadata, ADDRESS_INDEX_DB_MAX_SIZE,
};
type Key = u32;
type Value = EmptyAddressData;
@@ -78,7 +80,9 @@ impl AddressIndexToEmptyAddressData {
(db_index + 1) * ADDRESS_INDEX_DB_MAX_SIZE
);
Database::open(Self::folder(), &db_name).unwrap()
let path = Self::root().join(db_name);
Database::open(path).unwrap()
})
}
@@ -90,19 +94,14 @@ impl AddressIndexToEmptyAddressData {
impl AnyDatabaseGroup for AddressIndexToEmptyAddressData {
fn import() -> Self {
Self {
metadata: Metadata::import(Self::root(), 1),
map: BTreeMap::default(),
metadata: Metadata::import(&Self::full_path()),
}
}
fn export(&mut self, height: Height, date: Date) -> color_eyre::Result<()> {
mem::take(&mut self.map)
.into_par_iter()
.try_for_each(|(_, db)| db.export())?;
self.metadata.export(height, date)?;
Ok(())
fn create_dir_all(&self) -> color_eyre::Result<(), std::io::Error> {
fs::create_dir_all(Self::root())
}
fn reset_metadata(&mut self) {
@@ -112,4 +111,42 @@ impl AnyDatabaseGroup for AddressIndexToEmptyAddressData {
fn folder<'a>() -> &'a str {
"address_index_to_empty_address_data"
}
fn open_all(&mut self) {
let path = Self::root();
let folder = fs::read_dir(path);
if folder.is_err() {
return;
}
folder
.unwrap()
.map(|entry| {
entry
.unwrap()
.path()
.file_name()
.unwrap()
.to_str()
.unwrap()
.to_owned()
})
.filter(|file_name| file_name.contains(".."))
.for_each(|path| {
self.open_db(&path.split("..").next().unwrap().parse::<u32>().unwrap());
});
}
fn drain_to_vec(&mut self) -> Vec<Box<dyn AnyDatabase + Send>> {
mem::take(&mut self.map)
.into_values()
.map(|db| Box::new(db) as Box<dyn AnyDatabase + Send>)
.collect_vec()
}
fn export_metadata(&mut self, height: Height, date: Date) -> color_eyre::Result<()> {
self.metadata.export(height, date)
}
}
+223 -91
View File
@@ -1,11 +1,15 @@
use std::{collections::BTreeMap, mem, thread};
use std::{
collections::BTreeMap,
fs, mem,
path::{Path, PathBuf},
};
use allocative::Allocative;
use rayon::prelude::*;
use itertools::Itertools;
use crate::structs::{Address, Date, Height};
use crate::structs::{Address, Date, Height, U8x19, U8x31};
use super::{AnyDatabaseGroup, Database, Metadata, U8x19, U8x31};
use super::{AnyDatabase, AnyDatabaseGroup, Database, Metadata};
type Value = u32;
type U8x19Database = Database<U8x19, Value>;
@@ -42,20 +46,6 @@ pub struct AddressToAddressIndex {
}
impl AddressToAddressIndex {
// pub fn safe_get(&mut self, address: &Address) -> Option<&Value> {
// match address {
// Address::Empty(key) => self.open_empty().get(key),
// Address::Unknown(key) => self.open_unknown().get(key),
// Address::MultiSig(key) => self.open_multisig().get(key),
// Address::P2PK((prefix, rest)) => self.open_p2pk(*prefix).get(rest),
// Address::P2PKH((prefix, rest)) => self.open_p2pkh(*prefix).get(rest),
// Address::P2SH((prefix, rest)) => self.open_p2sh(*prefix).get(rest),
// Address::P2WPKH((prefix, rest)) => self.open_p2wpkh(*prefix).get(rest),
// Address::P2WSH((prefix, rest)) => self.open_p2wsh(*prefix).get(rest),
// Address::P2TR((prefix, rest)) => self.open_p2tr(*prefix).get(rest),
// }
// }
pub fn open_db(&mut self, address: &Address) {
match address {
Address::Empty(_) => {
@@ -146,95 +136,210 @@ impl AddressToAddressIndex {
}
}
pub fn open_p2pk(&mut self, prefix: u16) -> &mut P2PKDatabase {
self.p2pk.entry(prefix).or_insert_with(|| {
Database::open(
&format!("{}/{}", Self::folder(), "p2pk"),
&prefix.to_string(),
)
fn path_to_group_prefixes(path: &Path) -> Vec<u16> {
let folder = fs::read_dir(path);
if folder.is_err() {
return vec![];
}
folder
.unwrap()
.map(|entry| {
entry
.unwrap()
.path()
.file_name()
.unwrap()
.to_str()
.unwrap()
.to_owned()
.parse::<u16>()
.unwrap()
})
.collect_vec()
}
fn path_p2pk() -> PathBuf {
Self::root().join("p2pk")
}
pub fn open_p2pk(&mut self, prefix: u16) -> &mut P2PKDatabase {
let path = Self::path_p2pk();
self.p2pk.entry(prefix).or_insert_with(|| {
let path = path.join(prefix.to_string());
Database::open(path).unwrap()
})
}
fn open_all_p2pk(&mut self) {
let path = Self::path_p2pk();
Self::path_to_group_prefixes(&path)
.into_iter()
.for_each(|prefix| {
self.p2pk.insert(prefix, {
let path = path.join(prefix.to_string());
Database::open(path).unwrap()
});
});
}
fn path_p2pkh() -> PathBuf {
Self::root().join("p2pkh")
}
pub fn open_p2pkh(&mut self, prefix: u16) -> &mut P2PKHDatabase {
let path = Self::path_p2pkh();
self.p2pkh.entry(prefix).or_insert_with(|| {
Database::open(
&format!("{}/{}", Self::folder(), "p2pkh"),
&prefix.to_string(),
)
.unwrap()
let path = path.join(prefix.to_string());
Database::open(path).unwrap()
})
}
fn open_all_p2pkh(&mut self) {
let path = Self::path_p2pkh();
Self::path_to_group_prefixes(&path)
.into_iter()
.for_each(|prefix| {
self.p2pkh.insert(prefix, {
let path = path.join(prefix.to_string());
Database::open(path).unwrap()
});
});
}
fn path_p2sh() -> PathBuf {
Self::root().join("p2sh")
}
pub fn open_p2sh(&mut self, prefix: u16) -> &mut P2SHDatabase {
let path = Self::path_p2sh();
self.p2sh.entry(prefix).or_insert_with(|| {
Database::open(
&format!("{}/{}", Self::folder(), "p2sh"),
&prefix.to_string(),
)
.unwrap()
let path = path.join(prefix.to_string());
Database::open(path).unwrap()
})
}
fn open_all_p2sh(&mut self) {
let path = Self::path_p2sh();
Self::path_to_group_prefixes(&path)
.into_iter()
.for_each(|prefix| {
self.p2sh.insert(prefix, {
let path = path.join(prefix.to_string());
Database::open(path).unwrap()
});
});
}
fn path_p2wpkh() -> PathBuf {
Self::root().join("p2wpkh")
}
pub fn open_p2wpkh(&mut self, prefix: u16) -> &mut P2WPKHDatabase {
let path = Self::path_p2wpkh();
self.p2wpkh.entry(prefix).or_insert_with(|| {
Database::open(
&format!("{}/{}", Self::folder(), "p2wpkh"),
&prefix.to_string(),
)
.unwrap()
let path = path.join(prefix.to_string());
Database::open(path).unwrap()
})
}
fn open_all_p2wpkh(&mut self) {
let path = Self::path_p2wpkh();
Self::path_to_group_prefixes(&path)
.into_iter()
.for_each(|prefix| {
self.p2wpkh.insert(prefix, {
let path = path.join(prefix.to_string());
Database::open(path).unwrap()
});
});
}
fn path_p2wsh() -> PathBuf {
Self::root().join("p2wsh")
}
pub fn open_p2wsh(&mut self, prefix: u16) -> &mut P2WSHDatabase {
let path = Self::path_p2wsh();
self.p2wsh.entry(prefix).or_insert_with(|| {
Database::open(
&format!("{}/{}", Self::folder(), "p2wsh"),
&prefix.to_string(),
)
.unwrap()
let path = path.join(prefix.to_string());
Database::open(path).unwrap()
})
}
fn open_all_p2wsh(&mut self) {
let path = Self::path_p2wsh();
Self::path_to_group_prefixes(&path)
.into_iter()
.for_each(|prefix| {
self.p2wsh.insert(prefix, {
let path = path.join(prefix.to_string());
Database::open(path).unwrap()
});
});
}
fn path_p2tr() -> PathBuf {
Self::root().join("p2tr")
}
pub fn open_p2tr(&mut self, prefix: u16) -> &mut P2TRDatabase {
let path = Self::path_p2tr();
self.p2tr.entry(prefix).or_insert_with(|| {
Database::open(
&format!("{}/{}", Self::folder(), "p2tr"),
&prefix.to_string(),
)
.unwrap()
let path = path.join(prefix.to_string());
Database::open(path).unwrap()
})
}
fn open_all_p2tr(&mut self) {
let path = Self::path_p2tr();
Self::path_to_group_prefixes(&path)
.into_iter()
.for_each(|prefix| {
self.p2tr.insert(prefix, {
let path = path.join(prefix.to_string());
Database::open(path).unwrap()
});
});
}
pub fn open_unknown(&mut self) -> &mut UnknownDatabase {
self.unknown
.get_or_insert_with(|| Database::open(Self::folder(), "unknown").unwrap())
.get_or_insert_with(|| Database::open(Self::root().join("unknown")).unwrap())
}
pub fn open_op_return(&mut self) -> &mut UnknownDatabase {
self.op_return
.get_or_insert_with(|| Database::open(Self::folder(), "op_return").unwrap())
.get_or_insert_with(|| Database::open(Self::root().join("op_return")).unwrap())
}
pub fn open_push_only(&mut self) -> &mut UnknownDatabase {
self.push_only
.get_or_insert_with(|| Database::open(Self::folder(), "push_only").unwrap())
.get_or_insert_with(|| Database::open(Self::root().join("push_only")).unwrap())
}
pub fn open_empty(&mut self) -> &mut UnknownDatabase {
self.empty
.get_or_insert_with(|| Database::open(Self::folder(), "empty").unwrap())
.get_or_insert_with(|| Database::open(Self::root().join("empty")).unwrap())
}
pub fn open_multisig(&mut self) -> &mut MultisigDatabase {
self.multisig
.get_or_insert_with(|| Database::open(Self::folder(), "multisig").unwrap())
.get_or_insert_with(|| Database::open(Self::root().join("multisig")).unwrap())
}
}
impl AnyDatabaseGroup for AddressToAddressIndex {
fn import() -> Self {
Self {
metadata: Metadata::import(Self::root(), 1),
p2pk: BTreeMap::default(),
p2pkh: BTreeMap::default(),
p2sh: BTreeMap::default(),
@@ -246,46 +351,16 @@ impl AnyDatabaseGroup for AddressToAddressIndex {
unknown: None,
empty: None,
multisig: None,
metadata: Metadata::import(&Self::full_path()),
}
}
fn export(&mut self, height: Height, date: Date) -> color_eyre::Result<()> {
thread::scope(|s| {
s.spawn(|| {
mem::take(&mut self.p2pk)
.into_par_iter()
.chain(mem::take(&mut self.p2pkh).into_par_iter())
.chain(mem::take(&mut self.p2sh).into_par_iter())
.chain(mem::take(&mut self.p2wpkh).into_par_iter())
.try_for_each(|(_, db)| db.export())
});
s.spawn(|| {
mem::take(&mut self.p2wsh)
.into_par_iter()
.chain(mem::take(&mut self.p2tr).into_par_iter())
.try_for_each(|(_, db)| db.export())
});
s.spawn(|| {
[
self.unknown.take(),
self.op_return.take(),
self.push_only.take(),
self.empty.take(),
]
.into_par_iter()
.flatten()
.try_for_each(|db| db.export())
});
self.multisig.take().map(|db| db.export());
});
self.metadata.export(height, date)?;
Ok(())
fn create_dir_all(&self) -> color_eyre::Result<(), std::io::Error> {
fs::create_dir_all(Self::path_p2pk()).unwrap();
fs::create_dir_all(Self::path_p2pkh()).unwrap();
fs::create_dir_all(Self::path_p2sh()).unwrap();
fs::create_dir_all(Self::path_p2wpkh()).unwrap();
fs::create_dir_all(Self::path_p2wsh()).unwrap();
fs::create_dir_all(Self::path_p2tr())
}
fn reset_metadata(&mut self) {
@@ -295,4 +370,61 @@ impl AnyDatabaseGroup for AddressToAddressIndex {
fn folder<'a>() -> &'a str {
"address_to_address_index"
}
fn drain_to_vec(&mut self) -> Vec<Box<dyn AnyDatabase + Send>> {
mem::take(&mut self.p2pk)
.into_values()
.map(|db| Box::new(db) as Box<dyn AnyDatabase + Send>)
.chain(
mem::take(&mut self.p2pkh)
.into_values()
.map(|db| Box::new(db) as Box<dyn AnyDatabase + Send>),
)
.chain(
mem::take(&mut self.p2sh)
.into_values()
.map(|db| Box::new(db) as Box<dyn AnyDatabase + Send>),
)
.chain(
mem::take(&mut self.p2wpkh)
.into_values()
.map(|db| Box::new(db) as Box<dyn AnyDatabase + Send>),
)
.chain(
mem::take(&mut self.p2wsh)
.into_values()
.map(|db| Box::new(db) as Box<dyn AnyDatabase + Send>),
)
.chain(
mem::take(&mut self.p2tr)
.into_values()
.map(|db| Box::new(db) as Box<dyn AnyDatabase + Send>),
)
.chain(
[
self.unknown.take(),
self.op_return.take(),
self.push_only.take(),
self.empty.take(),
self.multisig.take(),
]
.into_iter()
.flatten()
.map(|db| Box::new(db) as Box<dyn AnyDatabase + Send>),
)
.collect_vec()
}
fn open_all(&mut self) {
self.open_all_p2pk();
self.open_all_p2pkh();
self.open_all_p2wpkh();
self.open_all_p2wsh();
self.open_all_p2sh();
self.open_all_p2tr();
}
fn export_metadata(&mut self, height: Height, date: Date) -> color_eyre::Result<()> {
self.metadata.export(height, date)
}
}
+23 -14
View File
@@ -1,11 +1,12 @@
use allocative::Allocative;
use bincode::{Decode, Encode};
use color_eyre::eyre::eyre;
use serde::{Deserialize, Serialize};
use std::{
fmt::Debug,
fs, io,
ops::{Deref, DerefMut},
path::Path,
path::{Path, PathBuf},
};
use crate::{
@@ -15,7 +16,7 @@ use crate::{
#[derive(Default, Debug, Encode, Decode, Allocative)]
pub struct Metadata {
path: String,
path: PathBuf,
data: MetadataData,
}
@@ -34,10 +35,10 @@ impl DerefMut for Metadata {
}
impl Metadata {
pub fn import(path: &str) -> Self {
pub fn import(path: PathBuf, version: u16) -> Self {
Self {
path: path.to_owned(),
data: MetadataData::import(path).unwrap_or_default(),
data: MetadataData::import(&path, version),
path,
}
}
@@ -77,6 +78,7 @@ impl Metadata {
#[derive(Default, Debug, Encode, Decode, Serialize, Deserialize, Allocative)]
pub struct MetadataData {
version: u16,
pub serial: usize,
pub len: Counter,
pub last_height: Option<Height>,
@@ -84,26 +86,33 @@ pub struct MetadataData {
}
impl MetadataData {
fn name<'a>() -> &'a str {
"metadata"
fn full_path(folder_path: &Path) -> PathBuf {
folder_path.join("metadata")
}
fn full_path(folder_path: &str) -> String {
let name = Self::name();
format!("{folder_path}/{name}")
pub fn import(path: &Path, version: u16) -> Self {
let mut s = Self::_import(path, version).unwrap_or_default();
s.version = version;
s
}
pub fn import(path: &str) -> color_eyre::Result<Self> {
fn _import(path: &Path, version: u16) -> color_eyre::Result<Self> {
fs::create_dir_all(path)?;
Serialization::Binary.import(Path::new(&Self::full_path(path)))
let s: MetadataData = Serialization::Binary.import(&Self::full_path(path))?;
if s.version != version {
return Err(eyre!("Bad version"));
}
Ok(s)
}
pub fn export(&self, path: &str) -> color_eyre::Result<()> {
pub fn export(&self, path: &Path) -> color_eyre::Result<()> {
Serialization::Binary.export(Path::new(&Self::full_path(path)), self)
}
pub fn reset(&mut self, path: &str) -> color_eyre::Result<(), io::Error> {
pub fn reset(&mut self, path: &Path) -> color_eyre::Result<(), io::Error> {
self.clear();
fs::remove_file(Self::full_path(path))
+86 -45
View File
@@ -17,14 +17,18 @@ use _trait::*;
pub use address_index_to_address_data::*;
pub use address_index_to_empty_address_data::*;
pub use address_to_address_index::*;
use itertools::Itertools;
use metadata::*;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
pub use txid_to_tx_data::*;
pub use txout_index_to_address_index::*;
pub use txout_index_to_amount::*;
use crate::{
log,
structs::{Date, Height},
utils::time,
Exit,
};
#[derive(Allocative)]
@@ -39,17 +43,17 @@ pub struct Databases {
impl Databases {
pub fn import() -> Self {
let address_index_to_address_data = AddressIndexToAddressData::import();
let address_index_to_address_data = AddressIndexToAddressData::init();
let address_index_to_empty_address_data = AddressIndexToEmptyAddressData::import();
let address_index_to_empty_address_data = AddressIndexToEmptyAddressData::init();
let address_to_address_index = AddressToAddressIndex::import();
let address_to_address_index = AddressToAddressIndex::init();
let txid_to_tx_data = TxidToTxData::import();
let txid_to_tx_data = TxidToTxData::init();
let txout_index_to_address_index = TxoutIndexToAddressIndex::import();
let txout_index_to_address_index = TxoutIndexToAddressIndex::init();
let txout_index_to_amount = TxoutIndexToAmount::import();
let txout_index_to_amount = TxoutIndexToAmount::init();
Self {
address_index_to_address_data,
@@ -61,51 +65,88 @@ impl Databases {
}
}
pub fn drain_to_vec(&mut self) -> Vec<Box<dyn AnyDatabase + Send>> {
self.txid_to_tx_data
.drain_to_vec()
.into_iter()
.chain(self.txout_index_to_amount.drain_to_vec())
.chain(self.address_to_address_index.drain_to_vec())
.chain(self.address_index_to_address_data.drain_to_vec())
.chain(self.address_index_to_empty_address_data.drain_to_vec())
.chain(self.txout_index_to_address_index.drain_to_vec())
.collect_vec()
}
fn export_metadata(&mut self, height: Height, date: Date) -> color_eyre::Result<()> {
self.txid_to_tx_data.export_metadata(height, date)?;
self.txout_index_to_amount.export_metadata(height, date)?;
self.address_index_to_address_data
.export_metadata(height, date)?;
self.address_index_to_empty_address_data
.export_metadata(height, date)?;
self.address_to_address_index
.export_metadata(height, date)?;
self.txout_index_to_address_index
.export_metadata(height, date)?;
Ok(())
}
pub fn export(&mut self, height: Height, date: Date) -> color_eyre::Result<()> {
thread::scope(|s| {
s.spawn(|| {
time("> Database txid_to_tx_data", || {
self.txid_to_tx_data.export(height, date)
})
});
self.export_metadata(height, date)?;
s.spawn(|| {
time("> Database txout_index_to_amount", || {
self.txout_index_to_amount.export(height, date)
})
});
});
thread::scope(|s| {
s.spawn(|| {
time("> Database address_index_to_address_data", || {
self.address_index_to_address_data.export(height, date)
})
});
s.spawn(|| {
time("> Database address_index_to_empty_address_data", || {
self.address_index_to_empty_address_data
.export(height, date)
})
});
s.spawn(|| {
time("> Database address_to_address_index", || {
self.address_to_address_index.export(height, date)
})
});
s.spawn(|| {
time("> Database txout_index_to_address_index", || {
self.txout_index_to_address_index.export(height, date)
})
});
});
self.drain_to_vec()
.into_par_iter()
.try_for_each(AnyDatabase::boxed_export)?;
Ok(())
}
fn open_all(&mut self) {
thread::scope(|s| {
s.spawn(|| {
self.address_index_to_address_data.open_all();
});
s.spawn(|| {
self.address_index_to_empty_address_data.open_all();
});
s.spawn(|| {
self.address_to_address_index.open_all();
});
s.spawn(|| {
self.txid_to_tx_data.open_all();
});
s.spawn(|| {
self.txout_index_to_address_index.open_all();
});
s.spawn(|| {
self.txout_index_to_amount.open_all();
});
});
}
pub fn defragment(&mut self, exit: &Exit) {
exit.block();
log("Databases defragmentation");
time("Defragmenting databases", || {
time("Opened all databases", || self.open_all());
log("Defragmenting...");
self.drain_to_vec()
.into_par_iter()
.for_each(AnyDatabase::boxed_defragment);
});
exit.unblock();
}
pub fn reset(&mut self, include_addresses: bool) {
if include_addresses {
let _ = self.address_index_to_address_data.reset();
+56 -16
View File
@@ -1,16 +1,16 @@
use std::{
collections::BTreeMap,
mem,
fs, mem,
ops::{Deref, DerefMut},
};
use allocative::Allocative;
use biter::bitcoin::Txid;
use rayon::prelude::*;
use itertools::Itertools;
use crate::structs::{Date, Height, TxData};
use crate::structs::{Date, Height, TxData, U8x31};
use super::{AnyDatabaseGroup, Database as _Database, Metadata, U8x31};
use super::{AnyDatabase, AnyDatabaseGroup, Database as _Database, Metadata};
type Key = U8x31;
type Value = TxData;
@@ -104,9 +104,15 @@ impl TxidToTxData {
#[inline(always)]
pub fn open_db(&mut self, txid: &Txid) -> &mut Database {
let db_index = Self::db_index(txid);
self._open_db(db_index)
}
self.entry(db_index)
.or_insert_with(|| Database::open(Self::folder(), &db_index.to_string()).unwrap())
#[inline(always)]
pub fn _open_db(&mut self, db_index: u16) -> &mut Database {
self.entry(db_index).or_insert_with(|| {
let path = Self::root().join(db_index.to_string());
Database::open(path).unwrap()
})
}
fn txid_to_key(txid: &Txid) -> U8x31 {
@@ -114,26 +120,22 @@ impl TxidToTxData {
}
fn db_index(txid: &Txid) -> u16 {
((txid[0] as u16) << 4) + ((txid[1] as u16) >> 4)
((txid[0] as u16) << 5) + ((txid[1] as u16) >> 3)
}
}
impl AnyDatabaseGroup for TxidToTxData {
fn import() -> Self {
let metadata = Metadata::import(Self::root(), 2);
Self {
metadata,
map: BTreeMap::default(),
metadata: Metadata::import(&Self::full_path()),
}
}
fn export(&mut self, height: Height, date: Date) -> color_eyre::Result<()> {
mem::take(&mut self.map)
.into_par_iter()
.try_for_each(|(_, db)| db.export())?;
self.metadata.export(height, date)?;
Ok(())
fn create_dir_all(&self) -> color_eyre::Result<(), std::io::Error> {
fs::create_dir_all(Self::root())
}
fn reset_metadata(&mut self) {
@@ -143,4 +145,42 @@ impl AnyDatabaseGroup for TxidToTxData {
fn folder<'a>() -> &'a str {
"txid_to_tx_data"
}
fn open_all(&mut self) {
let path = Self::root();
let folder = fs::read_dir(path);
if folder.is_err() {
return;
}
folder
.unwrap()
.flat_map(|entry| {
entry
.unwrap()
.path()
.file_name()
.unwrap()
.to_str()
.unwrap()
.to_owned()
.parse::<u16>()
})
.for_each(|db_index| {
self._open_db(db_index);
});
}
fn drain_to_vec(&mut self) -> Vec<Box<dyn AnyDatabase + Send>> {
mem::take(&mut self.map)
.into_values()
.map(|db| Box::new(db) as Box<dyn AnyDatabase + Send>)
.collect_vec()
}
fn export_metadata(&mut self, height: Height, date: Date) -> color_eyre::Result<()> {
self.metadata.export(height, date)
}
}
@@ -1,15 +1,15 @@
use std::{
collections::BTreeMap,
mem,
fs, mem,
ops::{Deref, DerefMut},
};
use allocative::Allocative;
use rayon::prelude::*;
use itertools::Itertools;
use crate::structs::{Date, Height, TxoutIndex};
use super::{AnyDatabaseGroup, Database as _Database, Metadata};
use super::{AnyDatabase, AnyDatabaseGroup, Database as _Database, Metadata};
type Key = TxoutIndex;
type Value = u32;
@@ -77,7 +77,9 @@ impl TxoutIndexToAddressIndex {
(db_index + 1) * DB_MAX_SIZE
);
Database::open(Self::folder(), &db_name).unwrap()
let path = Self::root().join(db_name);
Database::open(path).unwrap()
})
}
@@ -89,19 +91,14 @@ impl TxoutIndexToAddressIndex {
impl AnyDatabaseGroup for TxoutIndexToAddressIndex {
fn import() -> Self {
Self {
metadata: Metadata::import(Self::root(), 1),
map: BTreeMap::default(),
metadata: Metadata::import(&Self::full_path()),
}
}
fn export(&mut self, height: Height, date: Date) -> color_eyre::Result<()> {
mem::take(&mut self.map)
.into_par_iter()
.try_for_each(|(_, db)| db.export())?;
self.metadata.export(height, date)?;
Ok(())
fn create_dir_all(&self) -> color_eyre::Result<(), std::io::Error> {
fs::create_dir_all(Self::root())
}
fn reset_metadata(&mut self) {
@@ -111,4 +108,50 @@ impl AnyDatabaseGroup for TxoutIndexToAddressIndex {
fn folder<'a>() -> &'a str {
"txout_index_to_address_index"
}
fn open_all(&mut self) {
let path = Self::root();
let folder = fs::read_dir(path);
if folder.is_err() {
return;
}
folder
.unwrap()
.map(|entry| {
entry
.unwrap()
.path()
.file_name()
.unwrap()
.to_str()
.unwrap()
.to_owned()
})
.filter(|file_name| file_name.contains(".."))
.for_each(|path| {
self.open_db(
&path
.split("..")
.next()
.unwrap()
.parse::<u64>()
.unwrap()
.into(),
);
});
}
fn drain_to_vec(&mut self) -> Vec<Box<dyn AnyDatabase + Send>> {
mem::take(&mut self.map)
.into_values()
.map(|db| Box::new(db) as Box<dyn AnyDatabase + Send>)
.collect_vec()
}
fn export_metadata(&mut self, height: Height, date: Date) -> color_eyre::Result<()> {
self.metadata.export(height, date)
}
}
+57 -14
View File
@@ -1,15 +1,15 @@
use std::{
collections::BTreeMap,
mem,
fs, mem,
ops::{Deref, DerefMut},
};
use allocative::Allocative;
use rayon::prelude::*;
use itertools::Itertools;
use crate::structs::{Amount, Date, Height, TxoutIndex};
use super::{AnyDatabaseGroup, Database as _Database, Metadata};
use super::{AnyDatabase, AnyDatabaseGroup, Database as _Database, Metadata};
type Key = TxoutIndex;
type Value = Amount;
@@ -19,7 +19,7 @@ type Database = _Database<Key, Value>;
pub struct TxoutIndexToAmount {
pub metadata: Metadata,
pub map: BTreeMap<usize, Database>,
map: BTreeMap<usize, Database>,
}
impl Deref for TxoutIndexToAmount {
@@ -77,7 +77,9 @@ impl TxoutIndexToAmount {
(db_index + 1) * DB_MAX_SIZE
);
Database::open(Self::folder(), &db_name).unwrap()
let path = Self::root().join(db_name);
Database::open(path).unwrap()
})
}
@@ -89,19 +91,14 @@ impl TxoutIndexToAmount {
impl AnyDatabaseGroup for TxoutIndexToAmount {
fn import() -> Self {
Self {
metadata: Metadata::import(Self::root(), 1),
map: BTreeMap::default(),
metadata: Metadata::import(&Self::full_path()),
}
}
fn export(&mut self, height: Height, date: Date) -> color_eyre::Result<()> {
mem::take(&mut self.map)
.into_par_iter()
.try_for_each(|(_, db)| db.export())?;
self.metadata.export(height, date)?;
Ok(())
fn create_dir_all(&self) -> color_eyre::Result<(), std::io::Error> {
fs::create_dir_all(Self::root())
}
fn reset_metadata(&mut self) {
@@ -111,4 +108,50 @@ impl AnyDatabaseGroup for TxoutIndexToAmount {
fn folder<'a>() -> &'a str {
"txout_index_to_amount"
}
fn open_all(&mut self) {
let path = Self::root();
let folder = fs::read_dir(path);
if folder.is_err() {
return;
}
folder
.unwrap()
.map(|entry| {
entry
.unwrap()
.path()
.file_name()
.unwrap()
.to_str()
.unwrap()
.to_owned()
})
.filter(|file_name| file_name.contains(".."))
.for_each(|path| {
self.open_db(
&path
.split("..")
.next()
.unwrap()
.parse::<u64>()
.unwrap()
.into(),
);
});
}
fn drain_to_vec(&mut self) -> Vec<Box<dyn AnyDatabase + Send>> {
mem::take(&mut self.map)
.into_values()
.map(|db| Box::new(db) as Box<dyn AnyDatabase + Send>)
.collect_vec()
}
fn export_metadata(&mut self, height: Height, date: Date) -> color_eyre::Result<()> {
self.metadata.export(height, date)
}
}
+617 -16
View File
@@ -1,14 +1,21 @@
use itertools::Itertools;
use rayon::prelude::*;
use struct_iterable::Iterable;
use crate::{
datasets::ComputeData,
structs::{AnyBiMap, AnyDateMap, AnyHeightMap, AnyMap, Date, Height},
datasets::{
cohort_metadata::AddressCohortMetadataDataset, ComputeData, DateRecapDataset, RatioDataset,
SubDataset,
},
structs::{
AnyBiMap, AnyDateMap, AnyHeightMap, AnyMap, BiMap, Date, Height, MapKind, Timestamp, OHLC,
},
DateMap, HeightMap,
};
use super::MinInitialStates;
use super::{AnyDatasetGroup, MinInitialStates};
pub trait AnyDataset {
pub trait AnyDataset: Iterable {
fn get_min_initial_states(&self) -> &MinInitialStates;
fn needs_insert(&self, height: Height, date: Date) -> bool {
@@ -38,28 +45,613 @@ pub trait AnyDataset {
})
}
fn to_kind_bi_map_vec(&self, kind: MapKind) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
let mut v = vec![];
self.iter().for_each(|(_, any)| {
if let Some(map) = any.downcast_ref::<BiMap<u8>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyBiMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<BiMap<u16>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyBiMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<BiMap<u32>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyBiMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<BiMap<u64>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyBiMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<BiMap<usize>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyBiMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<BiMap<f32>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyBiMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<BiMap<f64>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyBiMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<BiMap<OHLC>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyBiMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<BiMap<Date>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyBiMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<BiMap<Height>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyBiMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<BiMap<Timestamp>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyBiMap + Send + Sync))
}
} else if let Some(dataset) = any.downcast_ref::<RatioDataset>() {
match kind {
MapKind::Inserted => dataset.to_inserted_bi_map_vec(),
MapKind::Computed => dataset.to_computed_bi_map_vec(),
}
.into_iter()
.for_each(|map| {
v.push(map);
});
} else if let Some(dataset) = any.downcast_ref::<AddressCohortMetadataDataset>() {
match kind {
MapKind::Inserted => dataset.to_inserted_bi_map_vec(),
MapKind::Computed => dataset.to_computed_bi_map_vec(),
}
.into_iter()
.for_each(|map| {
v.push(map);
});
} else if let Some(dataset) = any.downcast_ref::<SubDataset>() {
dataset.as_vec().into_iter().for_each(|dataset| {
v.append(&mut dataset.to_kind_bi_map_vec(kind));
});
}
});
v
}
fn to_kind_mut_bi_map_vec(&mut self, kind: MapKind) -> Vec<&mut dyn AnyBiMap> {
let mut v = vec![];
self.iter_mut().for_each(|(_, any)| match any {
any if any.is::<BiMap<u8>>() => {
if let Some(map) = any.downcast_mut::<BiMap<u8>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyBiMap);
}
}
}
any if any.is::<BiMap<u16>>() => {
if let Some(map) = any.downcast_mut::<BiMap<u16>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyBiMap);
}
}
}
any if any.is::<BiMap<u32>>() => {
if let Some(map) = any.downcast_mut::<BiMap<u32>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyBiMap);
}
}
}
any if any.is::<BiMap<u64>>() => {
if let Some(map) = any.downcast_mut::<BiMap<u64>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyBiMap);
}
}
}
any if any.is::<BiMap<usize>>() => {
if let Some(map) = any.downcast_mut::<BiMap<usize>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyBiMap);
}
}
}
any if any.is::<BiMap<f32>>() => {
if let Some(map) = any.downcast_mut::<BiMap<f32>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyBiMap);
}
}
}
any if any.is::<BiMap<f64>>() => {
if let Some(map) = any.downcast_mut::<BiMap<f64>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyBiMap);
}
}
}
any if any.is::<BiMap<OHLC>>() => {
if let Some(map) = any.downcast_mut::<BiMap<OHLC>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyBiMap);
}
}
}
any if any.is::<BiMap<Date>>() => {
if let Some(map) = any.downcast_mut::<BiMap<Date>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyBiMap);
}
}
}
any if any.is::<BiMap<Height>>() => {
if let Some(map) = any.downcast_mut::<BiMap<Height>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyBiMap);
}
}
}
any if any.is::<BiMap<Timestamp>>() => {
if let Some(map) = any.downcast_mut::<BiMap<Timestamp>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyBiMap);
}
}
}
any if any.is::<RatioDataset>() => {
if let Some(dataset) = any.downcast_mut::<RatioDataset>() {
match kind {
MapKind::Inserted => dataset.to_inserted_mut_bi_map_vec(),
MapKind::Computed => dataset.to_computed_mut_bi_map_vec(),
}
.into_iter()
.for_each(|map| {
v.push(map);
});
}
}
any if any.is::<AddressCohortMetadataDataset>() => {
if let Some(dataset) = any.downcast_mut::<AddressCohortMetadataDataset>() {
match kind {
MapKind::Inserted => dataset.to_inserted_mut_bi_map_vec(),
MapKind::Computed => dataset.to_computed_mut_bi_map_vec(),
}
.into_iter()
.for_each(|map| {
v.push(map);
});
}
}
any if any.is::<SubDataset>() => {
if let Some(dataset) = any.downcast_mut::<SubDataset>() {
dataset.as_mut_vec().into_iter().for_each(|dataset| {
v.append(&mut dataset.to_kind_mut_bi_map_vec(kind));
});
}
}
_ => {}
});
v
}
fn to_kind_date_map_vec(&self, kind: MapKind) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
let mut v = vec![];
self.iter().for_each(|(_, any)| {
if let Some(map) = any.downcast_ref::<DateMap<u8>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyDateMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<DateMap<u16>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyDateMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<DateMap<u32>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyDateMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<DateMap<u64>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyDateMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<DateMap<usize>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyDateMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<DateMap<f32>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyDateMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<DateMap<f64>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyDateMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<DateMap<OHLC>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyDateMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<DateMap<Date>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyDateMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<DateMap<Height>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyDateMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<DateMap<Timestamp>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyDateMap + Send + Sync))
}
} else if let Some(dataset) = any.downcast_ref::<DateRecapDataset<u32>>() {
dataset.as_vec().into_iter().for_each(|map| {
if map.kind() == kind {
v.push(map as &(dyn AnyDateMap + Send + Sync))
}
});
} else if let Some(dataset) = any.downcast_ref::<DateRecapDataset<u64>>() {
dataset.as_vec().into_iter().for_each(|map| {
if map.kind() == kind {
v.push(map as &(dyn AnyDateMap + Send + Sync))
}
});
} else if let Some(dataset) = any.downcast_ref::<DateRecapDataset<f32>>() {
dataset.as_vec().into_iter().for_each(|map| {
if map.kind() == kind {
v.push(map as &(dyn AnyDateMap + Send + Sync))
}
});
} else if let Some(dataset) = any.downcast_ref::<SubDataset>() {
dataset.as_vec().into_iter().for_each(|dataset| {
v.append(&mut dataset.to_kind_date_map_vec(kind));
});
} else if let Some(dataset) = any.downcast_ref::<AddressCohortMetadataDataset>() {
match kind {
MapKind::Inserted => dataset.to_inserted_date_map_vec(),
MapKind::Computed => dataset.to_computed_date_map_vec(),
}
.into_iter()
.for_each(|map| {
v.push(map);
});
}
});
v
}
fn to_kind_mut_date_map_vec(&mut self, kind: MapKind) -> Vec<&mut dyn AnyDateMap> {
let mut v = vec![];
self.iter_mut().for_each(|(_, any)| match any {
any if any.is::<DateMap<u8>>() => {
if let Some(map) = any.downcast_mut::<DateMap<u8>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyDateMap);
}
}
}
any if any.is::<DateMap<u16>>() => {
if let Some(map) = any.downcast_mut::<DateMap<u16>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyDateMap);
}
}
}
any if any.is::<DateMap<u32>>() => {
if let Some(map) = any.downcast_mut::<DateMap<u32>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyDateMap);
}
}
}
any if any.is::<DateMap<u64>>() => {
if let Some(map) = any.downcast_mut::<DateMap<u64>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyDateMap);
}
}
}
any if any.is::<DateMap<usize>>() => {
if let Some(map) = any.downcast_mut::<DateMap<usize>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyDateMap);
}
}
}
any if any.is::<DateMap<f32>>() => {
if let Some(map) = any.downcast_mut::<DateMap<f32>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyDateMap);
}
}
}
any if any.is::<DateMap<f64>>() => {
if let Some(map) = any.downcast_mut::<DateMap<f64>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyDateMap);
}
}
}
any if any.is::<DateMap<OHLC>>() => {
if let Some(map) = any.downcast_mut::<DateMap<OHLC>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyDateMap);
}
}
}
any if any.is::<DateMap<Date>>() => {
if let Some(map) = any.downcast_mut::<DateMap<Date>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyDateMap);
}
}
}
any if any.is::<DateMap<Height>>() => {
if let Some(map) = any.downcast_mut::<DateMap<Height>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyDateMap);
}
}
}
any if any.is::<DateMap<Timestamp>>() => {
if let Some(map) = any.downcast_mut::<DateMap<Timestamp>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyDateMap);
}
}
}
any if any.is::<DateRecapDataset<u32>>() => {
if let Some(dataset) = any.downcast_mut::<DateRecapDataset<u32>>() {
dataset.as_mut_vec().into_iter().for_each(|map| {
if map.kind() == kind {
v.push(map as &mut dyn AnyDateMap);
}
});
}
}
any if any.is::<DateRecapDataset<u64>>() => {
if let Some(dataset) = any.downcast_mut::<DateRecapDataset<u64>>() {
dataset.as_mut_vec().into_iter().for_each(|map| {
if map.kind() == kind {
v.push(map as &mut dyn AnyDateMap);
}
});
}
}
any if any.is::<DateRecapDataset<f32>>() => {
if let Some(dataset) = any.downcast_mut::<DateRecapDataset<f32>>() {
dataset.as_mut_vec().into_iter().for_each(|map| {
if map.kind() == kind {
v.push(map as &mut dyn AnyDateMap);
}
});
}
}
any if any.is::<SubDataset>() => {
if let Some(dataset) = any.downcast_mut::<SubDataset>() {
dataset.as_mut_vec().into_iter().for_each(|dataset| {
v.append(&mut dataset.to_kind_mut_date_map_vec(kind));
});
}
}
any if any.is::<AddressCohortMetadataDataset>() => {
if let Some(dataset) = any.downcast_mut::<AddressCohortMetadataDataset>() {
match kind {
MapKind::Inserted => dataset.to_inserted_mut_date_map_vec(),
MapKind::Computed => dataset.to_computed_mut_date_map_vec(),
}
.into_iter()
.for_each(|map| {
v.push(map);
});
}
}
_ => {}
});
v
}
fn to_kind_height_map_vec(&self, kind: MapKind) -> Vec<&(dyn AnyHeightMap + Send + Sync)> {
let mut v = vec![];
self.iter().for_each(|(_, any)| {
if let Some(map) = any.downcast_ref::<HeightMap<u8>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyHeightMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<HeightMap<u16>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyHeightMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<HeightMap<u32>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyHeightMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<HeightMap<u64>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyHeightMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<HeightMap<usize>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyHeightMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<HeightMap<f32>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyHeightMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<HeightMap<f64>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyHeightMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<HeightMap<OHLC>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyHeightMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<HeightMap<Date>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyHeightMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<HeightMap<Height>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyHeightMap + Send + Sync))
}
} else if let Some(map) = any.downcast_ref::<HeightMap<Timestamp>>() {
if map.kind() == kind {
v.push(map as &(dyn AnyHeightMap + Send + Sync))
}
} else if let Some(dataset) = any.downcast_ref::<SubDataset>() {
dataset.as_vec().into_iter().for_each(|dataset| {
v.append(&mut dataset.to_kind_height_map_vec(kind));
});
} else if let Some(dataset) = any.downcast_ref::<AddressCohortMetadataDataset>() {
match kind {
MapKind::Inserted => dataset.to_inserted_height_map_vec(),
MapKind::Computed => dataset.to_computed_height_map_vec(),
}
.into_iter()
.for_each(|map| {
v.push(map);
});
}
});
v
}
fn to_kind_mut_height_map_vec(&mut self, kind: MapKind) -> Vec<&mut dyn AnyHeightMap> {
let mut v = vec![];
self.iter_mut().for_each(|(_, any)| match any {
any if any.is::<HeightMap<u8>>() => {
if let Some(map) = any.downcast_mut::<HeightMap<u8>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyHeightMap);
}
}
}
any if any.is::<HeightMap<u16>>() => {
if let Some(map) = any.downcast_mut::<HeightMap<u16>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyHeightMap);
}
}
}
any if any.is::<HeightMap<u32>>() => {
if let Some(map) = any.downcast_mut::<HeightMap<u32>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyHeightMap);
}
}
}
any if any.is::<HeightMap<u64>>() => {
if let Some(map) = any.downcast_mut::<HeightMap<u64>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyHeightMap);
}
}
}
any if any.is::<HeightMap<usize>>() => {
if let Some(map) = any.downcast_mut::<HeightMap<usize>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyHeightMap);
}
}
}
any if any.is::<HeightMap<f32>>() => {
if let Some(map) = any.downcast_mut::<HeightMap<f32>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyHeightMap);
}
}
}
any if any.is::<HeightMap<f64>>() => {
if let Some(map) = any.downcast_mut::<HeightMap<f64>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyHeightMap);
}
}
}
any if any.is::<HeightMap<OHLC>>() => {
if let Some(map) = any.downcast_mut::<HeightMap<OHLC>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyHeightMap);
}
}
}
any if any.is::<HeightMap<Date>>() => {
if let Some(map) = any.downcast_mut::<HeightMap<Date>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyHeightMap);
}
}
}
any if any.is::<HeightMap<Height>>() => {
if let Some(map) = any.downcast_mut::<HeightMap<Height>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyHeightMap);
}
}
}
any if any.is::<HeightMap<Timestamp>>() => {
if let Some(map) = any.downcast_mut::<HeightMap<Timestamp>>() {
if map.kind() == kind {
v.push(map as &mut dyn AnyHeightMap);
}
}
}
any if any.is::<SubDataset>() => {
if let Some(dataset) = any.downcast_mut::<SubDataset>() {
dataset.as_mut_vec().into_iter().for_each(|dataset| {
v.append(&mut dataset.to_kind_mut_height_map_vec(kind));
});
}
}
any if any.is::<AddressCohortMetadataDataset>() => {
if let Some(dataset) = any.downcast_mut::<AddressCohortMetadataDataset>() {
match kind {
MapKind::Inserted => dataset.to_inserted_mut_height_map_vec(),
MapKind::Computed => dataset.to_computed_mut_height_map_vec(),
}
.into_iter()
.for_each(|map| {
v.push(map);
});
}
}
_ => {}
});
v
}
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![]
self.to_kind_bi_map_vec(MapKind::Inserted)
}
fn to_inserted_height_map_vec(&self) -> Vec<&(dyn AnyHeightMap + Send + Sync)> {
vec![]
self.to_kind_height_map_vec(MapKind::Inserted)
}
fn to_inserted_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
vec![]
self.to_kind_date_map_vec(MapKind::Inserted)
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![]
self.to_kind_mut_bi_map_vec(MapKind::Inserted)
}
fn to_inserted_mut_height_map_vec(&mut self) -> Vec<&mut dyn AnyHeightMap> {
vec![]
self.to_kind_mut_height_map_vec(MapKind::Inserted)
}
fn to_inserted_mut_date_map_vec(&mut self) -> Vec<&mut dyn AnyDateMap> {
vec![]
self.to_kind_mut_date_map_vec(MapKind::Inserted)
}
fn to_all_inserted_height_map_vec(&self) -> Vec<&(dyn AnyHeightMap + Send + Sync)> {
@@ -140,27 +732,27 @@ pub trait AnyDataset {
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![]
self.to_kind_bi_map_vec(MapKind::Computed)
}
fn to_computed_height_map_vec(&self) -> Vec<&(dyn AnyHeightMap + Send + Sync)> {
vec![]
self.to_kind_height_map_vec(MapKind::Computed)
}
fn to_computed_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
vec![]
self.to_kind_date_map_vec(MapKind::Computed)
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![]
self.to_kind_mut_bi_map_vec(MapKind::Computed)
}
fn to_computed_mut_height_map_vec(&mut self) -> Vec<&mut dyn AnyHeightMap> {
vec![]
self.to_kind_mut_height_map_vec(MapKind::Computed)
}
fn to_computed_mut_date_map_vec(&mut self) -> Vec<&mut dyn AnyDateMap> {
vec![]
self.to_kind_mut_date_map_vec(MapKind::Computed)
}
fn to_all_computed_height_map_vec(&self) -> Vec<&(dyn AnyHeightMap + Send + Sync)> {
@@ -283,4 +875,13 @@ pub trait AnyDataset {
.for_each(|map| map.post_export())
});
}
fn reset_computed(&self) {
self.to_all_computed_date_map_vec()
.iter()
.for_each(|map| map.delete_files());
self.to_all_computed_height_map_vec()
.iter()
.for_each(|map| map.delete_files());
}
}
@@ -1,6 +1,6 @@
use allocative::Allocative;
use crate::structs::{AnyDateMap, AnyHeightMap, Date, Height};
use crate::structs::{AnyDateMap, AnyHeightMap, Config, Date, Height};
use super::{AnyDataset, AnyDatasets};
@@ -16,17 +16,17 @@ impl MinInitialStates {
self.computed = other.computed;
}
pub fn compute_from_dataset(dataset: &dyn AnyDataset) -> Self {
pub fn compute_from_dataset(dataset: &dyn AnyDataset, config: &Config) -> Self {
Self {
inserted: MinInitialState::compute_from_dataset(dataset, Mode::Inserted),
computed: MinInitialState::compute_from_dataset(dataset, Mode::Computed),
inserted: MinInitialState::compute_from_dataset(dataset, Mode::Inserted, config),
computed: MinInitialState::compute_from_dataset(dataset, Mode::Computed, config),
}
}
pub fn compute_from_datasets(datasets: &dyn AnyDatasets) -> Self {
pub fn compute_from_datasets(datasets: &dyn AnyDatasets, config: &Config) -> Self {
Self {
inserted: MinInitialState::compute_from_datasets(datasets, Mode::Inserted),
computed: MinInitialState::compute_from_datasets(datasets, Mode::Computed),
inserted: MinInitialState::compute_from_datasets(datasets, Mode::Inserted, config),
computed: MinInitialState::compute_from_datasets(datasets, Mode::Computed, config),
}
}
}
@@ -52,7 +52,7 @@ impl MinInitialState {
// self.last_height = other.last_height;
// }
fn compute_from_datasets(datasets: &dyn AnyDatasets, mode: Mode) -> Self {
fn compute_from_datasets(datasets: &dyn AnyDatasets, mode: Mode, config: &Config) -> Self {
match mode {
Mode::Inserted => {
let contains_date_maps = |dataset: &&(dyn AnyDataset + Sync + Send)| {
@@ -111,6 +111,11 @@ impl MinInitialState {
}
}
Mode::Computed => {
if config.recompute_computed() {
// datasets.reset_computed();
return Self::default();
}
let contains_date_maps = |dataset: &&(dyn AnyDataset + Sync + Send)| {
!dataset.to_all_computed_date_map_vec().is_empty()
};
@@ -197,7 +202,7 @@ impl MinInitialState {
)
}
fn compute_from_dataset(dataset: &dyn AnyDataset, mode: Mode) -> Self {
fn compute_from_dataset(dataset: &dyn AnyDataset, mode: Mode, config: &Config) -> Self {
match mode {
Mode::Inserted => {
let date_vec = dataset.to_all_inserted_date_map_vec();
@@ -215,6 +220,11 @@ impl MinInitialState {
}
}
Mode::Computed => {
if config.recompute_computed() {
dataset.reset_computed();
return Self::default();
}
let date_vec = dataset.to_all_computed_date_map_vec();
let height_vec = dataset.to_all_computed_height_map_vec();
+11 -28
View File
@@ -1,37 +1,36 @@
use allocative::Allocative;
use struct_iterable::Iterable;
use crate::{
datasets::{AnyDataset, ComputeData, InsertData, MinInitialStates},
structs::{AnyBiMap, BiMap},
structs::{BiMap, Config, MapKind},
};
#[derive(Allocative)]
#[derive(Allocative, Iterable)]
pub struct AllAddressesMetadataDataset {
min_initial_states: MinInitialStates,
// Inserted
created_addreses: BiMap<u32>,
empty_addresses: BiMap<u32>,
// Computed
new_addresses: BiMap<u32>,
}
impl AllAddressesMetadataDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
pub fn import(parent_path: &str, config: &Config) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
// TODO: Shouldn't be (like many others)
created_addreses: BiMap::new_bin(1, &f("created_addresses")),
empty_addresses: BiMap::new_bin(1, &f("empty_addresses")),
new_addresses: BiMap::new_bin(1, &f("new_addresses")),
// Inserted
created_addreses: BiMap::new_bin(1, MapKind::Inserted, &f("created_addresses")),
empty_addresses: BiMap::new_bin(1, MapKind::Inserted, &f("empty_addresses")),
// Computed
new_addresses: BiMap::new_bin(1, MapKind::Computed, &f("new_addresses")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
.consume(MinInitialStates::compute_from_dataset(&s, config));
Ok(s)
}
@@ -72,20 +71,4 @@ impl AnyDataset for AllAddressesMetadataDataset {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![&self.created_addreses, &self.empty_addresses]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.created_addreses, &mut self.empty_addresses]
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![&self.new_addresses]
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.new_addresses]
}
}
+55 -375
View File
@@ -1,63 +1,50 @@
use allocative::Allocative;
use itertools::Itertools;
use struct_iterable::Iterable;
use crate::{
datasets::{
AnyDataset, AnyDatasetGroup, ComputeData, InsertData, MinInitialStates, SubDataset,
},
states::{AddressCohortDurableStates, AddressCohortId},
structs::{AddressSplit, AnyBiMap, AnyDateMap, AnyHeightMap, BiMap, Date, Height},
datasets::{AnyDataset, ComputeData, InsertData, MinInitialStates, SubDataset},
states::{AddressCohortId, DurableStates},
structs::{AddressSplit, BiMap, Config, Date, Height},
};
use super::cohort_metadata::MetadataDataset;
use super::cohort_metadata::AddressCohortMetadataDataset;
#[derive(Default, Allocative)]
#[derive(Allocative, Iterable)]
pub struct CohortDataset {
min_initial_states: MinInitialStates,
split: AddressSplit,
metadata: MetadataDataset,
metadata: AddressCohortMetadataDataset,
pub all: SubDataset,
illiquid: SubDataset,
liquid: SubDataset,
highly_liquid: SubDataset,
pub subs: SubDataset,
}
impl CohortDataset {
pub fn import(parent_path: &str, id: AddressCohortId) -> color_eyre::Result<Self> {
pub fn import(
parent_path: &str,
id: AddressCohortId,
config: &Config,
) -> color_eyre::Result<Self> {
let name = id.as_name().map(|s| s.to_owned());
let split = id.as_split();
let f = |s: &str| {
if let Some(name) = &name {
Some(format!("{s}/{name}"))
} else {
Some(s.to_owned())
}
};
let mut s = Self {
min_initial_states: MinInitialStates::default(),
split,
metadata: MetadataDataset::import(parent_path, &name)?,
all: SubDataset::import(parent_path, &name)?,
illiquid: SubDataset::import(parent_path, &f("illiquid"))?,
liquid: SubDataset::import(parent_path, &f("liquid"))?,
highly_liquid: SubDataset::import(parent_path, &f("highly_liquid"))?,
metadata: AddressCohortMetadataDataset::import(parent_path, &name, config)?,
subs: SubDataset::import(parent_path, &name, config)?,
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
.consume(MinInitialStates::compute_from_dataset(&s, config));
Ok(s)
}
pub fn sub_datasets_vec(&self) -> Vec<&SubDataset> {
vec![&self.all, &self.illiquid, &self.liquid, &self.highly_liquid]
vec![&self.subs]
}
pub fn needs_insert_metadata(&self, height: Height, date: Date) -> bool {
@@ -113,28 +100,14 @@ impl CohortDataset {
// }
pub fn insert_realized_data(&mut self, insert_data: &InsertData) {
let split_realized_state = insert_data
let realized_state = insert_data
.address_cohorts_realized_states
.as_ref()
.unwrap()
.get(&self.split)
.unwrap();
self.all
.realized
.insert(insert_data, &split_realized_state.all);
self.illiquid
.realized
.insert(insert_data, &split_realized_state.illiquid);
self.liquid
.realized
.insert(insert_data, &split_realized_state.liquid);
self.highly_liquid
.realized
.insert(insert_data, &split_realized_state.highly_liquid);
self.subs.realized.insert(insert_data, realized_state);
}
fn insert_metadata(&mut self, insert_data: &InsertData) {
@@ -150,109 +123,26 @@ impl CohortDataset {
self.metadata.insert(insert_data, address_count);
}
fn insert_supply_data(
&mut self,
insert_data: &InsertData,
liquidity_split_state: &AddressCohortDurableStates,
) {
self.all.supply.insert(
insert_data,
&liquidity_split_state.split_durable_states.all.supply_state,
);
self.illiquid.supply.insert(
insert_data,
&liquidity_split_state
.split_durable_states
.illiquid
.supply_state,
);
self.liquid.supply.insert(
insert_data,
&liquidity_split_state
.split_durable_states
.liquid
.supply_state,
);
self.highly_liquid.supply.insert(
insert_data,
&liquidity_split_state
.split_durable_states
.highly_liquid
.supply_state,
);
fn insert_supply_data(&mut self, insert_data: &InsertData, durable_states: &DurableStates) {
self.subs
.supply
.insert(insert_data, &durable_states.supply_state);
}
fn insert_utxo_data(
&mut self,
insert_data: &InsertData,
liquidity_split_state: &AddressCohortDurableStates,
) {
self.all.utxo.insert(
insert_data,
&liquidity_split_state.split_durable_states.all.utxo_state,
);
self.illiquid.utxo.insert(
insert_data,
&liquidity_split_state
.split_durable_states
.illiquid
.utxo_state,
);
self.liquid.utxo.insert(
insert_data,
&liquidity_split_state.split_durable_states.liquid.utxo_state,
);
self.highly_liquid.utxo.insert(
insert_data,
&liquidity_split_state
.split_durable_states
.highly_liquid
.utxo_state,
);
fn insert_utxo_data(&mut self, insert_data: &InsertData, durable_states: &DurableStates) {
self.subs
.utxo
.insert(insert_data, &durable_states.utxo_state);
}
fn insert_capitalization_data(
&mut self,
insert_data: &InsertData,
liquidity_split_state: &AddressCohortDurableStates,
durable_states: &DurableStates,
) {
self.all.capitalization.insert(
insert_data,
&liquidity_split_state
.split_durable_states
.all
.capitalization_state,
);
self.illiquid.capitalization.insert(
insert_data,
&liquidity_split_state
.split_durable_states
.illiquid
.capitalization_state,
);
self.liquid.capitalization.insert(
insert_data,
&liquidity_split_state
.split_durable_states
.liquid
.capitalization_state,
);
self.highly_liquid.capitalization.insert(
insert_data,
&liquidity_split_state
.split_durable_states
.highly_liquid
.capitalization_state,
);
self.subs
.capitalization
.insert(insert_data, &durable_states.capitalization_state);
}
fn insert_unrealized_data(&mut self, insert_data: &InsertData) {
@@ -263,28 +153,10 @@ impl CohortDataset {
.get(&self.split)
.unwrap();
self.all.unrealized.insert(
self.subs.unrealized.insert(
insert_data,
&states.all.unrealized_block_state,
&states.all.unrealized_date_state,
);
self.illiquid.unrealized.insert(
insert_data,
&states.illiquid.unrealized_block_state,
&states.illiquid.unrealized_date_state,
);
self.liquid.unrealized.insert(
insert_data,
&states.liquid.unrealized_block_state,
&states.liquid.unrealized_date_state,
);
self.highly_liquid.unrealized.insert(
insert_data,
&states.highly_liquid.unrealized_block_state,
&states.highly_liquid.unrealized_date_state,
&states.unrealized_block_state,
&states.unrealized_date_state,
);
}
@@ -296,21 +168,9 @@ impl CohortDataset {
.get(&self.split)
.unwrap();
self.all
self.subs
.price_paid
.insert(insert_data, &states.all.price_paid_state);
self.illiquid
.price_paid
.insert(insert_data, &states.illiquid.price_paid_state);
self.liquid
.price_paid
.insert(insert_data, &states.liquid.price_paid_state);
self.highly_liquid
.price_paid
.insert(insert_data, &states.highly_liquid.price_paid_state);
.insert(insert_data, &states.price_paid_state);
}
fn insert_input_data(&mut self, insert_data: &InsertData) {
@@ -321,12 +181,7 @@ impl CohortDataset {
.get(&self.split)
.unwrap();
self.all.input.insert(insert_data, &state.all);
self.illiquid.input.insert(insert_data, &state.illiquid);
self.liquid.input.insert(insert_data, &state.liquid);
self.highly_liquid
.input
.insert(insert_data, &state.highly_liquid);
self.subs.input.insert(insert_data, state);
}
// fn insert_output_data(&mut self, insert_data: &InsertData) {
@@ -337,7 +192,7 @@ impl CohortDataset {
// .get(&self.split)
// .unwrap();
// self.all.output.insert(insert_data, &state.all);
// self.output.insert(insert_data, &state.all);
// self.illiquid.output.insert(insert_data, &state.illiquid);
// self.liquid.output.insert(insert_data, &state.liquid);
// self.highly_liquid
@@ -345,65 +200,41 @@ impl CohortDataset {
// .insert(insert_data, &state.highly_liquid);
// }
fn as_vec(&self) -> Vec<&(dyn AnyDataset + Send + Sync)> {
vec![
self.all.as_vec(),
self.illiquid.as_vec(),
self.liquid.as_vec(),
self.highly_liquid.as_vec(),
vec![&self.metadata],
]
.into_iter()
.flatten()
.collect_vec()
}
fn as_mut_vec(&mut self) -> Vec<&mut dyn AnyDataset> {
vec![
self.all.as_mut_vec(),
self.illiquid.as_mut_vec(),
self.liquid.as_mut_vec(),
self.highly_liquid.as_mut_vec(),
vec![&mut self.metadata],
]
.into_iter()
.flatten()
.collect_vec()
}
pub fn insert(&mut self, insert_data: &InsertData) {
if !insert_data.compute_addresses {
return;
}
let liquidity_split_processed_address_state = insert_data
let address_cohort_durable_states = insert_data
.states
.address_cohorts_durable_states
.as_ref()
.unwrap()
.get(&self.split);
if liquidity_split_processed_address_state.is_none() {
if address_cohort_durable_states.is_none() {
return; // TODO: Check if should panic instead
}
let liquidity_split_processed_address_state =
liquidity_split_processed_address_state.unwrap();
let address_cohort_durable_states = address_cohort_durable_states.unwrap();
if self.needs_insert_metadata(insert_data.height, insert_data.date) {
self.insert_metadata(insert_data);
}
if self.needs_insert_utxo(insert_data.height, insert_data.date) {
self.insert_utxo_data(insert_data, liquidity_split_processed_address_state);
self.insert_utxo_data(insert_data, &address_cohort_durable_states.durable_states);
}
if self.needs_insert_capitalization(insert_data.height, insert_data.date) {
self.insert_capitalization_data(insert_data, liquidity_split_processed_address_state);
self.insert_capitalization_data(
insert_data,
&address_cohort_durable_states.durable_states,
);
}
if self.needs_insert_supply(insert_data.height, insert_data.date) {
self.insert_supply_data(insert_data, liquidity_split_processed_address_state);
self.insert_supply_data(insert_data, &address_cohort_durable_states.durable_states);
}
if self.needs_insert_realized(insert_data.height, insert_data.date) {
@@ -478,17 +309,7 @@ impl CohortDataset {
compute_data: &ComputeData,
circulating_supply: &mut BiMap<f64>,
) {
self.all.supply.compute(compute_data, circulating_supply);
self.illiquid
.supply
.compute(compute_data, circulating_supply);
self.liquid.supply.compute(compute_data, circulating_supply);
self.highly_liquid
.supply
.compute(compute_data, circulating_supply);
self.subs.supply.compute(compute_data, circulating_supply);
}
fn compute_unrealized_data(
@@ -497,85 +318,28 @@ impl CohortDataset {
circulating_supply: &mut BiMap<f64>,
market_cap: &mut BiMap<f32>,
) {
self.all.unrealized.compute(
self.subs.unrealized.compute(
compute_data,
&mut self.all.supply.supply,
circulating_supply,
market_cap,
);
self.illiquid.unrealized.compute(
compute_data,
&mut self.illiquid.supply.supply,
circulating_supply,
market_cap,
);
self.liquid.unrealized.compute(
compute_data,
&mut self.liquid.supply.supply,
circulating_supply,
market_cap,
);
self.highly_liquid.unrealized.compute(
compute_data,
&mut self.highly_liquid.supply.supply,
&mut self.subs.supply.supply,
circulating_supply,
market_cap,
);
}
fn compute_realized_data(&mut self, compute_data: &ComputeData, market_cap: &mut BiMap<f32>) {
self.all.realized.compute(compute_data, market_cap);
self.illiquid.realized.compute(compute_data, market_cap);
self.liquid.realized.compute(compute_data, market_cap);
self.highly_liquid
.realized
.compute(compute_data, market_cap);
self.subs.realized.compute(compute_data, market_cap);
}
fn compute_capitalization_data(&mut self, compute_data: &ComputeData, closes: &mut BiMap<f32>) {
self.all
self.subs
.capitalization
.compute(compute_data, closes, &mut self.all.supply.supply);
self.illiquid.capitalization.compute(
compute_data,
closes,
&mut self.illiquid.supply.supply,
);
self.liquid
.capitalization
.compute(compute_data, closes, &mut self.liquid.supply.supply);
self.highly_liquid.capitalization.compute(
compute_data,
closes,
&mut self.highly_liquid.supply.supply,
);
.compute(compute_data, closes, &mut self.subs.supply.supply);
}
// fn compute_output_data(&mut self, compute_data: &ComputeData) {
// self.all
// .output
// .compute(compute_data, &mut self.all.supply.total);
// self.illiquid
// .output
// .compute(compute_data, &mut self.illiquid.supply.total);
// self.liquid
// .output
// .compute(compute_data, &mut self.liquid.supply.total);
// self.highly_liquid
// .output
// .compute(compute_data, &mut self.highly_liquid.supply.total);
// .compute(compute_data, &mut self.supply.total);
// }
pub fn compute(
@@ -609,90 +373,6 @@ impl CohortDataset {
}
impl AnyDataset for CohortDataset {
fn to_inserted_height_map_vec(&self) -> Vec<&(dyn AnyHeightMap + Send + Sync)> {
self.as_vec()
.into_iter()
.flat_map(|d| d.to_inserted_height_map_vec())
.collect_vec()
}
fn to_inserted_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
self.as_vec()
.into_iter()
.flat_map(|d| d.to_inserted_date_map_vec())
.collect_vec()
}
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
self.as_vec()
.into_iter()
.flat_map(|d| d.to_inserted_bi_map_vec())
.collect_vec()
}
fn to_inserted_mut_height_map_vec(&mut self) -> Vec<&mut dyn AnyHeightMap> {
self.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_inserted_mut_height_map_vec())
.collect_vec()
}
fn to_inserted_mut_date_map_vec(&mut self) -> Vec<&mut dyn AnyDateMap> {
self.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_inserted_mut_date_map_vec())
.collect_vec()
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
self.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_inserted_mut_bi_map_vec())
.collect_vec()
}
fn to_computed_height_map_vec(&self) -> Vec<&(dyn AnyHeightMap + Send + Sync)> {
self.as_vec()
.into_iter()
.flat_map(|d| d.to_computed_height_map_vec())
.collect_vec()
}
fn to_computed_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
self.as_vec()
.into_iter()
.flat_map(|d| d.to_computed_date_map_vec())
.collect_vec()
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
self.as_vec()
.into_iter()
.flat_map(|d| d.to_computed_bi_map_vec())
.collect_vec()
}
fn to_computed_mut_height_map_vec(&mut self) -> Vec<&mut dyn AnyHeightMap> {
self.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_computed_mut_height_map_vec())
.collect_vec()
}
fn to_computed_mut_date_map_vec(&mut self) -> Vec<&mut dyn AnyDateMap> {
self.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_computed_mut_date_map_vec())
.collect_vec()
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
self.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_computed_mut_bi_map_vec())
.collect_vec()
}
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
+16 -19
View File
@@ -1,24 +1,28 @@
use allocative::Allocative;
use struct_iterable::Iterable;
use crate::{
datasets::{AnyDataset, InsertData, MinInitialStates},
structs::{AnyBiMap, BiMap},
structs::{BiMap, Config, MapKind},
};
#[derive(Default, Allocative)]
pub struct MetadataDataset {
#[derive(Allocative, Iterable)]
pub struct AddressCohortMetadataDataset {
min_initial_states: MinInitialStates,
// Inserted
address_count: BiMap<usize>,
address_count: BiMap<f64>,
// pub output: OutputSubDataset,
// Sending addresses
// Receiving addresses
// Active addresses (Unique(Sending + Receiving))
}
impl MetadataDataset {
pub fn import(parent_path: &str, name: &Option<String>) -> color_eyre::Result<Self> {
impl AddressCohortMetadataDataset {
pub fn import(
parent_path: &str,
name: &Option<String>,
config: &Config,
) -> color_eyre::Result<Self> {
let f = |s: &str| {
if let Some(name) = name {
format!("{parent_path}/{name}/{s}")
@@ -30,12 +34,13 @@ impl MetadataDataset {
let mut s = Self {
min_initial_states: MinInitialStates::default(),
address_count: BiMap::new_bin(1, &f("address_count")),
// Inserted
address_count: BiMap::new_bin(1, MapKind::Inserted, &f("address_count")),
// output: OutputSubDataset::import(parent_path)?,
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
.consume(MinInitialStates::compute_from_dataset(&s, config));
Ok(s)
}
@@ -48,7 +53,7 @@ impl MetadataDataset {
is_date_last_block,
..
}: &InsertData,
address_count: usize,
address_count: f64,
) {
self.address_count.height.insert(height, address_count);
@@ -58,16 +63,8 @@ impl MetadataDataset {
}
}
impl AnyDataset for MetadataDataset {
impl AnyDataset for AddressCohortMetadataDataset {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![&self.address_count]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.address_count]
}
}
+9 -9
View File
@@ -1,6 +1,6 @@
mod all_metadata;
mod cohort;
mod cohort_metadata;
pub mod cohort_metadata;
use allocative::Allocative;
use itertools::Itertools;
@@ -8,7 +8,7 @@ use rayon::prelude::*;
use crate::{
states::SplitByAddressCohort,
structs::{BiMap, Height},
structs::{BiMap, Config, Height},
Date,
};
@@ -26,30 +26,30 @@ pub struct AddressDatasets {
}
impl AddressDatasets {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
let mut cohorts = SplitByAddressCohort::<CohortDataset>::default();
pub fn import(parent_path: &str, config: &Config) -> color_eyre::Result<Self> {
let mut cohorts = SplitByAddressCohort::<Option<CohortDataset>>::default();
cohorts
.as_vec()
.into_par_iter()
.map(|(_, id)| (id, CohortDataset::import(parent_path, id)))
.map(|(_, id)| (id, CohortDataset::import(parent_path, id, config)))
.collect::<Vec<_>>()
.into_iter()
.try_for_each(|(id, dataset)| -> color_eyre::Result<()> {
*cohorts.get_mut_from_id(&id) = dataset?;
cohorts.get_mut_from_id(&id).replace(dataset?);
Ok(())
})?;
let mut s = Self {
min_initial_states: MinInitialStates::default(),
metadata: AllAddressesMetadataDataset::import(parent_path)?,
metadata: AllAddressesMetadataDataset::import(parent_path, config)?,
cohorts,
cohorts: cohorts.unwrap(),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_datasets(&s));
.consume(MinInitialStates::compute_from_datasets(&s, config));
Ok(s)
}
+10 -19
View File
@@ -1,34 +1,33 @@
use allocative::Allocative;
use struct_iterable::Iterable;
use crate::{
datasets::AnyDataset,
structs::{AnyHeightMap, Date, HeightMap},
structs::{Config, Date, HeightMap, MapKind, Timestamp},
};
use super::{InsertData, MinInitialStates};
#[derive(Allocative)]
#[derive(Allocative, Iterable)]
pub struct BlockMetadataDataset {
min_initial_states: MinInitialStates,
// Inserted
pub date: HeightMap<Date>,
pub timestamp: HeightMap<u32>,
pub timestamp: HeightMap<Timestamp>,
}
impl BlockMetadataDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
pub fn import(parent_path: &str, config: &Config) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
date: HeightMap::new_bin(1, &f("date")),
timestamp: HeightMap::new_bin(1, &f("timestamp")),
// Inserted
date: HeightMap::new_bin(1, MapKind::Inserted, &f("date")),
timestamp: HeightMap::new_bin(1, MapKind::Inserted, &f("timestamp")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
.consume(MinInitialStates::compute_from_dataset(&s, config));
Ok(s)
}
@@ -41,7 +40,7 @@ impl BlockMetadataDataset {
) {
self.timestamp.insert(height, timestamp);
self.date.insert(height, Date::from_timestamp(timestamp));
self.date.insert(height, timestamp.to_date());
}
}
@@ -49,12 +48,4 @@ impl AnyDataset for BlockMetadataDataset {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_inserted_height_map_vec(&self) -> Vec<&(dyn AnyHeightMap + Send + Sync)> {
vec![&self.date, &self.timestamp]
}
fn to_inserted_mut_height_map_vec(&mut self) -> Vec<&mut dyn AnyHeightMap> {
vec![&mut self.date, &mut self.timestamp]
}
}
+17 -19
View File
@@ -1,32 +1,39 @@
use allocative::Allocative;
use struct_iterable::Iterable;
use crate::{
datasets::AnyDataset,
structs::{AnyBiMap, BiMap},
structs::{Config, MapKind},
DateMap, HeightMap,
};
use super::{InsertData, MinInitialStates};
#[derive(Allocative)]
#[derive(Allocative, Iterable)]
pub struct CoindaysDataset {
min_initial_states: MinInitialStates,
// Inserted
pub coindays_destroyed: BiMap<f32>,
pub coindays_destroyed: HeightMap<f32>,
pub coindays_destroyed_1d_sum: DateMap<f32>,
}
impl CoindaysDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
pub fn import(parent_path: &str, config: &Config) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
coindays_destroyed: BiMap::new_bin(1, &f("coindays_destroyed")),
// Inserted
coindays_destroyed: HeightMap::new_bin(1, MapKind::Inserted, &f("coindays_destroyed")),
coindays_destroyed_1d_sum: DateMap::new_bin(
1,
MapKind::Inserted,
&f("coindays_destroyed_1d_sum"),
),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
.consume(MinInitialStates::compute_from_dataset(&s, config));
Ok(s)
}
@@ -43,25 +50,16 @@ impl CoindaysDataset {
}: &InsertData,
) {
self.coindays_destroyed
.height
.insert(height, satdays_destroyed.to_btc() as f32);
if is_date_last_block {
self.coindays_destroyed
.date_insert_sum_range(date, date_blocks_range)
self.coindays_destroyed_1d_sum
.insert(date, self.coindays_destroyed.sum_range(date_blocks_range));
}
}
}
impl AnyDataset for CoindaysDataset {
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![&self.coindays_destroyed]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.coindays_destroyed]
}
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
+263 -234
View File
@@ -1,18 +1,21 @@
use allocative::Allocative;
use struct_iterable::Iterable;
use crate::{
structs::{AnyBiMap, BiMap, DateMap, Height},
structs::{BiMap, Config, DateMap, Height, MapKind},
utils::{ONE_DAY_IN_DAYS, ONE_YEAR_IN_DAYS, THREE_MONTHS_IN_DAYS, TWO_WEEK_IN_DAYS},
HeightMap,
};
use super::{AnyDataset, ComputeData, InsertData, MinInitialStates, RatioDataset};
#[derive(Allocative)]
#[derive(Allocative, Iterable)]
pub struct CointimeDataset {
min_initial_states: MinInitialStates,
// Inserted
pub coinblocks_destroyed: BiMap<f32>,
pub coinblocks_destroyed: HeightMap<f32>,
pub coinblocks_destroyed_1d_sum: DateMap<f32>,
// Computed
pub active_cap: BiMap<f32>,
@@ -22,18 +25,24 @@ pub struct CointimeDataset {
pub active_supply_3m_net_change: BiMap<f32>,
pub active_supply_net_change: BiMap<f32>,
pub activity_to_vaultedness_ratio: BiMap<f32>,
pub coinblocks_created: BiMap<f32>,
pub coinblocks_stored: BiMap<f32>,
pub cointime_adjusted_velocity: BiMap<f32>,
pub cointime_adjusted_yearly_inflation_rate: BiMap<f32>,
pub coinblocks_created: HeightMap<f32>,
pub coinblocks_created_1d_sum: DateMap<f32>,
pub coinblocks_stored: HeightMap<f32>,
pub coinblocks_stored_1d_sum: DateMap<f32>,
pub cointime_adjusted_velocity: DateMap<f32>,
pub cointime_adjusted_inflation_rate: DateMap<f32>,
pub cointime_adjusted_yearly_inflation_rate: DateMap<f32>,
pub cointime_cap: BiMap<f32>,
pub cointime_price: BiMap<f32>,
pub cointime_price_ratio: RatioDataset,
pub cointime_value_created: BiMap<f32>,
pub cointime_value_destroyed: BiMap<f32>,
pub cointime_value_stored: BiMap<f32>,
pub concurrent_liveliness: BiMap<f32>,
pub concurrent_liveliness_2w_median: BiMap<f32>,
pub cointime_value_created: HeightMap<f32>,
pub cointime_value_created_1d_sum: DateMap<f32>,
pub cointime_value_destroyed: HeightMap<f32>,
pub cointime_value_destroyed_1d_sum: DateMap<f32>,
pub cointime_value_stored: HeightMap<f32>,
pub cointime_value_stored_1d_sum: DateMap<f32>,
pub concurrent_liveliness: DateMap<f32>,
pub concurrent_liveliness_2w_median: DateMap<f32>,
pub cumulative_coinblocks_created: BiMap<f32>,
pub cumulative_coinblocks_destroyed: BiMap<f32>,
pub cumulative_coinblocks_stored: BiMap<f32>,
@@ -63,80 +72,197 @@ pub struct CointimeDataset {
}
impl CointimeDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
pub fn import(parent_path: &str, config: &Config) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
active_cap: BiMap::new_bin(1, &f("active_cap")),
active_price: BiMap::new_bin(1, &f("active_price")),
active_price_ratio: RatioDataset::import(parent_path, "active_price")?,
active_supply: BiMap::new_bin(1, &f("active_supply")),
active_supply_3m_net_change: BiMap::new_bin(1, &f("active_supply_3m_net_change")),
active_supply_net_change: BiMap::new_bin(1, &f("active_supply_net_change")),
activity_to_vaultedness_ratio: BiMap::new_bin(2, &f("activity_to_vaultedness_ratio")),
coinblocks_created: BiMap::new_bin(1, &f("coinblocks_created")),
coinblocks_destroyed: BiMap::new_bin(1, &f("coinblocks_destroyed")),
coinblocks_stored: BiMap::new_bin(1, &f("coinblocks_stored")),
cointime_adjusted_velocity: BiMap::new_bin(1, &f("cointime_adjusted_velocity")),
cointime_adjusted_yearly_inflation_rate: BiMap::new_bin(
// Inserted
coinblocks_destroyed: HeightMap::new_bin(
1,
MapKind::Inserted,
&f("coinblocks_destroyed"),
),
coinblocks_destroyed_1d_sum: DateMap::new_bin(
1,
MapKind::Inserted,
&f("coinblocks_destroyed_1d_sum"),
),
// Computed
active_cap: BiMap::new_bin(1, MapKind::Computed, &f("active_cap")),
active_price: BiMap::new_bin(1, MapKind::Computed, &f("active_price")),
active_price_ratio: RatioDataset::import(parent_path, "active_price", config)?,
active_supply: BiMap::new_bin(1, MapKind::Computed, &f("active_supply")),
active_supply_3m_net_change: BiMap::new_bin(
1,
MapKind::Computed,
&f("active_supply_3m_net_change"),
),
active_supply_net_change: BiMap::new_bin(
1,
MapKind::Computed,
&f("active_supply_net_change"),
),
activity_to_vaultedness_ratio: BiMap::new_bin(
2,
MapKind::Computed,
&f("activity_to_vaultedness_ratio"),
),
coinblocks_created: HeightMap::new_bin(1, MapKind::Computed, &f("coinblocks_created")),
coinblocks_created_1d_sum: DateMap::new_bin(
1,
MapKind::Computed,
&f("coinblocks_created_1d_sum"),
),
coinblocks_stored: HeightMap::new_bin(1, MapKind::Computed, &f("coinblocks_stored")),
coinblocks_stored_1d_sum: DateMap::new_bin(
1,
MapKind::Computed,
&f("coinblocks_stored_1d_sum"),
),
cointime_adjusted_velocity: DateMap::new_bin(
1,
MapKind::Computed,
&f("cointime_adjusted_velocity"),
),
cointime_adjusted_inflation_rate: DateMap::new_bin(
1,
MapKind::Computed,
&f("cointime_adjusted_inflation_rate"),
),
cointime_adjusted_yearly_inflation_rate: DateMap::new_bin(
1,
MapKind::Computed,
&f("cointime_adjusted_yearly_inflation_rate"),
),
cointime_cap: BiMap::new_bin(1, &f("cointime_cap")),
cointime_price: BiMap::new_bin(1, &f("cointime_price")),
cointime_price_ratio: RatioDataset::import(parent_path, "cointime_price")?,
cointime_value_created: BiMap::new_bin(1, &f("cointime_value_created")),
cointime_value_destroyed: BiMap::new_bin(1, &f("cointime_value_destroyed")),
cointime_value_stored: BiMap::new_bin(1, &f("cointime_value_stored")),
concurrent_liveliness: BiMap::new_bin(1, &f("concurrent_liveliness")),
concurrent_liveliness_2w_median: BiMap::new_bin(
cointime_cap: BiMap::new_bin(1, MapKind::Computed, &f("cointime_cap")),
cointime_price: BiMap::new_bin(1, MapKind::Computed, &f("cointime_price")),
cointime_price_ratio: RatioDataset::import(parent_path, "cointime_price", config)?,
cointime_value_created: HeightMap::new_bin(
1,
MapKind::Computed,
&f("cointime_value_created"),
),
cointime_value_created_1d_sum: DateMap::new_bin(
1,
MapKind::Computed,
&f("cointime_value_created_1d_sum"),
),
cointime_value_destroyed: HeightMap::new_bin(
1,
MapKind::Computed,
&f("cointime_value_destroyed"),
),
cointime_value_destroyed_1d_sum: DateMap::new_bin(
1,
MapKind::Computed,
&f("cointime_value_destroyed_1d_sum"),
),
cointime_value_stored: HeightMap::new_bin(
1,
MapKind::Computed,
&f("cointime_value_stored"),
),
cointime_value_stored_1d_sum: DateMap::new_bin(
1,
MapKind::Computed,
&f("cointime_value_stored_1d_sum"),
),
concurrent_liveliness: DateMap::new_bin(
1,
MapKind::Computed,
&f("concurrent_liveliness"),
),
concurrent_liveliness_2w_median: DateMap::new_bin(
2,
MapKind::Computed,
&f("concurrent_liveliness_2w_median"),
),
cumulative_coinblocks_created: BiMap::new_bin(1, &f("cumulative_coinblocks_created")),
cumulative_coinblocks_created: BiMap::new_bin(
1,
MapKind::Computed,
&f("cumulative_coinblocks_created"),
),
cumulative_coinblocks_destroyed: BiMap::new_bin(
1,
MapKind::Computed,
&f("cumulative_coinblocks_destroyed"),
),
cumulative_coinblocks_stored: BiMap::new_bin(1, &f("cumulative_coinblocks_stored")),
investor_cap: BiMap::new_bin(1, &f("investor_cap")),
investorness: BiMap::new_bin(1, &f("investorness")),
liveliness: BiMap::new_bin(1, &f("liveliness")),
liveliness_net_change: BiMap::new_bin(1, &f("liveliness_net_change")),
cumulative_coinblocks_stored: BiMap::new_bin(
1,
MapKind::Computed,
&f("cumulative_coinblocks_stored"),
),
investor_cap: BiMap::new_bin(1, MapKind::Computed, &f("investor_cap")),
investorness: BiMap::new_bin(1, MapKind::Computed, &f("investorness")),
liveliness: BiMap::new_bin(1, MapKind::Computed, &f("liveliness")),
liveliness_net_change: BiMap::new_bin(
1,
MapKind::Computed,
&f("liveliness_net_change"),
),
liveliness_net_change_2w_median: BiMap::new_bin(
3,
MapKind::Computed,
&f("liveliness_net_change_2w_median"),
),
producerness: BiMap::new_bin(1, &f("producerness")),
thermo_cap: BiMap::new_bin(1, &f("thermo_cap")),
producerness: BiMap::new_bin(1, MapKind::Computed, &f("producerness")),
thermo_cap: BiMap::new_bin(1, MapKind::Computed, &f("thermo_cap")),
thermo_cap_to_investor_cap_ratio: BiMap::new_bin(
2,
MapKind::Computed,
&f("thermo_cap_to_investor_cap_ratio"),
),
total_cointime_value_created: BiMap::new_bin(1, &f("total_cointime_value_created")),
total_cointime_value_destroyed: BiMap::new_bin(1, &f("total_cointime_value_destroyed")),
total_cointime_value_stored: BiMap::new_bin(1, &f("total_cointime_value_stored")),
true_market_deviation: BiMap::new_bin(1, &f("true_market_deviation")),
true_market_mean: BiMap::new_bin(1, &f("true_market_mean")),
true_market_mean_ratio: RatioDataset::import(parent_path, "true_market_mean")?,
total_cointime_value_created: BiMap::new_bin(
1,
MapKind::Computed,
&f("total_cointime_value_created"),
),
total_cointime_value_destroyed: BiMap::new_bin(
1,
MapKind::Computed,
&f("total_cointime_value_destroyed"),
),
total_cointime_value_stored: BiMap::new_bin(
1,
MapKind::Computed,
&f("total_cointime_value_stored"),
),
true_market_deviation: BiMap::new_bin(
1,
MapKind::Computed,
&f("true_market_deviation"),
),
true_market_mean: BiMap::new_bin(1, MapKind::Computed, &f("true_market_mean")),
true_market_mean_ratio: RatioDataset::import(parent_path, "true_market_mean", config)?,
true_market_net_unrealized_profit_and_loss: BiMap::new_bin(
1,
MapKind::Computed,
&f("true_market_net_unrealized_profit_and_loss"),
),
vaulted_cap: BiMap::new_bin(1, &f("vaulted_cap")),
vaulted_price: BiMap::new_bin(1, &f("vaulted_price")),
vaulted_price_ratio: RatioDataset::import(parent_path, "vaulted_price")?,
vaulted_supply: BiMap::new_bin(1, &f("vaulted_supply")),
vaulted_supply_3m_net_change: BiMap::new_bin(1, &f("vaulted_supply_3m_net_change")),
vaulted_supply_net_change: BiMap::new_bin(1, &f("vaulted_supply_net_change")),
vaultedness: BiMap::new_bin(1, &f("vaultedness")),
vaulting_rate: BiMap::new_bin(1, &f("vaulting_rate")),
vaulted_cap: BiMap::new_bin(1, MapKind::Computed, &f("vaulted_cap")),
vaulted_price: BiMap::new_bin(1, MapKind::Computed, &f("vaulted_price")),
vaulted_price_ratio: RatioDataset::import(parent_path, "vaulted_price", config)?,
vaulted_supply: BiMap::new_bin(1, MapKind::Computed, &f("vaulted_supply")),
vaulted_supply_3m_net_change: BiMap::new_bin(
1,
MapKind::Computed,
&f("vaulted_supply_3m_net_change"),
),
vaulted_supply_net_change: BiMap::new_bin(
1,
MapKind::Computed,
&f("vaulted_supply_net_change"),
),
vaultedness: BiMap::new_bin(1, MapKind::Computed, &f("vaultedness")),
vaulting_rate: BiMap::new_bin(1, MapKind::Computed, &f("vaulting_rate")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
.consume(MinInitialStates::compute_from_dataset(&s, config));
Ok(s)
}
@@ -153,12 +279,11 @@ impl CointimeDataset {
}: &InsertData,
) {
self.coinblocks_destroyed
.height
.insert(height, satblocks_destroyed.to_btc() as f32);
if is_date_last_block {
self.coinblocks_destroyed
.date_insert_sum_range(date, date_blocks_range);
self.coinblocks_destroyed_1d_sum
.insert(date, self.coinblocks_destroyed.sum_range(date_blocks_range));
}
}
@@ -172,45 +297,58 @@ impl CointimeDataset {
circulating_supply: &mut BiMap<f64>,
realized_cap: &mut BiMap<f32>,
realized_price: &mut BiMap<f32>,
yearly_inflation_rate: &mut BiMap<f64>,
annualized_transaction_volume: &mut BiMap<f32>,
inflation_rate: &mut DateMap<f64>,
yearly_inflation_rate: &mut DateMap<f64>,
annualized_transaction_volume: &mut DateMap<f32>,
cumulative_subsidy_in_dollars: &mut BiMap<f32>,
) {
let &ComputeData { heights, dates, .. } = compute_data;
self.cumulative_coinblocks_destroyed
.multi_insert_cumulative(heights, dates, &mut self.coinblocks_destroyed);
self.coinblocks_created
.height
.multi_insert_simple_transform(
heights,
&mut circulating_supply.height,
|circulating_supply| circulating_supply as f32,
);
self.coinblocks_created
.multi_date_insert_sum_range(dates, first_height, last_height);
.multi_insert_cumulative(heights, &mut self.coinblocks_destroyed);
self.cumulative_coinblocks_destroyed
.date
.multi_insert_cumulative(dates, &mut self.coinblocks_destroyed_1d_sum);
self.cumulative_coinblocks_created.multi_insert_cumulative(
self.coinblocks_created.multi_insert_simple_transform(
heights,
&mut circulating_supply.height,
|circulating_supply, _| circulating_supply as f32,
);
self.coinblocks_created_1d_sum.multi_insert_sum_range(
dates,
&self.coinblocks_created,
first_height,
last_height,
);
self.cumulative_coinblocks_created
.height
.multi_insert_cumulative(heights, &mut self.coinblocks_created);
self.cumulative_coinblocks_created
.date
.multi_insert_cumulative(dates, &mut self.coinblocks_created_1d_sum);
self.coinblocks_stored.multi_insert_subtract(
heights,
&mut self.coinblocks_created,
&mut self.coinblocks_destroyed,
);
self.coinblocks_stored.height.multi_insert_subtract(
heights,
&mut self.coinblocks_created.height,
&mut self.coinblocks_destroyed.height,
);
self.coinblocks_stored
.multi_date_insert_sum_range(dates, first_height, last_height);
self.cumulative_coinblocks_stored.multi_insert_cumulative(
heights,
self.coinblocks_stored_1d_sum.multi_insert_sum_range(
dates,
&mut self.coinblocks_stored,
&self.coinblocks_stored,
first_height,
last_height,
);
self.cumulative_coinblocks_stored
.height
.multi_insert_cumulative(heights, &mut self.coinblocks_stored);
self.cumulative_coinblocks_stored
.date
.multi_insert_cumulative(dates, &mut self.coinblocks_stored_1d_sum);
self.liveliness.multi_insert_divide(
heights,
dates,
@@ -233,14 +371,12 @@ impl CointimeDataset {
);
self.concurrent_liveliness.multi_insert_divide(
heights,
dates,
&mut self.coinblocks_destroyed,
&mut self.coinblocks_created,
&mut self.coinblocks_destroyed_1d_sum,
&mut self.coinblocks_created_1d_sum,
);
self.concurrent_liveliness_2w_median.multi_insert_median(
heights,
dates,
&mut self.concurrent_liveliness,
Some(TWO_WEEK_IN_DAYS),
@@ -309,19 +445,23 @@ impl CointimeDataset {
// let min_vaulted_supply = ;
// let max_active_supply = ;
self.cointime_adjusted_inflation_rate.multi_insert_multiply(
dates,
&mut self.activity_to_vaultedness_ratio.date,
inflation_rate,
);
self.cointime_adjusted_yearly_inflation_rate
.multi_insert_multiply(
heights,
dates,
&mut self.activity_to_vaultedness_ratio,
&mut self.activity_to_vaultedness_ratio.date,
yearly_inflation_rate,
);
self.cointime_adjusted_velocity.multi_insert_divide(
heights,
dates,
annualized_transaction_volume,
&mut self.active_supply,
&mut self.active_supply.date,
);
// TODO:
@@ -414,7 +554,7 @@ impl CointimeDataset {
.multi_insert_complex_transform(
dates,
&mut self.active_cap.date,
|(active_cap, date, _)| {
|(active_cap, date, _, _)| {
let investor_cap = self.investor_cap.date.get(date).unwrap();
(active_cap - investor_cap) / active_cap
},
@@ -426,56 +566,59 @@ impl CointimeDataset {
self.producerness
.multi_insert_divide(heights, dates, &mut self.thermo_cap, realized_cap);
self.cointime_value_destroyed.height.multi_insert_multiply(
self.cointime_value_destroyed.multi_insert_multiply(
heights,
&mut self.coinblocks_destroyed.height,
&mut self.coinblocks_destroyed,
&mut closes.height,
);
self.cointime_value_destroyed.date.multi_insert_multiply(
self.cointime_value_destroyed_1d_sum.multi_insert_multiply(
dates,
&mut self.coinblocks_destroyed.date,
&mut self.coinblocks_destroyed_1d_sum,
&mut closes.date,
);
self.cointime_value_created.height.multi_insert_multiply(
self.cointime_value_created.multi_insert_multiply(
heights,
&mut self.coinblocks_created.height,
&mut self.coinblocks_created,
&mut closes.height,
);
self.cointime_value_created.date.multi_insert_multiply(
self.cointime_value_created_1d_sum.multi_insert_multiply(
dates,
&mut self.coinblocks_created.date,
&mut self.coinblocks_created_1d_sum,
&mut closes.date,
);
self.cointime_value_stored.height.multi_insert_multiply(
self.cointime_value_stored.multi_insert_multiply(
heights,
&mut self.coinblocks_stored.height,
&mut self.coinblocks_stored,
&mut closes.height,
);
self.cointime_value_stored.date.multi_insert_multiply(
self.cointime_value_stored_1d_sum.multi_insert_multiply(
dates,
&mut self.coinblocks_stored.date,
&mut self.coinblocks_stored_1d_sum,
&mut closes.date,
);
self.total_cointime_value_created.multi_insert_cumulative(
heights,
dates,
&mut self.cointime_value_created,
);
self.total_cointime_value_created
.height
.multi_insert_cumulative(heights, &mut self.cointime_value_created);
self.total_cointime_value_created
.date
.multi_insert_cumulative(dates, &mut self.cointime_value_created_1d_sum);
self.total_cointime_value_destroyed.multi_insert_cumulative(
heights,
dates,
&mut self.cointime_value_destroyed,
);
self.total_cointime_value_destroyed
.height
.multi_insert_cumulative(heights, &mut self.cointime_value_destroyed);
self.total_cointime_value_destroyed
.date
.multi_insert_cumulative(dates, &mut self.cointime_value_destroyed_1d_sum);
self.total_cointime_value_stored.multi_insert_cumulative(
heights,
dates,
&mut self.cointime_value_stored,
);
self.total_cointime_value_stored
.height
.multi_insert_cumulative(heights, &mut self.cointime_value_stored);
self.total_cointime_value_stored
.date
.multi_insert_cumulative(dates, &mut self.cointime_value_stored_1d_sum);
self.cointime_price.multi_insert_divide(
heights,
@@ -506,120 +649,6 @@ impl CointimeDataset {
}
impl AnyDataset for CointimeDataset {
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![&self.coinblocks_destroyed]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.coinblocks_destroyed]
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
let mut v = vec![
&self.active_cap as &(dyn AnyBiMap + Send + Sync),
&self.active_price,
&self.active_supply,
&self.active_supply_3m_net_change,
&self.active_supply_net_change,
&self.activity_to_vaultedness_ratio,
&self.coinblocks_created,
&self.coinblocks_stored,
&self.cointime_adjusted_velocity,
&self.cointime_adjusted_yearly_inflation_rate,
&self.cointime_cap,
&self.cointime_price,
&self.cointime_value_created,
&self.cointime_value_destroyed,
&self.cointime_value_stored,
&self.concurrent_liveliness,
&self.concurrent_liveliness_2w_median,
&self.cumulative_coinblocks_created,
&self.cumulative_coinblocks_destroyed,
&self.cumulative_coinblocks_stored,
&self.investor_cap,
&self.investorness,
&self.liveliness,
&self.liveliness_net_change,
&self.liveliness_net_change_2w_median,
&self.producerness,
&self.thermo_cap,
&self.thermo_cap_to_investor_cap_ratio,
&self.total_cointime_value_created,
&self.total_cointime_value_destroyed,
&self.total_cointime_value_stored,
&self.true_market_deviation,
&self.true_market_mean,
&self.true_market_net_unrealized_profit_and_loss,
&self.vaulted_cap,
&self.vaulted_price,
&self.vaulted_supply,
&self.vaulted_supply_net_change,
&self.vaulted_supply_3m_net_change,
&self.vaultedness,
&self.vaulting_rate,
];
v.append(&mut self.active_price_ratio.to_computed_bi_map_vec());
v.append(&mut self.cointime_price_ratio.to_computed_bi_map_vec());
v.append(&mut self.true_market_mean_ratio.to_computed_bi_map_vec());
v.append(&mut self.vaulted_price_ratio.to_computed_bi_map_vec());
v
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
let mut v = vec![
&mut self.active_cap as &mut dyn AnyBiMap,
&mut self.active_price,
&mut self.active_supply,
&mut self.active_supply_3m_net_change,
&mut self.active_supply_net_change,
&mut self.activity_to_vaultedness_ratio,
&mut self.coinblocks_created,
&mut self.coinblocks_stored,
&mut self.cointime_adjusted_velocity,
&mut self.cointime_adjusted_yearly_inflation_rate,
&mut self.cointime_cap,
&mut self.cointime_price,
&mut self.cointime_value_created,
&mut self.cointime_value_destroyed,
&mut self.cointime_value_stored,
&mut self.concurrent_liveliness,
&mut self.concurrent_liveliness_2w_median,
&mut self.cumulative_coinblocks_created,
&mut self.cumulative_coinblocks_destroyed,
&mut self.cumulative_coinblocks_stored,
&mut self.investor_cap,
&mut self.investorness,
&mut self.liveliness,
&mut self.liveliness_net_change,
&mut self.liveliness_net_change_2w_median,
&mut self.producerness,
&mut self.thermo_cap,
&mut self.thermo_cap_to_investor_cap_ratio,
&mut self.total_cointime_value_created,
&mut self.total_cointime_value_destroyed,
&mut self.total_cointime_value_stored,
&mut self.true_market_deviation,
&mut self.true_market_mean,
&mut self.true_market_net_unrealized_profit_and_loss,
&mut self.vaulted_cap,
&mut self.vaulted_price,
&mut self.vaulted_supply,
&mut self.vaulted_supply_net_change,
&mut self.vaulted_supply_3m_net_change,
&mut self.vaultedness,
&mut self.vaulting_rate,
];
v.append(&mut self.active_price_ratio.to_computed_mut_bi_map_vec());
v.append(&mut self.cointime_price_ratio.to_computed_mut_bi_map_vec());
v.append(&mut self.true_market_mean_ratio.to_computed_mut_bi_map_vec());
v.append(&mut self.vaulted_price_ratio.to_computed_mut_bi_map_vec());
v
}
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
+10 -17
View File
@@ -1,14 +1,14 @@
use allocative::Allocative;
use struct_iterable::Iterable;
use crate::structs::{AnyBiMap, BiMap};
use crate::structs::{BiMap, Config, MapKind};
use super::{AnyDataset, ComputeData, MinInitialStates};
#[derive(Allocative)]
#[derive(Allocative, Iterable)]
pub struct ConstantDataset {
min_initial_states: MinInitialStates,
// Computed
pub _0: BiMap<u16>,
pub _1: BiMap<u16>,
pub _50: BiMap<u16>,
@@ -16,20 +16,21 @@ pub struct ConstantDataset {
}
impl ConstantDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
pub fn import(parent_path: &str, config: &Config) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
_0: BiMap::new_bin(1, &f("0")),
_1: BiMap::new_bin(1, &f("1")),
_50: BiMap::new_bin(1, &f("50")),
_100: BiMap::new_bin(1, &f("100")),
// Computed
_0: BiMap::new_bin(1, MapKind::Computed, &f("0")),
_1: BiMap::new_bin(1, MapKind::Computed, &f("1")),
_50: BiMap::new_bin(1, MapKind::Computed, &f("50")),
_100: BiMap::new_bin(1, MapKind::Computed, &f("100")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
.consume(MinInitialStates::compute_from_dataset(&s, config));
Ok(s)
}
@@ -46,12 +47,4 @@ impl AnyDataset for ConstantDataset {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![&self._0, &self._1, &self._50, &self._100]
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self._0, &mut self._1, &mut self._50, &mut self._100]
}
}
+8 -15
View File
@@ -1,34 +1,35 @@
use allocative::Allocative;
use struct_iterable::Iterable;
use crate::{
datasets::AnyDataset,
structs::{AnyDateMap, DateMap, Height},
structs::{Config, DateMap, Height, MapKind},
};
use super::{InsertData, MinInitialStates};
#[derive(Allocative)]
#[derive(Allocative, Iterable)]
pub struct DateMetadataDataset {
min_initial_states: MinInitialStates,
// Inserted
pub first_height: DateMap<Height>,
pub last_height: DateMap<Height>,
}
impl DateMetadataDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
pub fn import(parent_path: &str, config: &Config) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
first_height: DateMap::new_bin(1, &f("first_height")),
last_height: DateMap::new_bin(1, &f("last_height")),
// Inserted
first_height: DateMap::new_bin(1, MapKind::Inserted, &f("first_height")),
last_height: DateMap::new_bin(1, MapKind::Inserted, &f("last_height")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
.consume(MinInitialStates::compute_from_dataset(&s, config));
Ok(s)
}
@@ -49,14 +50,6 @@ impl DateMetadataDataset {
}
impl AnyDataset for DateMetadataDataset {
fn to_inserted_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
vec![&self.first_height, &self.last_height]
}
fn to_inserted_mut_date_map_vec(&mut self) -> Vec<&mut dyn AnyDateMap> {
vec![&mut self.first_height, &mut self.last_height]
}
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
+324 -339
View File
@@ -1,13 +1,11 @@
use allocative::Allocative;
use itertools::Itertools;
use ordered_float::OrderedFloat;
use struct_iterable::Iterable;
use crate::{
datasets::AnyDataset,
structs::{
date_map_vec_to_any_date_map_vec, date_map_vec_to_mut_any_date_map_vec, Amount, AnyBiMap,
AnyDateMap, AnyHeightMap, BiMap, DateMap, Height, HeightMap, MapKey,
},
structs::{Amount, BiMap, Config, DateMap, Height, HeightMap, MapKey, MapKind},
utils::{
BYTES_IN_MB, ONE_DAY_IN_DAYS, ONE_MONTH_IN_DAYS, ONE_WEEK_IN_DAYS, ONE_YEAR_IN_DAYS,
TARGET_BLOCKS_PER_DAY,
@@ -18,17 +16,21 @@ use super::{
ComputeData, DateRecapDataset, InsertData, MinInitialStates, RecapDataset, RecapOptions,
};
#[derive(Allocative)]
#[derive(Allocative, Iterable)]
pub struct MiningDataset {
min_initial_states: MinInitialStates,
// Inserted
pub blocks_mined: DateMap<usize>,
pub total_blocks_mined: DateMap<usize>,
pub coinbase: BiMap<f64>,
pub coinbase_in_dollars: BiMap<f32>,
pub fees: BiMap<f64>,
pub fees_in_dollars: BiMap<f32>,
pub coinbase: HeightMap<f64>,
pub coinbase_1d_sum: DateMap<f64>,
pub coinbase_in_dollars: HeightMap<f32>,
pub coinbase_in_dollars_1d_sum: DateMap<f32>,
pub fees: HeightMap<f64>,
pub fees_1d_sum: DateMap<f64>,
pub fees_in_dollars: HeightMap<f32>,
pub fees_in_dollars_1d_sum: DateMap<f32>,
// Raw
// pub average_fee_paid: BiMap<f32>,
// pub max_fee_paid: BiMap<f32>,
@@ -48,8 +50,10 @@ pub struct MiningDataset {
// pub _10th_percentile_fee_price: BiMap<f32>,
// pub min_fee_price: BiMap<f32>,
// -
pub subsidy: BiMap<f64>,
pub subsidy_in_dollars: BiMap<f32>,
pub subsidy: HeightMap<f64>,
pub subsidy_1d_sum: DateMap<f64>,
pub subsidy_in_dollars: HeightMap<f32>,
pub subsidy_in_dollars_1d_sum: DateMap<f32>,
pub last_coinbase: DateMap<f64>,
pub last_coinbase_in_dollars: DateMap<f32>,
pub last_fees: DateMap<f64>,
@@ -57,17 +61,13 @@ pub struct MiningDataset {
pub last_subsidy: DateMap<f64>,
pub last_subsidy_in_dollars: DateMap<f32>,
pub difficulty: BiMap<f64>,
pub block_size: HeightMap<f32>, // in MB
pub block_size_recap: DateRecapDataset<f32>, // in MB
pub block_weight: HeightMap<f32>, // in MB
pub block_weight_recap: DateRecapDataset<f32>, // in MB
pub block_size: HeightMap<f32>, // in MB
pub block_weight: HeightMap<f32>, // in MB
pub block_vbytes: HeightMap<u64>,
pub block_vbytes_recap: DateRecapDataset<u64>,
pub block_interval: HeightMap<u32>, // in s
pub block_interval_recap: DateRecapDataset<u32>, // in s
pub block_interval: HeightMap<u32>, // in s
// Computed
pub annualized_issuance: BiMap<f64>, // Same as subsidy_1y_sum
pub annualized_issuance: DateMap<f64>, // Same as subsidy_1y_sum
pub blocks_mined_1d_target: DateMap<usize>,
pub blocks_mined_1m_sma: DateMap<f32>,
pub blocks_mined_1m_sum: DateMap<usize>,
@@ -78,44 +78,39 @@ pub struct MiningDataset {
pub blocks_mined_1y_sum: DateMap<usize>,
pub blocks_mined_1y_target: DateMap<usize>,
pub cumulative_block_size: BiMap<f32>,
pub cumulative_block_size_gigabytes: BiMap<f32>,
pub subsidy_1y_sum: DateMap<f64>,
pub subsidy_in_dollars_1y_sum: DateMap<f64>,
pub cumulative_subsidy: BiMap<f64>,
pub cumulative_subsidy_in_dollars: BiMap<f32>,
pub coinbase_1y_sum: DateMap<f64>,
pub coinbase_in_dollars_1y_sum: DateMap<f64>,
pub coinbase_in_dollars_1y_sma: DateMap<f32>,
pub coinbase_in_dollars_1d_sum_1y_sma: DateMap<f32>,
pub cumulative_coinbase: BiMap<f64>,
pub cumulative_coinbase_in_dollars: BiMap<f32>,
pub fees_1y_sum: DateMap<f64>,
pub fees_in_dollars_1y_sum: DateMap<f64>,
pub cumulative_fees: BiMap<f64>,
pub cumulative_fees_in_dollars: BiMap<f32>,
pub yearly_inflation_rate: BiMap<f64>,
pub subsidy_to_coinbase_ratio: BiMap<f64>,
pub fees_to_coinbase_ratio: BiMap<f64>,
pub inflation_rate: DateMap<f64>,
pub yearly_inflation_rate: DateMap<f64>,
pub subsidy_to_coinbase_ratio: HeightMap<f64>,
pub subsidy_to_coinbase_1d_ratio: DateMap<f64>,
pub fees_to_coinbase_ratio: HeightMap<f64>,
pub fees_to_coinbase_1d_ratio: DateMap<f64>,
pub hash_rate: DateMap<f64>,
pub hash_rate_1w_sma: DateMap<f32>,
pub hash_rate_1m_sma: DateMap<f32>,
pub hash_rate_2m_sma: DateMap<f32>,
pub hash_price: DateMap<f64>,
pub hash_price_min: DateMap<f64>,
pub hash_price_rebound: DateMap<f64>,
pub difficulty_adjustment: DateMap<f64>,
pub block_size_recap: DateRecapDataset<f32>, // in MB
pub block_weight_recap: DateRecapDataset<f32>, // in MB
pub block_vbytes_recap: DateRecapDataset<u64>,
pub block_interval_recap: DateRecapDataset<u32>, // in s
pub puell_multiple: DateMap<f32>,
// pub block_size_1d_sma: DateMap<f32>, // in MB
// pub block_weight_1d_sma: DateMap<f32>, // in MB
// pub block_vbytes_1d_sma: DateMap<u64>,
// pub block_interval_1d_sma: DateMap<u32>, // in s
// pub block_size_1d_median: DateMap<f32>, // in MB
// pub block_weight_1d_median: DateMap<f32>, // in MB
// pub block_vbytes_1d_median: DateMap<u64>,
// pub block_interval_1d_median: DateMap<u32>,
// pub blocks_size: DateMap<f32>,
// pub average_block_size: DateMap<f32>,
// pub median_block_size: DateMap<f32>,
// pub average_block_weight: DateMap<f32>,
// pub median_block_weight: DateMap<f32>,
// pub average_block_interval: DateMap<u32>,
// pub median_block_interval: DateMap<u32>,
// pub hash_price_in_dollars: DateMap<f64>,
// pub hash_price_30d_volatility: BiMap<f32>,
// difficulty_adjustment
@@ -128,62 +123,172 @@ pub struct MiningDataset {
}
impl MiningDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
pub fn import(parent_path: &str, config: &Config) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
total_blocks_mined: DateMap::new_bin(1, &f("total_blocks_mined")),
blocks_mined: DateMap::new_bin(1, &f("blocks_mined")),
coinbase: BiMap::new_bin(1, &f("coinbase")),
coinbase_in_dollars: BiMap::new_bin(1, &f("coinbase_in_dollars")),
coinbase_1y_sum: DateMap::new_bin(1, &f("coinbase_1y_sum")),
coinbase_in_dollars_1y_sum: DateMap::new_bin(1, &f("coinbase_in_dollars_1y_sum")),
coinbase_in_dollars_1y_sma: DateMap::new_bin(1, &f("coinbase_in_dollars_1y_sma")),
cumulative_coinbase: BiMap::new_bin(1, &f("cumulative_coinbase")),
cumulative_coinbase_in_dollars: BiMap::new_bin(1, &f("cumulative_coinbase_in_dollars")),
fees: BiMap::new_bin(1, &f("fees")),
fees_in_dollars: BiMap::new_bin(1, &f("fees_in_dollars")),
fees_1y_sum: DateMap::new_bin(1, &f("fees_1y_sum")),
fees_in_dollars_1y_sum: DateMap::new_bin(1, &f("fees_in_dollars_1y_sum")),
cumulative_fees: BiMap::new_bin(1, &f("cumulative_fees")),
cumulative_fees_in_dollars: BiMap::new_bin(1, &f("cumulative_fees_in_dollars")),
subsidy: BiMap::new_bin(1, &f("subsidy")),
subsidy_in_dollars: BiMap::new_bin(1, &f("subsidy_in_dollars")),
subsidy_1y_sum: DateMap::new_bin(1, &f("subsidy_1y_sum")),
subsidy_in_dollars_1y_sum: DateMap::new_bin(1, &f("subsidy_in_dollars_1y_sum")),
cumulative_subsidy: BiMap::new_bin(1, &f("cumulative_subsidy")),
cumulative_subsidy_in_dollars: BiMap::new_bin(1, &f("cumulative_subsidy_in_dollars")),
// ---
// Inserted
// ---
total_blocks_mined: DateMap::new_bin(1, MapKind::Inserted, &f("total_blocks_mined")),
blocks_mined: DateMap::new_bin(1, MapKind::Inserted, &f("blocks_mined")),
coinbase: HeightMap::new_bin(1, MapKind::Inserted, &f("coinbase")),
coinbase_1d_sum: DateMap::new_bin(1, MapKind::Inserted, &f("coinbase_1d_sum")),
coinbase_in_dollars: HeightMap::new_bin(
1,
MapKind::Inserted,
&f("coinbase_in_dollars"),
),
coinbase_in_dollars_1d_sum: DateMap::new_bin(
1,
MapKind::Inserted,
&f("coinbase_in_dollars_1d_sum"),
),
fees: HeightMap::new_bin(1, MapKind::Inserted, &f("fees")),
fees_1d_sum: DateMap::new_bin(1, MapKind::Inserted, &f("fees_1d_sum")),
fees_in_dollars: HeightMap::new_bin(1, MapKind::Inserted, &f("fees_in_dollars")),
fees_in_dollars_1d_sum: DateMap::new_bin(
1,
MapKind::Inserted,
&f("fees_in_dollars_1d_sum"),
),
subsidy: HeightMap::new_bin(1, MapKind::Inserted, &f("subsidy")),
subsidy_1d_sum: DateMap::new_bin(1, MapKind::Inserted, &f("subsidy_1d_sum")),
subsidy_in_dollars: HeightMap::new_bin(1, MapKind::Inserted, &f("subsidy_in_dollars")),
subsidy_in_dollars_1d_sum: DateMap::new_bin(
1,
MapKind::Inserted,
&f("subsidy_in_dollars_1d_sum"),
),
last_subsidy: DateMap::new_bin(1, MapKind::Inserted, &f("last_subsidy")),
last_subsidy_in_dollars: DateMap::new_bin(
1,
MapKind::Inserted,
&f("last_subsidy_in_dollars"),
),
last_coinbase: DateMap::new_bin(1, MapKind::Inserted, &f("last_coinbase")),
last_coinbase_in_dollars: DateMap::new_bin(
1,
MapKind::Inserted,
&f("last_coinbase_in_dollars"),
),
last_fees: DateMap::new_bin(1, MapKind::Inserted, &f("last_fees")),
last_fees_in_dollars: DateMap::new_bin(
1,
MapKind::Inserted,
&f("last_fees_in_dollars"),
),
difficulty: BiMap::new_bin(1, MapKind::Inserted, &f("difficulty")),
block_size: HeightMap::new_bin(1, MapKind::Inserted, &f("block_size")),
block_weight: HeightMap::new_bin(1, MapKind::Inserted, &f("block_weight")),
block_vbytes: HeightMap::new_bin(1, MapKind::Inserted, &f("block_vbytes")),
block_interval: HeightMap::new_bin(2, MapKind::Inserted, &f("block_interval")),
subsidy_to_coinbase_ratio: BiMap::new_bin(1, &f("subsidy_to_coinbase_ratio")),
fees_to_coinbase_ratio: BiMap::new_bin(1, &f("fees_to_coinbase_ratio")),
// ---
// Computed
// ---
coinbase_1y_sum: DateMap::new_bin(1, MapKind::Computed, &f("coinbase_1y_sum")),
coinbase_in_dollars_1y_sum: DateMap::new_bin(
1,
MapKind::Computed,
&f("coinbase_in_dollars_1y_sum"),
),
coinbase_in_dollars_1d_sum_1y_sma: DateMap::new_bin(
1,
MapKind::Computed,
&f("coinbase_in_dollars_1d_sum_1y_sma"),
),
cumulative_coinbase: BiMap::new_bin(1, MapKind::Computed, &f("cumulative_coinbase")),
cumulative_coinbase_in_dollars: BiMap::new_bin(
1,
MapKind::Computed,
&f("cumulative_coinbase_in_dollars"),
),
annualized_issuance: BiMap::new_bin(1, &f("annualized_issuance")),
yearly_inflation_rate: BiMap::new_bin(1, &f("yearly_inflation_rate")),
fees_1y_sum: DateMap::new_bin(1, MapKind::Computed, &f("fees_1y_sum")),
fees_in_dollars_1y_sum: DateMap::new_bin(
1,
MapKind::Computed,
&f("fees_in_dollars_1y_sum"),
),
cumulative_fees: BiMap::new_bin(1, MapKind::Computed, &f("cumulative_fees")),
cumulative_fees_in_dollars: BiMap::new_bin(
1,
MapKind::Computed,
&f("cumulative_fees_in_dollars"),
),
subsidy_1y_sum: DateMap::new_bin(1, MapKind::Computed, &f("subsidy_1y_sum")),
subsidy_in_dollars_1y_sum: DateMap::new_bin(
1,
MapKind::Computed,
&f("subsidy_in_dollars_1y_sum"),
),
cumulative_subsidy: BiMap::new_bin(1, MapKind::Computed, &f("cumulative_subsidy")),
cumulative_subsidy_in_dollars: BiMap::new_bin(
1,
MapKind::Computed,
&f("cumulative_subsidy_in_dollars"),
),
last_subsidy: DateMap::new_bin(1, &f("last_subsidy")),
last_subsidy_in_dollars: DateMap::new_bin(1, &f("last_subsidy_in_dollars")),
last_coinbase: DateMap::new_bin(1, &f("last_coinbase")),
last_coinbase_in_dollars: DateMap::new_bin(1, &f("last_coinbase_in_dollars")),
last_fees: DateMap::new_bin(1, &f("last_fees")),
last_fees_in_dollars: DateMap::new_bin(1, &f("last_fees_in_dollars")),
blocks_mined_1d_target: DateMap::new_bin(1, &f("blocks_mined_1d_target")),
blocks_mined_1w_sma: DateMap::new_bin(1, &f("blocks_mined_1w_sma")),
blocks_mined_1m_sma: DateMap::new_bin(1, &f("blocks_mined_1m_sma")),
blocks_mined_1w_sum: DateMap::new_bin(1, &f("blocks_mined_1w_sum")),
blocks_mined_1m_sum: DateMap::new_bin(1, &f("blocks_mined_1m_sum")),
blocks_mined_1y_sum: DateMap::new_bin(1, &f("blocks_mined_1y_sum")),
blocks_mined_1w_target: DateMap::new_bin(1, &f("blocks_mined_1w_target")),
blocks_mined_1m_target: DateMap::new_bin(1, &f("blocks_mined_1m_target")),
blocks_mined_1y_target: DateMap::new_bin(1, &f("blocks_mined_1y_target")),
difficulty: BiMap::new_bin(1, &f("difficulty")),
difficulty_adjustment: DateMap::new_bin(1, &f("difficulty_adjustment")),
block_size: HeightMap::new_bin(1, &f("block_size")),
subsidy_to_coinbase_ratio: HeightMap::new_bin(
1,
MapKind::Computed,
&f("subsidy_to_coinbase_ratio"),
),
subsidy_to_coinbase_1d_ratio: DateMap::new_bin(
1,
MapKind::Computed,
&f("subsidy_to_coinbase_1d_ratio"),
),
fees_to_coinbase_ratio: HeightMap::new_bin(
1,
MapKind::Computed,
&f("fees_to_coinbase_ratio"),
),
fees_to_coinbase_1d_ratio: DateMap::new_bin(
1,
MapKind::Computed,
&f("fees_to_coinbase_1d_ratio"),
),
annualized_issuance: DateMap::new_bin(1, MapKind::Computed, &f("annualized_issuance")),
inflation_rate: DateMap::new_bin(2, MapKind::Computed, &f("inflation_rate")),
yearly_inflation_rate: DateMap::new_bin(
1,
MapKind::Computed,
&f("yearly_inflation_rate"),
),
blocks_mined_1d_target: DateMap::new_bin(
1,
MapKind::Computed,
&f("blocks_mined_1d_target"),
),
blocks_mined_1w_sma: DateMap::new_bin(1, MapKind::Computed, &f("blocks_mined_1w_sma")),
blocks_mined_1m_sma: DateMap::new_bin(1, MapKind::Computed, &f("blocks_mined_1m_sma")),
blocks_mined_1w_sum: DateMap::new_bin(1, MapKind::Computed, &f("blocks_mined_1w_sum")),
blocks_mined_1m_sum: DateMap::new_bin(1, MapKind::Computed, &f("blocks_mined_1m_sum")),
blocks_mined_1y_sum: DateMap::new_bin(1, MapKind::Computed, &f("blocks_mined_1y_sum")),
blocks_mined_1w_target: DateMap::new_bin(
1,
MapKind::Computed,
&f("blocks_mined_1w_target"),
),
blocks_mined_1m_target: DateMap::new_bin(
1,
MapKind::Computed,
&f("blocks_mined_1m_target"),
),
blocks_mined_1y_target: DateMap::new_bin(
1,
MapKind::Computed,
&f("blocks_mined_1y_target"),
),
difficulty_adjustment: DateMap::new_bin(
1,
MapKind::Computed,
&f("difficulty_adjustment"),
),
block_size_recap: RecapDataset::import(
&f("block_size_1d"),
RecapOptions::default()
@@ -197,8 +302,16 @@ impl MiningDataset {
.add_10p()
.add_min(),
)?,
cumulative_block_size: BiMap::new_bin(1, &f("cumulative_block_size")),
block_weight: HeightMap::new_bin(1, &f("block_weight")),
cumulative_block_size: BiMap::new_bin(
1,
MapKind::Computed,
&f("cumulative_block_size"),
),
cumulative_block_size_gigabytes: BiMap::new_bin(
1,
MapKind::Computed,
&f("cumulative_block_size_gigabytes"),
),
block_weight_recap: RecapDataset::import(
&f("block_weight_1d"),
RecapOptions::default()
@@ -211,7 +324,6 @@ impl MiningDataset {
.add_10p()
.add_min(),
)?,
block_vbytes: HeightMap::new_bin(1, &f("block_vbytes")),
block_vbytes_recap: RecapDataset::import(
&f("block_vbytes_1d"),
RecapOptions::default()
@@ -224,8 +336,6 @@ impl MiningDataset {
.add_10p()
.add_min(),
)?,
// block_vbytes_1d_sma: HeightMap::new_bin(1, &f("block_vbytes")),
block_interval: HeightMap::new_bin(2, &f("block_interval")),
block_interval_recap: RecapDataset::import(
&f("block_interval_1d"),
RecapOptions::default()
@@ -238,16 +348,18 @@ impl MiningDataset {
.add_10p()
.add_min(),
)?,
hash_rate: DateMap::new_bin(1, &f("hash_rate")),
hash_rate_1w_sma: DateMap::new_bin(1, &f("hash_rate_1w_sma")),
hash_rate_1m_sma: DateMap::new_bin(1, &f("hash_rate_1m_sma")),
hash_rate_2m_sma: DateMap::new_bin(1, &f("hash_rate_2m_sma")),
hash_price: DateMap::new_bin(1, &f("hash_price")),
puell_multiple: DateMap::new_bin(1, &f("puell_multiple")),
hash_rate: DateMap::new_bin(1, MapKind::Computed, &f("hash_rate")),
hash_rate_1w_sma: DateMap::new_bin(1, MapKind::Computed, &f("hash_rate_1w_sma")),
hash_rate_1m_sma: DateMap::new_bin(1, MapKind::Computed, &f("hash_rate_1m_sma")),
hash_rate_2m_sma: DateMap::new_bin(1, MapKind::Computed, &f("hash_rate_2m_sma")),
hash_price: DateMap::new_bin(1, MapKind::Computed, &f("hash_price")),
hash_price_min: DateMap::new_bin(1, MapKind::Computed, &f("hash_price_min")),
hash_price_rebound: DateMap::new_bin(1, MapKind::Computed, &f("hash_price_rebound")),
puell_multiple: DateMap::new_bin(1, MapKind::Computed, &f("puell_multiple")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
.consume(MinInitialStates::compute_from_dataset(&s, config));
Ok(s)
}
@@ -271,28 +383,25 @@ impl MiningDataset {
..
}: &InsertData,
) {
self.coinbase.height.insert(height, coinbase.to_btc());
self.coinbase.insert(height, coinbase.to_btc());
let coinbase_in_dollars = self
.coinbase_in_dollars
.height
.insert(height, (block_price * coinbase).to_dollar() as f32);
let sumed_fees = Amount::from_sat(fees.iter().map(|amount| amount.to_sat()).sum());
self.fees.height.insert(height, sumed_fees.to_btc());
self.fees.insert(height, sumed_fees.to_btc());
let sumed_fees_in_dollars = self
.fees_in_dollars
.height
.insert(height, (block_price * sumed_fees).to_dollar() as f32);
let subsidy = coinbase - sumed_fees;
self.subsidy.height.insert(height, subsidy.to_btc());
self.subsidy.insert(height, subsidy.to_btc());
let subsidy_in_dollars = self
.subsidy_in_dollars
.height
.insert(height, (block_price * subsidy).to_dollar() as f32);
self.difficulty.height.insert(height, difficulty);
@@ -302,23 +411,26 @@ impl MiningDataset {
self.block_weight
.insert(height, block_weight as f32 / BYTES_IN_MB as f32);
self.block_vbytes.insert(height, block_vbytes);
self.block_interval.insert(height, block_interval);
self.block_interval.insert(height, *block_interval);
if is_date_last_block {
self.coinbase.date_insert_sum_range(date, date_blocks_range);
self.coinbase_1d_sum
.insert(date, self.coinbase.sum_range(date_blocks_range));
self.coinbase_in_dollars
.date_insert_sum_range(date, date_blocks_range);
self.coinbase_in_dollars_1d_sum
.insert(date, self.coinbase_in_dollars.sum_range(date_blocks_range));
self.fees.date_insert_sum_range(date, date_blocks_range);
self.fees_1d_sum
.insert(date, self.fees.sum_range(date_blocks_range));
self.fees_in_dollars
.date_insert_sum_range(date, date_blocks_range);
self.fees_in_dollars_1d_sum
.insert(date, self.fees_in_dollars.sum_range(date_blocks_range));
self.subsidy.date_insert_sum_range(date, date_blocks_range);
self.subsidy_1d_sum
.insert(date, self.subsidy.sum_range(date_blocks_range));
self.subsidy_in_dollars
.date_insert_sum_range(date, date_blocks_range);
self.subsidy_in_dollars_1d_sum
.insert(date, self.subsidy_in_dollars.sum_range(date_blocks_range));
self.last_coinbase.insert(date, coinbase.to_btc());
@@ -370,96 +482,128 @@ impl MiningDataset {
self.subsidy_1y_sum.multi_insert_last_x_sum(
dates,
&mut self.subsidy.date,
&mut self.subsidy_1d_sum,
ONE_YEAR_IN_DAYS,
);
self.subsidy_in_dollars_1y_sum.multi_insert_last_x_sum(
dates,
&mut self.subsidy_in_dollars.date,
&mut self.subsidy_in_dollars_1d_sum,
ONE_YEAR_IN_DAYS,
);
self.cumulative_subsidy
.multi_insert_cumulative(heights, dates, &mut self.subsidy);
.height
.multi_insert_cumulative(heights, &mut self.subsidy);
self.cumulative_subsidy
.date
.multi_insert_cumulative(dates, &mut self.subsidy_1d_sum);
self.cumulative_subsidy_in_dollars.multi_insert_cumulative(
heights,
dates,
&mut self.subsidy_in_dollars,
);
self.cumulative_subsidy_in_dollars
.height
.multi_insert_cumulative(heights, &mut self.subsidy_in_dollars);
self.cumulative_subsidy_in_dollars
.date
.multi_insert_cumulative(dates, &mut self.subsidy_in_dollars_1d_sum);
self.fees_1y_sum
.multi_insert_last_x_sum(dates, &mut self.fees.date, ONE_YEAR_IN_DAYS);
.multi_insert_last_x_sum(dates, &mut self.fees_1d_sum, ONE_YEAR_IN_DAYS);
self.fees_in_dollars_1y_sum.multi_insert_last_x_sum(
dates,
&mut self.fees_in_dollars.date,
&mut self.fees_in_dollars_1d_sum,
ONE_YEAR_IN_DAYS,
);
self.cumulative_fees
.multi_insert_cumulative(heights, dates, &mut self.fees);
.height
.multi_insert_cumulative(heights, &mut self.fees);
self.cumulative_fees
.date
.multi_insert_cumulative(dates, &mut self.fees_1d_sum);
self.cumulative_fees_in_dollars.multi_insert_cumulative(
heights,
dates,
&mut self.fees_in_dollars,
);
self.cumulative_fees_in_dollars
.height
.multi_insert_cumulative(heights, &mut self.fees_in_dollars);
self.cumulative_fees_in_dollars
.date
.multi_insert_cumulative(dates, &mut self.fees_in_dollars_1d_sum);
self.coinbase_1y_sum.multi_insert_last_x_sum(
dates,
&mut self.coinbase.date,
&mut self.coinbase_1d_sum,
ONE_YEAR_IN_DAYS,
);
self.coinbase_in_dollars_1y_sum.multi_insert_last_x_sum(
dates,
&mut self.coinbase_in_dollars.date,
&mut self.coinbase_in_dollars_1d_sum,
ONE_YEAR_IN_DAYS,
);
self.coinbase_in_dollars_1y_sma.multi_insert_simple_average(
dates,
&mut self.coinbase_in_dollars.date,
ONE_YEAR_IN_DAYS,
);
self.coinbase_in_dollars_1d_sum_1y_sma
.multi_insert_simple_average(
dates,
&mut self.coinbase_in_dollars_1d_sum,
ONE_YEAR_IN_DAYS,
);
self.cumulative_coinbase
.multi_insert_cumulative(heights, dates, &mut self.coinbase);
.height
.multi_insert_cumulative(heights, &mut self.coinbase);
self.cumulative_coinbase
.date
.multi_insert_cumulative(dates, &mut self.coinbase_1d_sum);
self.cumulative_coinbase_in_dollars.multi_insert_cumulative(
heights,
dates,
&mut self.coinbase_in_dollars,
);
self.cumulative_coinbase_in_dollars
.height
.multi_insert_cumulative(heights, &mut self.coinbase_in_dollars);
self.cumulative_coinbase_in_dollars
.date
.multi_insert_cumulative(dates, &mut self.coinbase_in_dollars_1d_sum);
self.subsidy_to_coinbase_ratio.multi_insert_percentage(
heights,
dates,
&mut self.subsidy,
&mut self.coinbase,
);
self.subsidy_to_coinbase_1d_ratio.multi_insert_percentage(
dates,
&mut self.subsidy_1d_sum,
&mut self.coinbase_1d_sum,
);
self.fees_to_coinbase_ratio.multi_insert_percentage(
heights,
dates,
&mut self.fees,
&mut self.coinbase,
);
self.fees_to_coinbase_1d_ratio.multi_insert_percentage(
dates,
&mut self.fees_1d_sum,
&mut self.coinbase_1d_sum,
);
self.annualized_issuance.multi_insert_last_x_sum(
heights,
dates,
&mut self.subsidy,
&mut self.subsidy_1d_sum,
ONE_YEAR_IN_DAYS,
);
self.inflation_rate.multi_insert_simple_transform(
dates,
&mut self.subsidy_1d_sum,
|subsidy_1d_sum, date| {
subsidy_1d_sum * ONE_YEAR_IN_DAYS as f64
/ self.cumulative_subsidy.date.get_or_import(date).unwrap()
* 100.0
},
);
self.yearly_inflation_rate.multi_insert_percentage(
heights,
dates,
&mut self.annualized_issuance,
&mut self.cumulative_subsidy,
&mut self.cumulative_subsidy.date,
);
self.blocks_mined_1d_target
@@ -496,13 +640,24 @@ impl MiningDataset {
last_height,
);
self.cumulative_block_size
.height
.multi_insert_cumulative(heights, &mut self.block_size);
self.cumulative_block_size_gigabytes
.multi_insert_simple_transform(heights, dates, &mut self.cumulative_block_size, &|v| {
v / 1000.0
});
// https://hashrateindex.com/blog/what-is-bitcoins-hashrate/
self.hash_rate.multi_insert(dates, |date| {
let blocks_mined = self.blocks_mined.get_or_import(date).unwrap();
let difficulty = self.difficulty.date.get_or_import(date).unwrap();
((blocks_mined as f64 / TARGET_BLOCKS_PER_DAY as f64) * difficulty * 2.0_f64.powi(32))
(blocks_mined as f64 / (date.get_day_completion() * TARGET_BLOCKS_PER_DAY as f64)
* difficulty
* 2.0_f64.powi(32))
/ 600.0
/ 1_000_000_000_000_000_000.0
});
@@ -526,17 +681,31 @@ impl MiningDataset {
);
self.hash_price.multi_insert(dates, |date| {
let coinbase_in_dollars = self.coinbase_in_dollars.date.get_or_import(date).unwrap();
let coinbase_in_dollars = self.coinbase_in_dollars_1d_sum.get_or_import(date).unwrap();
let hashrate = self.hash_rate.get_or_import(date).unwrap();
let hash_rate = self.hash_rate.get_or_import(date).unwrap();
coinbase_in_dollars as f64 / hashrate / 1_000.0
coinbase_in_dollars as f64 / hash_rate / 1_000.0
});
self.hash_price_min
.multi_insert_min(dates, &mut self.hash_price, 0.0);
self.hash_price_rebound.multi_insert_percentage(
dates,
&mut self.hash_price,
&mut self.hash_price_min,
);
self.puell_multiple.multi_insert_divide(
dates,
&mut self.coinbase_in_dollars.date,
&mut self.coinbase_in_dollars_1y_sma,
&mut self.coinbase_in_dollars_1d_sum,
&mut self.coinbase_in_dollars_1d_sum_1y_sma,
);
self.puell_multiple.multi_insert_divide(
dates,
&mut self.coinbase_in_dollars_1d_sum,
&mut self.coinbase_in_dollars_1d_sum_1y_sma,
);
self.difficulty_adjustment.multi_insert_percentage_change(
@@ -588,188 +757,4 @@ impl AnyDataset for MiningDataset {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![
&self.coinbase,
&self.coinbase_in_dollars,
&self.fees,
&self.fees_in_dollars,
&self.subsidy,
&self.subsidy_in_dollars,
&self.difficulty,
]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![
&mut self.coinbase,
&mut self.coinbase_in_dollars,
&mut self.fees,
&mut self.fees_in_dollars,
&mut self.subsidy,
&mut self.subsidy_in_dollars,
&mut self.difficulty,
]
}
fn to_inserted_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
vec![
&self.total_blocks_mined,
&self.blocks_mined,
&self.last_subsidy,
&self.last_subsidy_in_dollars,
&self.last_coinbase,
&self.last_coinbase_in_dollars,
&self.last_fees,
&self.last_fees_in_dollars,
]
}
fn to_inserted_mut_date_map_vec(&mut self) -> Vec<&mut dyn AnyDateMap> {
vec![
&mut self.total_blocks_mined,
&mut self.blocks_mined,
&mut self.last_subsidy,
&mut self.last_subsidy_in_dollars,
&mut self.last_coinbase,
&mut self.last_coinbase_in_dollars,
&mut self.last_fees,
&mut self.last_fees_in_dollars,
]
}
fn to_inserted_height_map_vec(&self) -> Vec<&(dyn AnyHeightMap + Send + Sync)> {
vec![
&self.block_size,
&self.block_weight,
&self.block_vbytes,
&self.block_interval,
]
}
fn to_inserted_mut_height_map_vec(&mut self) -> Vec<&mut dyn AnyHeightMap> {
vec![
&mut self.block_size,
&mut self.block_weight,
&mut self.block_vbytes,
&mut self.block_interval,
]
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![
&self.cumulative_coinbase,
&self.cumulative_coinbase_in_dollars,
&self.cumulative_fees,
&self.cumulative_fees_in_dollars,
&self.cumulative_subsidy,
&self.cumulative_subsidy_in_dollars,
&self.annualized_issuance,
&self.yearly_inflation_rate,
&self.cumulative_block_size,
&self.subsidy_to_coinbase_ratio,
&self.fees_to_coinbase_ratio,
]
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![
&mut self.cumulative_coinbase,
&mut self.cumulative_coinbase_in_dollars,
&mut self.cumulative_fees,
&mut self.cumulative_fees_in_dollars,
&mut self.cumulative_subsidy,
&mut self.cumulative_subsidy_in_dollars,
&mut self.annualized_issuance,
&mut self.yearly_inflation_rate,
&mut self.cumulative_block_size,
&mut self.subsidy_to_coinbase_ratio,
&mut self.fees_to_coinbase_ratio,
]
}
fn to_computed_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
[
&self.blocks_mined_1d_target as &(dyn AnyDateMap + Send + Sync),
&self.blocks_mined_1w_sma,
&self.blocks_mined_1m_sma,
&self.blocks_mined_1w_sum,
&self.blocks_mined_1m_sum,
&self.blocks_mined_1y_sum,
&self.blocks_mined_1w_target,
&self.blocks_mined_1m_target,
&self.blocks_mined_1y_target,
&self.subsidy_1y_sum,
&self.subsidy_in_dollars_1y_sum,
&self.coinbase_1y_sum,
&self.coinbase_in_dollars_1y_sum,
&self.coinbase_in_dollars_1y_sma,
&self.fees_1y_sum,
&self.fees_in_dollars_1y_sum,
&self.hash_rate,
&self.hash_rate_1w_sma,
&self.hash_rate_1m_sma,
&self.hash_rate_2m_sma,
&self.hash_price,
&self.puell_multiple,
&self.difficulty_adjustment,
]
.into_iter()
.chain(date_map_vec_to_any_date_map_vec(
self.block_size_recap.as_vec(),
))
.chain(date_map_vec_to_any_date_map_vec(
self.block_vbytes_recap.as_vec(),
))
.chain(date_map_vec_to_any_date_map_vec(
self.block_weight_recap.as_vec(),
))
.chain(date_map_vec_to_any_date_map_vec(
self.block_interval_recap.as_vec(),
))
.collect_vec()
}
fn to_computed_mut_date_map_vec(&mut self) -> Vec<&mut dyn AnyDateMap> {
[
&mut self.blocks_mined_1d_target as &mut dyn AnyDateMap,
&mut self.blocks_mined_1w_sma,
&mut self.blocks_mined_1m_sma,
&mut self.blocks_mined_1w_sum,
&mut self.blocks_mined_1m_sum,
&mut self.blocks_mined_1y_sum,
&mut self.blocks_mined_1w_target,
&mut self.blocks_mined_1m_target,
&mut self.blocks_mined_1y_target,
&mut self.subsidy_1y_sum,
&mut self.subsidy_in_dollars_1y_sum,
&mut self.coinbase_1y_sum,
&mut self.coinbase_in_dollars_1y_sum,
&mut self.coinbase_in_dollars_1y_sma,
&mut self.fees_1y_sum,
&mut self.fees_in_dollars_1y_sum,
&mut self.hash_rate,
&mut self.hash_rate_1w_sma,
&mut self.hash_rate_1m_sma,
&mut self.hash_rate_2m_sma,
&mut self.hash_price,
&mut self.puell_multiple,
&mut self.difficulty_adjustment,
]
.into_iter()
.chain(date_map_vec_to_mut_any_date_map_vec(
self.block_size_recap.as_mut_vec(),
))
.chain(date_map_vec_to_mut_any_date_map_vec(
self.block_vbytes_recap.as_mut_vec(),
))
.chain(date_map_vec_to_mut_any_date_map_vec(
self.block_weight_recap.as_mut_vec(),
))
.chain(date_map_vec_to_mut_any_date_map_vec(
self.block_interval_recap.as_mut_vec(),
))
.collect_vec()
}
}
+66 -31
View File
@@ -28,13 +28,14 @@ pub use constant::*;
pub use date_metadata::*;
pub use mining::*;
pub use price::*;
use serde_json::Value;
pub use subs::*;
pub use transaction::*;
pub use utxo::*;
use crate::{
databases::Databases,
io::Json,
io::{Json, JSON_EXTENSION},
states::{
AddressCohortsInputStates,
AddressCohortsOneShotStates,
@@ -44,7 +45,7 @@ use crate::{
// UTXOCohortsReceivedStates,
UTXOCohortsSentStates,
},
structs::{Amount, Date, Height, Price},
structs::{Amount, Config, Date, Height, Price, Timestamp},
};
pub struct InsertData<'a> {
@@ -52,7 +53,7 @@ pub struct InsertData<'a> {
pub address_cohorts_one_shot_states: &'a Option<AddressCohortsOneShotStates>,
pub address_cohorts_realized_states: &'a Option<AddressCohortsRealizedStates>,
pub amount_sent: Amount,
pub block_interval: u32,
pub block_interval: Timestamp,
pub block_price: Price,
pub block_size: usize,
pub block_vbytes: u64,
@@ -70,7 +71,7 @@ pub struct InsertData<'a> {
pub satblocks_destroyed: Amount,
pub satdays_destroyed: Amount,
pub states: &'a States,
pub timestamp: u32,
pub timestamp: Timestamp,
pub transaction_count: usize,
pub utxo_cohorts_one_shot_states: &'a UTXOCohortsOneShotStates,
// pub utxo_cohorts_received_states: &'a UTXOCohortsReceivedStates,
@@ -98,29 +99,31 @@ pub struct AllDatasets {
pub utxo: UTXODatasets,
}
const DATASETS_PATH: &str = "../datasets";
impl AllDatasets {
pub fn import() -> color_eyre::Result<Self> {
let path = "../datasets";
pub fn import(config: &Config) -> color_eyre::Result<Self> {
let path = DATASETS_PATH;
let price = PriceDatasets::import(path)?;
let price = PriceDatasets::import(path, config)?;
let constant = ConstantDataset::import(path)?;
let constant = ConstantDataset::import(path, config)?;
let date_metadata = DateMetadataDataset::import(path)?;
let date_metadata = DateMetadataDataset::import(path, config)?;
let cointime = CointimeDataset::import(path)?;
let cointime = CointimeDataset::import(path, config)?;
let coindays = CoindaysDataset::import(path)?;
let coindays = CoindaysDataset::import(path, config)?;
let mining = MiningDataset::import(path)?;
let mining = MiningDataset::import(path, config)?;
let block_metadata = BlockMetadataDataset::import(path)?;
let block_metadata = BlockMetadataDataset::import(path, config)?;
let transaction = TransactionDataset::import(path)?;
let transaction = TransactionDataset::import(path, config)?;
let address = AddressDatasets::import(path)?;
let address = AddressDatasets::import(path, config)?;
let utxo = UTXODatasets::import(path)?;
let utxo = UTXODatasets::import(path, config)?;
let mut s = Self {
min_initial_states: MinInitialStates::default(),
@@ -138,7 +141,7 @@ impl AllDatasets {
};
s.min_initial_states
.consume(MinInitialStates::compute_from_datasets(&s));
.consume(MinInitialStates::compute_from_datasets(&s, config));
s.export_meta_files()?;
@@ -146,7 +149,9 @@ impl AllDatasets {
}
pub fn insert(&mut self, insert_data: InsertData) {
self.address.insert(&insert_data);
if insert_data.compute_addresses {
self.address.insert(&insert_data);
}
self.utxo.insert(&insert_data);
@@ -212,14 +217,14 @@ impl AllDatasets {
self.address.compute(
&compute_data,
&mut self.price.closes,
&mut self.price.close,
&mut self.mining.cumulative_subsidy,
&mut self.price.market_cap,
);
self.utxo.compute(
&compute_data,
&mut self.price.closes,
&mut self.price.close,
&mut self.mining.cumulative_subsidy,
&mut self.price.market_cap,
);
@@ -252,10 +257,11 @@ impl AllDatasets {
&compute_data,
&mut self.date_metadata.first_height,
&mut self.date_metadata.last_height,
&mut self.price.closes,
&mut self.price.close,
&mut self.mining.cumulative_subsidy,
&mut self.address.cohorts.all.all.capitalization.realized_cap,
&mut self.address.cohorts.all.all.capitalization.realized_price,
&mut self.address.cohorts.all.subs.capitalization.realized_cap,
&mut self.address.cohorts.all.subs.capitalization.realized_price,
&mut self.mining.inflation_rate,
&mut self.mining.yearly_inflation_rate,
&mut self.transaction.annualized_volume,
&mut self.mining.cumulative_subsidy_in_dollars,
@@ -264,17 +270,15 @@ impl AllDatasets {
}
pub fn export_meta_files(&self) -> color_eyre::Result<()> {
let path_to_type: BTreeMap<&Path, &str> = self
let mut path_to_type: BTreeMap<&Path, &str> = self
.to_any_dataset_vec()
.into_iter()
.flat_map(|dataset| {
dataset
.to_all_map_vec()
.into_iter()
.flat_map(|map| map.exported_path_with_t_name())
})
.flat_map(|dataset| dataset.to_all_map_vec())
.flat_map(|map| map.exported_path_with_t_name())
.collect();
path_to_type.insert(Path::new("../datasets/last"), "Value");
let datasets_len = path_to_type.len();
let server_inputs_path = "../server/in";
@@ -310,9 +314,40 @@ impl AllDatasets {
.into_par_iter()
.try_for_each(|dataset| -> color_eyre::Result<()> { dataset.export() })?;
let mut path_to_last: BTreeMap<String, Value> = BTreeMap::default();
self.to_mut_any_dataset_vec()
.into_iter()
.for_each(|dataset| dataset.post_export());
.for_each(|dataset| {
dataset.post_export();
dataset.to_all_map_vec().iter().for_each(|map| {
if let Some(last_path) = map.path_last() {
if let Some(last_value) = map.last_value() {
let mut last_path = last_path.clone();
last_path.pop();
let last_path = last_path.to_str().unwrap();
let skip = if last_path.starts_with(DATASETS_PATH) {
2
} else {
1
};
path_to_last.insert(
last_path.split('/').skip(skip).join("-").to_string(),
last_value,
);
}
}
});
});
Json::export(
Path::new(&format!("{DATASETS_PATH}/last.{JSON_EXTENSION}")),
&path_to_last,
)?;
Ok(())
}
@@ -1,25 +1,23 @@
mod ohlc;
use std::collections::BTreeMap;
use allocative::Allocative;
use chrono::{Days, NaiveDateTime, NaiveTime, TimeZone, Timelike, Utc};
use chrono::Days;
use color_eyre::eyre::Error;
pub use ohlc::*;
use struct_iterable::Iterable;
use crate::{
price::{Binance, Kibo, Kraken},
structs::{
AnyBiMap, AnyDateMap, BiMap, Date, DateMap, DateMapChunkId, Height, HeightMapChunkId,
MapKey,
Amount, BiMap, Config, Date, DateMap, DateMapChunkId, Height, HeightMapChunkId, MapKey,
MapKind, Timestamp, OHLC,
},
utils::{ONE_MONTH_IN_DAYS, ONE_WEEK_IN_DAYS, ONE_YEAR_IN_DAYS},
};
use super::{AnyDataset, ComputeData, MinInitialStates, RatioDataset};
#[derive(Allocative)]
#[derive(Allocative, Iterable)]
pub struct PriceDatasets {
min_initial_states: MinInitialStates,
@@ -31,11 +29,11 @@ pub struct PriceDatasets {
kibo_by_height: BTreeMap<HeightMapChunkId, Vec<OHLC>>,
kibo_by_date: BTreeMap<DateMapChunkId, BTreeMap<Date, OHLC>>,
// Inserted
pub ohlcs: BiMap<OHLC>,
// Computed
pub closes: BiMap<f32>,
pub ohlc: BiMap<OHLC>,
pub open: BiMap<f32>,
pub high: BiMap<f32>,
pub low: BiMap<f32>,
pub close: BiMap<f32>,
pub market_cap: BiMap<f32>,
pub price_1w_sma: BiMap<f32>,
pub price_1w_sma_ratio: RatioDataset,
@@ -75,13 +73,19 @@ pub struct PriceDatasets {
pub price_10y_total_return: DateMap<f32>,
pub price_4y_compound_return: DateMap<f32>,
// projection via lowest 4y compound value
pub all_time_high: BiMap<f32>,
pub all_time_high_date: DateMap<Date>,
pub days_since_all_time_high: DateMap<u32>,
pub max_days_between_all_time_highs: DateMap<u32>,
pub max_years_between_all_time_highs: DateMap<f32>,
pub market_price_to_all_time_high_ratio: BiMap<f32>,
pub drawdown: BiMap<f32>,
pub sats_per_dollar: BiMap<f32>,
// volatility
// drawdown
// sats per dollar
}
impl PriceDatasets {
pub fn import(datasets_path: &str) -> color_eyre::Result<Self> {
pub fn import(datasets_path: &str, config: &Config) -> color_eyre::Result<Self> {
let price_path = "../price";
let f = |s: &str| format!("{datasets_path}/{s}");
@@ -97,50 +101,128 @@ impl PriceDatasets {
kibo_by_height: BTreeMap::default(),
kibo_by_date: BTreeMap::default(),
ohlcs: BiMap::new_json(1, price_path),
closes: BiMap::new_bin(1, &f("close")),
market_cap: BiMap::new_bin(1, &f("market_cap")),
price_1w_sma: BiMap::new_bin(1, &f("price_1w_sma")),
price_1w_sma_ratio: RatioDataset::import(datasets_path, "price_1w_sma")?,
price_1m_sma: BiMap::new_bin(1, &f("price_1m_sma")),
price_1m_sma_ratio: RatioDataset::import(datasets_path, "price_1m_sma")?,
price_1y_sma: BiMap::new_bin(1, &f("price_1y_sma")),
price_1y_sma_ratio: RatioDataset::import(datasets_path, "price_1y_sma")?,
price_2y_sma: BiMap::new_bin(1, &f("price_2y_sma")),
price_2y_sma_ratio: RatioDataset::import(datasets_path, "price_2y_sma")?,
price_4y_sma: BiMap::new_bin(1, &f("price_4y_sma")),
price_4y_sma_ratio: RatioDataset::import(datasets_path, "price_4y_sma")?,
price_8d_sma: BiMap::new_bin(1, &f("price_8d_sma")),
price_8d_sma_ratio: RatioDataset::import(datasets_path, "price_8d_sma")?,
price_13d_sma: BiMap::new_bin(1, &f("price_13d_sma")),
price_13d_sma_ratio: RatioDataset::import(datasets_path, "price_13d_sma")?,
price_21d_sma: BiMap::new_bin(1, &f("price_21d_sma")),
price_21d_sma_ratio: RatioDataset::import(datasets_path, "price_21d_sma")?,
price_34d_sma: BiMap::new_bin(1, &f("price_34d_sma")),
price_34d_sma_ratio: RatioDataset::import(datasets_path, "price_34d_sma")?,
price_55d_sma: BiMap::new_bin(1, &f("price_55d_sma")),
price_55d_sma_ratio: RatioDataset::import(datasets_path, "price_55d_sma")?,
price_89d_sma: BiMap::new_bin(1, &f("price_89d_sma")),
price_89d_sma_ratio: RatioDataset::import(datasets_path, "price_89d_sma")?,
price_144d_sma: BiMap::new_bin(1, &f("price_144d_sma")),
price_144d_sma_ratio: RatioDataset::import(datasets_path, "price_144d_sma")?,
price_200w_sma: BiMap::new_bin(1, &f("price_200w_sma")),
price_200w_sma_ratio: RatioDataset::import(datasets_path, "price_200w_sma")?,
price_1d_total_return: DateMap::new_bin(1, &f("price_1d_total_return")),
price_1m_total_return: DateMap::new_bin(1, &f("price_1m_total_return")),
price_6m_total_return: DateMap::new_bin(1, &f("price_6m_total_return")),
price_1y_total_return: DateMap::new_bin(1, &f("price_1y_total_return")),
price_2y_total_return: DateMap::new_bin(1, &f("price_2y_total_return")),
price_3y_total_return: DateMap::new_bin(1, &f("price_3y_total_return")),
price_4y_total_return: DateMap::new_bin(1, &f("price_4y_total_return")),
price_6y_total_return: DateMap::new_bin(1, &f("price_6y_total_return")),
price_8y_total_return: DateMap::new_bin(1, &f("price_8y_total_return")),
price_10y_total_return: DateMap::new_bin(1, &f("price_10y_total_return")),
price_4y_compound_return: DateMap::new_bin(1, &f("price_4y_compound_return")),
// ---
// Inserted
// ---
ohlc: BiMap::new_json(1, MapKind::Inserted, price_path),
// ---
// Computed
// ---
open: BiMap::new_bin(1, MapKind::Computed, &f("open")),
high: BiMap::new_bin(1, MapKind::Computed, &f("high")),
low: BiMap::new_bin(1, MapKind::Computed, &f("low")),
close: BiMap::new_bin(1, MapKind::Computed, &f("close")),
market_cap: BiMap::new_bin(1, MapKind::Computed, &f("market_cap")),
price_1w_sma: BiMap::new_bin(1, MapKind::Computed, &f("price_1w_sma")),
price_1w_sma_ratio: RatioDataset::import(datasets_path, "price_1w_sma", config)?,
price_1m_sma: BiMap::new_bin(1, MapKind::Computed, &f("price_1m_sma")),
price_1m_sma_ratio: RatioDataset::import(datasets_path, "price_1m_sma", config)?,
price_1y_sma: BiMap::new_bin(1, MapKind::Computed, &f("price_1y_sma")),
price_1y_sma_ratio: RatioDataset::import(datasets_path, "price_1y_sma", config)?,
price_2y_sma: BiMap::new_bin(1, MapKind::Computed, &f("price_2y_sma")),
price_2y_sma_ratio: RatioDataset::import(datasets_path, "price_2y_sma", config)?,
price_4y_sma: BiMap::new_bin(1, MapKind::Computed, &f("price_4y_sma")),
price_4y_sma_ratio: RatioDataset::import(datasets_path, "price_4y_sma", config)?,
price_8d_sma: BiMap::new_bin(1, MapKind::Computed, &f("price_8d_sma")),
price_8d_sma_ratio: RatioDataset::import(datasets_path, "price_8d_sma", config)?,
price_13d_sma: BiMap::new_bin(1, MapKind::Computed, &f("price_13d_sma")),
price_13d_sma_ratio: RatioDataset::import(datasets_path, "price_13d_sma", config)?,
price_21d_sma: BiMap::new_bin(1, MapKind::Computed, &f("price_21d_sma")),
price_21d_sma_ratio: RatioDataset::import(datasets_path, "price_21d_sma", config)?,
price_34d_sma: BiMap::new_bin(1, MapKind::Computed, &f("price_34d_sma")),
price_34d_sma_ratio: RatioDataset::import(datasets_path, "price_34d_sma", config)?,
price_55d_sma: BiMap::new_bin(1, MapKind::Computed, &f("price_55d_sma")),
price_55d_sma_ratio: RatioDataset::import(datasets_path, "price_55d_sma", config)?,
price_89d_sma: BiMap::new_bin(1, MapKind::Computed, &f("price_89d_sma")),
price_89d_sma_ratio: RatioDataset::import(datasets_path, "price_89d_sma", config)?,
price_144d_sma: BiMap::new_bin(1, MapKind::Computed, &f("price_144d_sma")),
price_144d_sma_ratio: RatioDataset::import(datasets_path, "price_144d_sma", config)?,
price_200w_sma: BiMap::new_bin(1, MapKind::Computed, &f("price_200w_sma")),
price_200w_sma_ratio: RatioDataset::import(datasets_path, "price_200w_sma", config)?,
price_1d_total_return: DateMap::new_bin(
1,
MapKind::Computed,
&f("price_1d_total_return"),
),
price_1m_total_return: DateMap::new_bin(
1,
MapKind::Computed,
&f("price_1m_total_return"),
),
price_6m_total_return: DateMap::new_bin(
1,
MapKind::Computed,
&f("price_6m_total_return"),
),
price_1y_total_return: DateMap::new_bin(
1,
MapKind::Computed,
&f("price_1y_total_return"),
),
price_2y_total_return: DateMap::new_bin(
1,
MapKind::Computed,
&f("price_2y_total_return"),
),
price_3y_total_return: DateMap::new_bin(
1,
MapKind::Computed,
&f("price_3y_total_return"),
),
price_4y_total_return: DateMap::new_bin(
1,
MapKind::Computed,
&f("price_4y_total_return"),
),
price_6y_total_return: DateMap::new_bin(
1,
MapKind::Computed,
&f("price_6y_total_return"),
),
price_8y_total_return: DateMap::new_bin(
1,
MapKind::Computed,
&f("price_8y_total_return"),
),
price_10y_total_return: DateMap::new_bin(
1,
MapKind::Computed,
&f("price_10y_total_return"),
),
price_4y_compound_return: DateMap::new_bin(
1,
MapKind::Computed,
&f("price_4y_compound_return"),
),
all_time_high: BiMap::new_bin(1, MapKind::Computed, &f("all_time_high")),
all_time_high_date: DateMap::new_bin(1, MapKind::Computed, &f("all_time_high_date")),
days_since_all_time_high: DateMap::new_bin(
1,
MapKind::Computed,
&f("days_since_all_time_high"),
),
max_days_between_all_time_highs: DateMap::new_bin(
1,
MapKind::Computed,
&f("max_days_between_all_time_highs"),
),
max_years_between_all_time_highs: DateMap::new_bin(
2,
MapKind::Computed,
&f("max_years_between_all_time_highs"),
),
market_price_to_all_time_high_ratio: BiMap::new_bin(
1,
MapKind::Computed,
&f("market_price_to_all_time_high_ratio"),
),
drawdown: BiMap::new_bin(1, MapKind::Computed, &f("drawdown")),
sats_per_dollar: BiMap::new_bin(1, MapKind::Computed, &f("sats_per_dollar")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
.consume(MinInitialStates::compute_from_dataset(&s, config));
Ok(s)
}
@@ -148,128 +230,137 @@ impl PriceDatasets {
pub fn compute(&mut self, compute_data: &ComputeData, circulating_supply: &mut BiMap<f64>) {
let &ComputeData { dates, heights, .. } = compute_data;
self.closes
.multi_insert_simple_transform(heights, dates, &mut self.ohlcs, &|ohlc| ohlc.close);
self.open
.multi_insert_simple_transform(heights, dates, &mut self.ohlc, &|ohlc| ohlc.open);
self.high
.multi_insert_simple_transform(heights, dates, &mut self.ohlc, &|ohlc| ohlc.high);
self.low
.multi_insert_simple_transform(heights, dates, &mut self.ohlc, &|ohlc| ohlc.low);
self.close
.multi_insert_simple_transform(heights, dates, &mut self.ohlc, &|ohlc| ohlc.close);
self.market_cap
.multi_insert_multiply(heights, dates, &mut self.closes, circulating_supply);
.multi_insert_multiply(heights, dates, &mut self.close, circulating_supply);
self.price_1w_sma.multi_insert_simple_average(
heights,
dates,
&mut self.closes,
&mut self.close,
ONE_WEEK_IN_DAYS,
);
self.price_1m_sma.multi_insert_simple_average(
heights,
dates,
&mut self.closes,
&mut self.close,
ONE_MONTH_IN_DAYS,
);
self.price_1y_sma.multi_insert_simple_average(
heights,
dates,
&mut self.closes,
&mut self.close,
ONE_YEAR_IN_DAYS,
);
self.price_2y_sma.multi_insert_simple_average(
heights,
dates,
&mut self.closes,
&mut self.close,
2 * ONE_YEAR_IN_DAYS,
);
self.price_4y_sma.multi_insert_simple_average(
heights,
dates,
&mut self.closes,
&mut self.close,
4 * ONE_YEAR_IN_DAYS,
);
self.price_8d_sma
.multi_insert_simple_average(heights, dates, &mut self.closes, 8);
.multi_insert_simple_average(heights, dates, &mut self.close, 8);
self.price_13d_sma
.multi_insert_simple_average(heights, dates, &mut self.closes, 13);
.multi_insert_simple_average(heights, dates, &mut self.close, 13);
self.price_21d_sma
.multi_insert_simple_average(heights, dates, &mut self.closes, 21);
.multi_insert_simple_average(heights, dates, &mut self.close, 21);
self.price_34d_sma
.multi_insert_simple_average(heights, dates, &mut self.closes, 34);
.multi_insert_simple_average(heights, dates, &mut self.close, 34);
self.price_55d_sma
.multi_insert_simple_average(heights, dates, &mut self.closes, 55);
.multi_insert_simple_average(heights, dates, &mut self.close, 55);
self.price_89d_sma
.multi_insert_simple_average(heights, dates, &mut self.closes, 89);
.multi_insert_simple_average(heights, dates, &mut self.close, 89);
self.price_144d_sma
.multi_insert_simple_average(heights, dates, &mut self.closes, 144);
.multi_insert_simple_average(heights, dates, &mut self.close, 144);
self.price_200w_sma.multi_insert_simple_average(
heights,
dates,
&mut self.closes,
&mut self.close,
200 * ONE_WEEK_IN_DAYS,
);
self.price_1d_total_return
.multi_insert_percentage_change(dates, &mut self.closes.date, 1);
.multi_insert_percentage_change(dates, &mut self.close.date, 1);
self.price_1m_total_return.multi_insert_percentage_change(
dates,
&mut self.closes.date,
&mut self.close.date,
ONE_MONTH_IN_DAYS,
);
self.price_6m_total_return.multi_insert_percentage_change(
dates,
&mut self.closes.date,
&mut self.close.date,
6 * ONE_MONTH_IN_DAYS,
);
self.price_1y_total_return.multi_insert_percentage_change(
dates,
&mut self.closes.date,
&mut self.close.date,
ONE_YEAR_IN_DAYS,
);
self.price_2y_total_return.multi_insert_percentage_change(
dates,
&mut self.closes.date,
&mut self.close.date,
2 * ONE_YEAR_IN_DAYS,
);
self.price_3y_total_return.multi_insert_percentage_change(
dates,
&mut self.closes.date,
&mut self.close.date,
3 * ONE_YEAR_IN_DAYS,
);
self.price_4y_total_return.multi_insert_percentage_change(
dates,
&mut self.closes.date,
&mut self.close.date,
4 * ONE_YEAR_IN_DAYS,
);
self.price_6y_total_return.multi_insert_percentage_change(
dates,
&mut self.closes.date,
&mut self.close.date,
6 * ONE_YEAR_IN_DAYS,
);
self.price_8y_total_return.multi_insert_percentage_change(
dates,
&mut self.closes.date,
&mut self.close.date,
8 * ONE_YEAR_IN_DAYS,
);
self.price_10y_total_return.multi_insert_percentage_change(
dates,
&mut self.closes.date,
&mut self.close.date,
10 * ONE_YEAR_IN_DAYS,
);
self.price_4y_compound_return
.multi_insert_complex_transform(
dates,
&mut self.closes.date,
|(last_value, date, closes)| {
&mut self.close.date,
|(last_value, date, closes, _)| {
let previous_value = date
.checked_sub_days(Days::new(4 * ONE_YEAR_IN_DAYS as u64))
.and_then(|date| closes.get_or_import(&Date::wrap(date)))
@@ -280,43 +371,95 @@ impl PriceDatasets {
);
self.price_1w_sma_ratio
.compute(compute_data, &mut self.closes, &mut self.price_1w_sma);
.compute(compute_data, &mut self.close, &mut self.price_1w_sma);
self.price_1m_sma_ratio
.compute(compute_data, &mut self.closes, &mut self.price_1m_sma);
.compute(compute_data, &mut self.close, &mut self.price_1m_sma);
self.price_1y_sma_ratio
.compute(compute_data, &mut self.closes, &mut self.price_1y_sma);
.compute(compute_data, &mut self.close, &mut self.price_1y_sma);
self.price_2y_sma_ratio
.compute(compute_data, &mut self.closes, &mut self.price_2y_sma);
.compute(compute_data, &mut self.close, &mut self.price_2y_sma);
self.price_4y_sma_ratio
.compute(compute_data, &mut self.closes, &mut self.price_4y_sma);
.compute(compute_data, &mut self.close, &mut self.price_4y_sma);
self.price_8d_sma_ratio
.compute(compute_data, &mut self.closes, &mut self.price_8d_sma);
.compute(compute_data, &mut self.close, &mut self.price_8d_sma);
self.price_13d_sma_ratio
.compute(compute_data, &mut self.closes, &mut self.price_13d_sma);
.compute(compute_data, &mut self.close, &mut self.price_13d_sma);
self.price_21d_sma_ratio
.compute(compute_data, &mut self.closes, &mut self.price_21d_sma);
.compute(compute_data, &mut self.close, &mut self.price_21d_sma);
self.price_34d_sma_ratio
.compute(compute_data, &mut self.closes, &mut self.price_34d_sma);
.compute(compute_data, &mut self.close, &mut self.price_34d_sma);
self.price_55d_sma_ratio
.compute(compute_data, &mut self.closes, &mut self.price_55d_sma);
.compute(compute_data, &mut self.close, &mut self.price_55d_sma);
self.price_89d_sma_ratio
.compute(compute_data, &mut self.closes, &mut self.price_89d_sma);
.compute(compute_data, &mut self.close, &mut self.price_89d_sma);
self.price_144d_sma_ratio
.compute(compute_data, &mut self.closes, &mut self.price_144d_sma);
.compute(compute_data, &mut self.close, &mut self.price_144d_sma);
self.price_200w_sma_ratio
.compute(compute_data, &mut self.closes, &mut self.price_200w_sma);
.compute(compute_data, &mut self.close, &mut self.price_200w_sma);
self.all_time_high
.multi_insert_max(heights, dates, &mut self.high);
self.market_price_to_all_time_high_ratio
.multi_insert_percentage(heights, dates, &mut self.close, &mut self.all_time_high);
self.all_time_high_date.multi_insert_complex_transform(
dates,
&mut self.all_time_high.date,
|(value, date, _, map)| {
let high = self.high.date.get_or_import(date).unwrap();
let is_ath = high == value;
if is_ath {
*date
} else {
let previous_date = date.checked_sub(1).unwrap();
*map.get_or_import(&previous_date).as_ref().unwrap_or(date)
}
},
);
self.days_since_all_time_high.multi_insert_simple_transform(
dates,
&mut self.all_time_high_date,
|value, key| key.difference_in_days_between(value),
);
self.max_days_between_all_time_highs
.multi_insert_max(dates, &mut self.days_since_all_time_high);
self.max_years_between_all_time_highs
.multi_insert_simple_transform(
dates,
&mut self.max_days_between_all_time_highs,
|days, _| (days as f64 / ONE_YEAR_IN_DAYS as f64) as f32,
);
self.drawdown.multi_insert_simple_transform(
heights,
dates,
&mut self.market_price_to_all_time_high_ratio,
&|v| -(100.0 - v),
);
self.sats_per_dollar.multi_insert_simple_transform(
heights,
dates,
&mut self.close,
&|price| Amount::ONE_BTC_F32 / price,
);
}
pub fn get_date_ohlc(&mut self, date: Date) -> color_eyre::Result<OHLC> {
if self.ohlcs.date.is_key_safe(date) {
Ok(self.ohlcs.date.get(&date).unwrap().to_owned())
if self.ohlc.date.is_key_safe(date) {
Ok(self.ohlc.date.get_or_import(&date).unwrap().to_owned())
} else {
let ohlc = self
.get_from_daily_kraken(&date)
.or_else(|_| self.get_from_daily_binance(&date))
.or_else(|_| self.get_from_date_kibo(&date))?;
self.ohlcs.date.insert(date, ohlc);
self.ohlc.date.insert(date, ohlc);
Ok(ohlc)
}
@@ -395,31 +538,20 @@ impl PriceDatasets {
pub fn get_height_ohlc(
&mut self,
height: Height,
timestamp: u32,
previous_timestamp: Option<u32>,
timestamp: Timestamp,
previous_timestamp: Option<Timestamp>,
) -> color_eyre::Result<OHLC> {
if let Some(ohlc) = self.ohlcs.height.get(&height) {
if let Some(ohlc) = self.ohlc.height.get_or_import(&height) {
return Ok(ohlc);
}
let clean_timestamp = |timestamp| {
let date_time = Utc.timestamp_opt(i64::from(timestamp), 0).unwrap();
NaiveDateTime::new(
date_time.date_naive(),
NaiveTime::from_hms_opt(date_time.hour(), date_time.minute(), 0).unwrap(),
)
.and_utc()
.timestamp() as u32
};
let timestamp = clean_timestamp(timestamp);
let timestamp = timestamp.to_floored_seconds();
if previous_timestamp.is_none() && !height.is_first() {
panic!("Shouldn't be possible");
}
let previous_timestamp = previous_timestamp.map(clean_timestamp);
let previous_timestamp = previous_timestamp.map(|t| t.to_floored_seconds());
let ohlc = self
.get_from_1mn_kraken(timestamp, previous_timestamp)
@@ -429,7 +561,7 @@ impl PriceDatasets {
self.get_from_har_binance(timestamp, previous_timestamp)
.unwrap_or_else(|_| {
self.get_from_height_kibo(&height).unwrap_or_else(|_| {
let date = Date::from_timestamp(timestamp);
let date = timestamp.to_date();
panic!(
"Can't find the price for: height: {height} - date: {date}
@@ -451,7 +583,7 @@ How to fix this:
})
});
self.ohlcs.height.insert(height, ohlc);
self.ohlc.height.insert(height, ohlc);
Ok(ohlc)
}
@@ -478,8 +610,8 @@ How to fix this:
fn get_from_1mn_kraken(
&mut self,
timestamp: u32,
previous_timestamp: Option<u32>,
timestamp: Timestamp,
previous_timestamp: Option<Timestamp>,
) -> color_eyre::Result<OHLC> {
if self.kraken_1mn.is_none()
|| self
@@ -499,8 +631,8 @@ How to fix this:
fn get_from_1mn_binance(
&mut self,
timestamp: u32,
previous_timestamp: Option<u32>,
timestamp: Timestamp,
previous_timestamp: Option<Timestamp>,
) -> color_eyre::Result<OHLC> {
if self.binance_1mn.is_none()
|| self
@@ -525,8 +657,8 @@ How to fix this:
fn get_from_har_binance(
&mut self,
timestamp: u32,
previous_timestamp: Option<u32>,
timestamp: Timestamp,
previous_timestamp: Option<Timestamp>,
) -> color_eyre::Result<OHLC> {
if self.binance_har.is_none() {
self.binance_har
@@ -543,8 +675,8 @@ How to fix this:
fn find_height_ohlc(
tree: &Option<BTreeMap<u32, OHLC>>,
timestamp: u32,
previous_timestamp: Option<u32>,
timestamp: Timestamp,
previous_timestamp: Option<Timestamp>,
name: &str,
) -> color_eyre::Result<OHLC> {
let tree = tree.as_ref().unwrap();
@@ -571,12 +703,12 @@ How to fix this:
close: previous_ohlc.close,
};
let start = previous_timestamp.unwrap_or(0);
let start = previous_timestamp.unwrap_or_default();
let end = timestamp;
// Otherwise it's a re-org
if start < end {
tree.range(&start..=&end).skip(1).for_each(|(_, ohlc)| {
tree.range(&*start..=&*end).skip(1).for_each(|(_, ohlc)| {
if ohlc.high > final_ohlc.high {
final_ohlc.high = ohlc.high
}
@@ -597,116 +729,4 @@ impl AnyDataset for PriceDatasets {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![&self.ohlcs]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.ohlcs]
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
let mut v = vec![
&self.closes as &(dyn AnyBiMap + Send + Sync),
&self.market_cap,
&self.price_1w_sma,
&self.price_1m_sma,
&self.price_1y_sma,
&self.price_2y_sma,
&self.price_4y_sma,
&self.price_8d_sma,
&self.price_13d_sma,
&self.price_21d_sma,
&self.price_34d_sma,
&self.price_55d_sma,
&self.price_89d_sma,
&self.price_144d_sma,
&self.price_200w_sma,
];
v.append(&mut self.price_1w_sma_ratio.to_computed_bi_map_vec());
v.append(&mut self.price_1m_sma_ratio.to_computed_bi_map_vec());
v.append(&mut self.price_1y_sma_ratio.to_computed_bi_map_vec());
v.append(&mut self.price_2y_sma_ratio.to_computed_bi_map_vec());
v.append(&mut self.price_4y_sma_ratio.to_computed_bi_map_vec());
v.append(&mut self.price_8d_sma_ratio.to_computed_bi_map_vec());
v.append(&mut self.price_13d_sma_ratio.to_computed_bi_map_vec());
v.append(&mut self.price_21d_sma_ratio.to_computed_bi_map_vec());
v.append(&mut self.price_34d_sma_ratio.to_computed_bi_map_vec());
v.append(&mut self.price_55d_sma_ratio.to_computed_bi_map_vec());
v.append(&mut self.price_89d_sma_ratio.to_computed_bi_map_vec());
v.append(&mut self.price_144d_sma_ratio.to_computed_bi_map_vec());
v.append(&mut self.price_200w_sma_ratio.to_computed_bi_map_vec());
v
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
let mut v = vec![
&mut self.closes as &mut dyn AnyBiMap,
&mut self.market_cap,
&mut self.price_1w_sma,
&mut self.price_1m_sma,
&mut self.price_1y_sma,
&mut self.price_2y_sma,
&mut self.price_4y_sma,
&mut self.price_8d_sma,
&mut self.price_13d_sma,
&mut self.price_21d_sma,
&mut self.price_34d_sma,
&mut self.price_55d_sma,
&mut self.price_89d_sma,
&mut self.price_144d_sma,
&mut self.price_200w_sma,
];
v.append(&mut self.price_1w_sma_ratio.to_computed_mut_bi_map_vec());
v.append(&mut self.price_1m_sma_ratio.to_computed_mut_bi_map_vec());
v.append(&mut self.price_1y_sma_ratio.to_computed_mut_bi_map_vec());
v.append(&mut self.price_2y_sma_ratio.to_computed_mut_bi_map_vec());
v.append(&mut self.price_4y_sma_ratio.to_computed_mut_bi_map_vec());
v.append(&mut self.price_8d_sma_ratio.to_computed_mut_bi_map_vec());
v.append(&mut self.price_13d_sma_ratio.to_computed_mut_bi_map_vec());
v.append(&mut self.price_21d_sma_ratio.to_computed_mut_bi_map_vec());
v.append(&mut self.price_34d_sma_ratio.to_computed_mut_bi_map_vec());
v.append(&mut self.price_55d_sma_ratio.to_computed_mut_bi_map_vec());
v.append(&mut self.price_89d_sma_ratio.to_computed_mut_bi_map_vec());
v.append(&mut self.price_144d_sma_ratio.to_computed_mut_bi_map_vec());
v.append(&mut self.price_200w_sma_ratio.to_computed_mut_bi_map_vec());
v
}
fn to_computed_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
vec![
&self.price_1d_total_return,
&self.price_1m_total_return,
&self.price_6m_total_return,
&self.price_1y_total_return,
&self.price_2y_total_return,
&self.price_3y_total_return,
&self.price_4y_total_return,
&self.price_6y_total_return,
&self.price_8y_total_return,
&self.price_10y_total_return,
&self.price_4y_compound_return,
]
}
fn to_computed_mut_date_map_vec(&mut self) -> Vec<&mut dyn AnyDateMap> {
vec![
&mut self.price_1d_total_return,
&mut self.price_1m_total_return,
&mut self.price_6m_total_return,
&mut self.price_1y_total_return,
&mut self.price_2y_total_return,
&mut self.price_3y_total_return,
&mut self.price_4y_total_return,
&mut self.price_6y_total_return,
&mut self.price_8y_total_return,
&mut self.price_10y_total_return,
&mut self.price_4y_compound_return,
]
}
}
+25 -37
View File
@@ -1,29 +1,31 @@
use allocative::Allocative;
use struct_iterable::Iterable;
use crate::{
datasets::{AnyDataset, ComputeData, InsertData, MinInitialStates},
states::CapitalizationState,
structs::{AnyBiMap, BiMap},
structs::{BiMap, Config, MapKind},
utils::ONE_MONTH_IN_DAYS,
};
use super::RatioDataset;
#[derive(Default, Allocative)]
#[derive(Allocative, Iterable)]
pub struct CapitalizationDataset {
min_initial_states: MinInitialStates,
// Inserted
pub realized_cap: BiMap<f32>,
// Computed
pub realized_price: BiMap<f32>,
realized_cap_1m_net_change: BiMap<f32>,
realized_price_ratio: RatioDataset,
}
impl CapitalizationDataset {
pub fn import(parent_path: &str, name: &Option<String>) -> color_eyre::Result<Self> {
pub fn import(
parent_path: &str,
name: &Option<String>,
config: &Config,
) -> color_eyre::Result<Self> {
let f = |s: &str| {
if let Some(name) = name {
format!("{parent_path}/{name}/{s}")
@@ -35,20 +37,32 @@ impl CapitalizationDataset {
let mut s = Self {
min_initial_states: MinInitialStates::default(),
realized_cap: BiMap::new_bin(1, &f("realized_cap")),
realized_cap_1m_net_change: BiMap::new_bin(1, &f("realized_cap_1m_net_change")),
realized_price: BiMap::new_bin(1, &f("realized_price")),
// ---
// Inserted
// ---
realized_cap: BiMap::new_bin(1, MapKind::Inserted, &f("realized_cap")),
// ---
// Computed
// ---
realized_cap_1m_net_change: BiMap::new_bin(
1,
MapKind::Computed,
&f("realized_cap_1m_net_change"),
),
realized_price: BiMap::new_bin(1, MapKind::Computed, &f("realized_price")),
realized_price_ratio: RatioDataset::import(
parent_path,
&format!(
"{}realized_price",
name.as_ref().map_or("".to_owned(), |n| format!("{n}-"))
),
config,
)?,
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
.consume(MinInitialStates::compute_from_dataset(&s, config));
Ok(s)
}
@@ -66,7 +80,7 @@ impl CapitalizationDataset {
let realized_cap = self
.realized_cap
.height
.insert(height, state.realized_cap.to_dollar() as f32);
.insert(height, state.realized_cap().to_dollar() as f32);
if is_date_last_block {
self.realized_cap.date.insert(date, realized_cap);
@@ -104,30 +118,4 @@ impl AnyDataset for CapitalizationDataset {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![&self.realized_cap]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.realized_cap]
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
let mut v = vec![
&self.realized_price as &(dyn AnyBiMap + Send + Sync),
&self.realized_cap_1m_net_change,
];
v.append(&mut self.realized_price_ratio.to_computed_bi_map_vec());
v
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
let mut v = vec![
&mut self.realized_price as &mut dyn AnyBiMap,
&mut self.realized_cap_1m_net_change,
];
v.append(&mut self.realized_price_ratio.to_computed_mut_bi_map_vec());
v
}
}
+25 -18
View File
@@ -1,24 +1,31 @@
use allocative::Allocative;
use struct_iterable::Iterable;
use crate::{
datasets::{AnyDataset, InsertData, MinInitialStates},
states::InputState,
structs::{AnyBiMap, BiMap},
structs::{BiMap, Config, MapKind},
DateMap, HeightMap,
};
#[derive(Default, Allocative)]
#[derive(Allocative, Iterable)]
pub struct InputSubDataset {
min_initial_states: MinInitialStates,
// Inserted
pub count: BiMap<u64>,
pub volume: BiMap<f64>,
pub volume: HeightMap<f64>,
pub volume_1d_sum: DateMap<f64>,
// Computed
// add inputs_per_second
}
impl InputSubDataset {
pub fn import(parent_path: &str, name: &Option<String>) -> color_eyre::Result<Self> {
pub fn import(
parent_path: &str,
name: &Option<String>,
config: &Config,
) -> color_eyre::Result<Self> {
let f = |s: &str| {
if let Some(name) = name {
format!("{parent_path}/{name}/{s}")
@@ -30,12 +37,16 @@ impl InputSubDataset {
let mut s = Self {
min_initial_states: MinInitialStates::default(),
count: BiMap::new_bin(1, &f("input_count")),
volume: BiMap::new_bin(1, &f("input_volume")),
// ---
// Inserted
// ---
count: BiMap::new_bin(1, MapKind::Inserted, &f("input_count")),
volume: HeightMap::new_bin(1, MapKind::Inserted, &f("input_volume")),
volume_1d_sum: DateMap::new_bin(1, MapKind::Inserted, &f("input_volume_1d_sum")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
.consume(MinInitialStates::compute_from_dataset(&s, config));
Ok(s)
}
@@ -51,14 +62,18 @@ impl InputSubDataset {
}: &InsertData,
state: &InputState,
) {
let count = self.count.height.insert(height, state.count.round() as u64);
let count = self
.count
.height
.insert(height, state.count().round() as u64);
self.volume.height.insert(height, state.volume.to_btc());
self.volume.insert(height, state.volume().to_btc());
if is_date_last_block {
self.count.date.insert(date, count);
self.volume.date_insert_sum_range(date, date_blocks_range);
self.volume_1d_sum
.insert(date, self.volume.sum_range(date_blocks_range));
}
}
}
@@ -67,12 +82,4 @@ impl AnyDataset for InputSubDataset {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![&self.count, &self.volume]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.count, &mut self.volume]
}
}
+15 -10
View File
@@ -16,15 +16,16 @@ pub use price_paid::*;
pub use ratio::*;
pub use realized::*;
pub use recap::*;
use struct_iterable::Iterable;
pub use supply::*;
pub use unrealized::*;
pub use utxo::*;
use crate::datasets::AnyDataset;
use crate::{datasets::AnyDataset, structs::Config};
use super::AnyDatasetGroup;
#[derive(Default, Allocative)]
#[derive(Allocative, Iterable)]
pub struct SubDataset {
pub capitalization: CapitalizationDataset,
pub input: InputSubDataset,
@@ -37,16 +38,20 @@ pub struct SubDataset {
}
impl SubDataset {
pub fn import(parent_path: &str, name: &Option<String>) -> color_eyre::Result<Self> {
pub fn import(
parent_path: &str,
name: &Option<String>,
config: &Config,
) -> color_eyre::Result<Self> {
let s = Self {
capitalization: CapitalizationDataset::import(parent_path, name)?,
input: InputSubDataset::import(parent_path, name)?,
capitalization: CapitalizationDataset::import(parent_path, name, config)?,
input: InputSubDataset::import(parent_path, name, config)?,
// output: OutputSubDataset::import(parent_path)?,
price_paid: PricePaidSubDataset::import(parent_path, name)?,
realized: RealizedSubDataset::import(parent_path, name)?,
supply: SupplySubDataset::import(parent_path, name)?,
unrealized: UnrealizedSubDataset::import(parent_path, name)?,
utxo: UTXOSubDataset::import(parent_path, name)?,
price_paid: PricePaidSubDataset::import(parent_path, name, config)?,
realized: RealizedSubDataset::import(parent_path, name, config)?,
supply: SupplySubDataset::import(parent_path, name, config)?,
unrealized: UnrealizedSubDataset::import(parent_path, name, config)?,
utxo: UTXOSubDataset::import(parent_path, name, config)?,
};
Ok(s)
-16
View File
@@ -84,20 +84,4 @@ impl AnyDataset for OutputSubDataset {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![&self.count, &self.volume]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.count, &mut self.volume]
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![&self.annualized_volume, &self.velocity]
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.annualized_volume, &mut self.velocity]
}
}
+50 -85
View File
@@ -1,17 +1,16 @@
use allocative::Allocative;
use itertools::Itertools;
use struct_iterable::Iterable;
use crate::{
datasets::{AnyDataset, InsertData, MinInitialStates},
states::PricePaidState,
structs::{AnyBiMap, BiMap, Date, Height},
structs::{BiMap, Config, Date, Height, MapKind},
};
#[derive(Default, Allocative)]
#[derive(Allocative, Iterable)]
pub struct PricePaidSubDataset {
min_initial_states: MinInitialStates,
// Inserted
pp_median: BiMap<f32>,
pp_95p: BiMap<f32>,
pp_90p: BiMap<f32>,
@@ -34,7 +33,11 @@ pub struct PricePaidSubDataset {
}
impl PricePaidSubDataset {
pub fn import(parent_path: &str, name: &Option<String>) -> color_eyre::Result<Self> {
pub fn import(
parent_path: &str,
name: &Option<String>,
config: &Config,
) -> color_eyre::Result<Self> {
let f = |s: &str| {
if let Some(name) = name {
format!("{parent_path}/{name}/{s}")
@@ -46,29 +49,32 @@ impl PricePaidSubDataset {
let mut s = Self {
min_initial_states: MinInitialStates::default(),
pp_median: BiMap::new_bin(1, &f("median_price_paid")),
pp_95p: BiMap::new_bin(1, &f("95p_price_paid")),
pp_90p: BiMap::new_bin(1, &f("90p_price_paid")),
pp_85p: BiMap::new_bin(1, &f("85p_price_paid")),
pp_80p: BiMap::new_bin(1, &f("80p_price_paid")),
pp_75p: BiMap::new_bin(1, &f("75p_price_paid")),
pp_70p: BiMap::new_bin(1, &f("70p_price_paid")),
pp_65p: BiMap::new_bin(1, &f("65p_price_paid")),
pp_60p: BiMap::new_bin(1, &f("60p_price_paid")),
pp_55p: BiMap::new_bin(1, &f("55p_price_paid")),
pp_45p: BiMap::new_bin(1, &f("45p_price_paid")),
pp_40p: BiMap::new_bin(1, &f("40p_price_paid")),
pp_35p: BiMap::new_bin(1, &f("35p_price_paid")),
pp_30p: BiMap::new_bin(1, &f("30p_price_paid")),
pp_25p: BiMap::new_bin(1, &f("25p_price_paid")),
pp_20p: BiMap::new_bin(1, &f("20p_price_paid")),
pp_15p: BiMap::new_bin(1, &f("15p_price_paid")),
pp_10p: BiMap::new_bin(1, &f("10p_price_paid")),
pp_05p: BiMap::new_bin(1, &f("05p_price_paid")),
// ---
// Inserted
// ---
pp_median: BiMap::new_bin(1, MapKind::Inserted, &f("median_price_paid")),
pp_95p: BiMap::new_bin(1, MapKind::Inserted, &f("95p_price_paid")),
pp_90p: BiMap::new_bin(1, MapKind::Inserted, &f("90p_price_paid")),
pp_85p: BiMap::new_bin(1, MapKind::Inserted, &f("85p_price_paid")),
pp_80p: BiMap::new_bin(1, MapKind::Inserted, &f("80p_price_paid")),
pp_75p: BiMap::new_bin(1, MapKind::Inserted, &f("75p_price_paid")),
pp_70p: BiMap::new_bin(1, MapKind::Inserted, &f("70p_price_paid")),
pp_65p: BiMap::new_bin(1, MapKind::Inserted, &f("65p_price_paid")),
pp_60p: BiMap::new_bin(1, MapKind::Inserted, &f("60p_price_paid")),
pp_55p: BiMap::new_bin(1, MapKind::Inserted, &f("55p_price_paid")),
pp_45p: BiMap::new_bin(1, MapKind::Inserted, &f("45p_price_paid")),
pp_40p: BiMap::new_bin(1, MapKind::Inserted, &f("40p_price_paid")),
pp_35p: BiMap::new_bin(1, MapKind::Inserted, &f("35p_price_paid")),
pp_30p: BiMap::new_bin(1, MapKind::Inserted, &f("30p_price_paid")),
pp_25p: BiMap::new_bin(1, MapKind::Inserted, &f("25p_price_paid")),
pp_20p: BiMap::new_bin(1, MapKind::Inserted, &f("20p_price_paid")),
pp_15p: BiMap::new_bin(1, MapKind::Inserted, &f("15p_price_paid")),
pp_10p: BiMap::new_bin(1, MapKind::Inserted, &f("10p_price_paid")),
pp_05p: BiMap::new_bin(1, MapKind::Inserted, &f("05p_price_paid")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
.consume(MinInitialStates::compute_from_dataset(&s, config));
Ok(s)
}
@@ -83,28 +89,25 @@ impl PricePaidSubDataset {
}: &InsertData,
state: &PricePaidState,
) {
let PricePaidState {
pp_05p,
pp_10p,
pp_15p,
pp_20p,
pp_25p,
pp_30p,
pp_35p,
pp_40p,
pp_45p,
pp_median,
pp_55p,
pp_60p,
pp_65p,
pp_70p,
pp_75p,
pp_80p,
pp_85p,
pp_90p,
pp_95p,
..
} = state;
let pp_05p = state.pp_05p();
let pp_10p = state.pp_10p();
let pp_15p = state.pp_15p();
let pp_20p = state.pp_20p();
let pp_25p = state.pp_25p();
let pp_30p = state.pp_30p();
let pp_35p = state.pp_35p();
let pp_40p = state.pp_40p();
let pp_45p = state.pp_45p();
let pp_median = state.pp_median();
let pp_55p = state.pp_55p();
let pp_60p = state.pp_60p();
let pp_65p = state.pp_65p();
let pp_70p = state.pp_70p();
let pp_75p = state.pp_75p();
let pp_80p = state.pp_80p();
let pp_85p = state.pp_85p();
let pp_90p = state.pp_90p();
let pp_95p = state.pp_95p();
// Check if iter was empty
if pp_05p.is_none() {
@@ -229,30 +232,6 @@ impl PricePaidSubDataset {
})
}
pub fn inserted_as_vec(&self) -> Vec<&BiMap<f32>> {
vec![
&self.pp_95p,
&self.pp_90p,
&self.pp_85p,
&self.pp_80p,
&self.pp_75p,
&self.pp_70p,
&self.pp_65p,
&self.pp_60p,
&self.pp_55p,
&self.pp_median,
&self.pp_45p,
&self.pp_40p,
&self.pp_35p,
&self.pp_30p,
&self.pp_25p,
&self.pp_20p,
&self.pp_15p,
&self.pp_10p,
&self.pp_05p,
]
}
pub fn inserted_as_mut_vec(&mut self) -> Vec<&mut BiMap<f32>> {
vec![
&mut self.pp_95p,
@@ -282,18 +261,4 @@ impl AnyDataset for PricePaidSubDataset {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
self.inserted_as_vec()
.into_iter()
.map(|dataset| dataset as &(dyn AnyBiMap + Send + Sync))
.collect_vec()
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
self.inserted_as_mut_vec()
.into_iter()
.map(|dataset| dataset as &mut dyn AnyBiMap)
.collect_vec()
}
}
+26 -66
View File
@@ -1,16 +1,16 @@
use allocative::Allocative;
use struct_iterable::Iterable;
use crate::{
datasets::{AnyDataset, ComputeData, MinInitialStates},
structs::{AnyBiMap, BiMap},
structs::{BiMap, Config, MapKind},
utils::{ONE_MONTH_IN_DAYS, ONE_WEEK_IN_DAYS, ONE_YEAR_IN_DAYS},
};
#[derive(Default, Allocative)]
#[derive(Allocative, Iterable)]
pub struct RatioDataset {
min_initial_states: MinInitialStates,
// Computed
ratio: BiMap<f32>,
ratio_1w_sma: BiMap<f32>,
ratio_1m_sma: BiMap<f32>,
@@ -31,37 +31,41 @@ pub struct RatioDataset {
}
impl RatioDataset {
pub fn import(parent_path: &str, name: &str) -> color_eyre::Result<Self> {
pub fn import(parent_path: &str, name: &str, config: &Config) -> color_eyre::Result<Self> {
let f_ratio = |s: &str| format!("{parent_path}/market_price_to_{name}_{s}");
let f_price = |s: &str| format!("{parent_path}/{name}_{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
ratio: BiMap::new_bin(1, &f_ratio("ratio")),
ratio_1w_sma: BiMap::new_bin(2, &f_ratio("ratio_1w_sma")),
ratio_1m_sma: BiMap::new_bin(2, &f_ratio("ratio_1m_sma")),
ratio_1y_sma: BiMap::new_bin(2, &f_ratio("ratio_1y_sma")),
// ---
// Computed
// ---
ratio: BiMap::new_bin(1, MapKind::Computed, &f_ratio("ratio")),
ratio_1w_sma: BiMap::new_bin(2, MapKind::Computed, &f_ratio("ratio_1w_sma")),
ratio_1m_sma: BiMap::new_bin(2, MapKind::Computed, &f_ratio("ratio_1m_sma")),
ratio_1y_sma: BiMap::new_bin(2, MapKind::Computed, &f_ratio("ratio_1y_sma")),
ratio_1y_sma_momentum_oscillator: BiMap::new_bin(
2,
MapKind::Computed,
&f_ratio("ratio_1y_sma_momentum_oscillator"),
),
ratio_99p: BiMap::new_bin(3, &f_ratio("ratio_99p")),
ratio_99_5p: BiMap::new_bin(3, &f_ratio("ratio_99_5p")),
ratio_99_9p: BiMap::new_bin(3, &f_ratio("ratio_99_9p")),
ratio_1p: BiMap::new_bin(3, &f_ratio("ratio_1p")),
ratio_0_5p: BiMap::new_bin(3, &f_ratio("ratio_0_5p")),
ratio_0_1p: BiMap::new_bin(3, &f_ratio("ratio_0_1p")),
price_99p: BiMap::new_bin(4, &f_price("99p")),
price_99_5p: BiMap::new_bin(4, &f_price("99_5p")),
price_99_9p: BiMap::new_bin(4, &f_price("99_9p")),
price_1p: BiMap::new_bin(4, &f_price("1p")),
price_0_5p: BiMap::new_bin(4, &f_price("0_5p")),
price_0_1p: BiMap::new_bin(4, &f_price("0_1p")),
ratio_99p: BiMap::new_bin(3, MapKind::Computed, &f_ratio("ratio_99p")),
ratio_99_5p: BiMap::new_bin(3, MapKind::Computed, &f_ratio("ratio_99_5p")),
ratio_99_9p: BiMap::new_bin(3, MapKind::Computed, &f_ratio("ratio_99_9p")),
ratio_1p: BiMap::new_bin(3, MapKind::Computed, &f_ratio("ratio_1p")),
ratio_0_5p: BiMap::new_bin(3, MapKind::Computed, &f_ratio("ratio_0_5p")),
ratio_0_1p: BiMap::new_bin(3, MapKind::Computed, &f_ratio("ratio_0_1p")),
price_99p: BiMap::new_bin(4, MapKind::Computed, &f_price("99p")),
price_99_5p: BiMap::new_bin(4, MapKind::Computed, &f_price("99_5p")),
price_99_9p: BiMap::new_bin(4, MapKind::Computed, &f_price("99_9p")),
price_1p: BiMap::new_bin(4, MapKind::Computed, &f_price("1p")),
price_0_5p: BiMap::new_bin(4, MapKind::Computed, &f_price("0_5p")),
price_0_1p: BiMap::new_bin(4, MapKind::Computed, &f_price("0_1p")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
.consume(MinInitialStates::compute_from_dataset(&s, config));
Ok(s)
}
@@ -122,7 +126,7 @@ impl RatioDataset {
self.ratio_1y_sma_momentum_oscillator
.date
.multi_insert_complex_transform(dates, &mut self.ratio.date, |(ratio, date, _)| {
.multi_insert_complex_transform(dates, &mut self.ratio.date, |(ratio, date, _, _)| {
(ratio / self.ratio_1y_sma.date.get_or_import(date).unwrap()) - 1.0
});
@@ -164,48 +168,4 @@ impl AnyDataset for RatioDataset {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![
&self.ratio,
&self.ratio_1w_sma,
&self.ratio_1m_sma,
&self.ratio_1y_sma,
&self.ratio_1y_sma_momentum_oscillator,
&self.ratio_99p,
&self.ratio_99_5p,
&self.ratio_99_9p,
&self.ratio_1p,
&self.ratio_0_5p,
&self.ratio_0_1p,
&self.price_99p,
&self.price_99_5p,
&self.price_99_9p,
&self.price_1p,
&self.price_0_5p,
&self.price_0_1p,
]
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![
&mut self.ratio,
&mut self.ratio_1w_sma,
&mut self.ratio_1m_sma,
&mut self.ratio_1y_sma,
&mut self.ratio_1y_sma_momentum_oscillator,
&mut self.ratio_99p,
&mut self.ratio_99_5p,
&mut self.ratio_99_9p,
&mut self.ratio_1p,
&mut self.ratio_0_5p,
&mut self.ratio_0_1p,
&mut self.price_99p,
&mut self.price_99_5p,
&mut self.price_99_9p,
&mut self.price_1p,
&mut self.price_0_5p,
&mut self.price_0_1p,
]
}
}
+267 -111
View File
@@ -1,35 +1,54 @@
use allocative::Allocative;
use struct_iterable::Iterable;
use crate::{
datasets::{AnyDataset, ComputeData, InsertData, MinInitialStates},
states::RealizedState,
structs::{AnyBiMap, BiMap, Price},
structs::{BiMap, Config, MapKind, Price},
utils::ONE_MONTH_IN_DAYS,
DateMap, HeightMap,
};
#[derive(Default, Allocative)]
#[derive(Allocative, Iterable)]
pub struct RealizedSubDataset {
min_initial_states: MinInitialStates,
// Inserted
realized_profit: BiMap<f32>,
realized_loss: BiMap<f32>,
value_destroyed: BiMap<f32>,
value_created: BiMap<f32>,
realized_profit: HeightMap<f32>,
realized_loss: HeightMap<f32>,
value_created: HeightMap<f32>,
adjusted_value_created: HeightMap<f32>,
value_destroyed: HeightMap<f32>,
adjusted_value_destroyed: HeightMap<f32>,
realized_profit_1d_sum: DateMap<f32>,
realized_loss_1d_sum: DateMap<f32>,
value_created_1d_sum: DateMap<f32>,
adjusted_value_created_1d_sum: DateMap<f32>,
value_destroyed_1d_sum: DateMap<f32>,
adjusted_value_destroyed_1d_sum: DateMap<f32>,
spent_output_profit_ratio: BiMap<f32>,
// Computed
negative_realized_loss: BiMap<f32>,
net_realized_profit_and_loss: BiMap<f32>,
net_realized_profit_and_loss_to_market_cap_ratio: BiMap<f32>,
adjusted_spent_output_profit_ratio: BiMap<f32>,
negative_realized_loss: HeightMap<f32>,
negative_realized_loss_1d_sum: DateMap<f32>,
net_realized_profit_and_loss: HeightMap<f32>,
net_realized_profit_and_loss_1d_sum: DateMap<f32>,
net_realized_profit_and_loss_1d_sum_to_market_cap_ratio: DateMap<f32>,
cumulative_realized_profit: BiMap<f32>,
cumulative_realized_loss: BiMap<f32>,
cumulative_net_realized_profit_and_loss: BiMap<f32>,
cumulative_net_realized_profit_and_loss_1m_net_change: BiMap<f32>,
realized_value: HeightMap<f32>,
realized_value_1d_sum: DateMap<f32>,
sell_side_risk_ratio: DateMap<f32>,
realized_profit_to_loss_ratio: HeightMap<f32>,
realized_profit_to_loss_1d_sum_ratio: DateMap<f32>,
}
impl RealizedSubDataset {
pub fn import(parent_path: &str, name: &Option<String>) -> color_eyre::Result<Self> {
pub fn import(
parent_path: &str,
name: &Option<String>,
config: &Config,
) -> color_eyre::Result<Self> {
let f = |s: &str| {
if let Some(name) = name {
format!("{parent_path}/{name}/{s}")
@@ -41,32 +60,137 @@ impl RealizedSubDataset {
let mut s = Self {
min_initial_states: MinInitialStates::default(),
realized_profit: BiMap::new_bin(1, &f("realized_profit")),
realized_loss: BiMap::new_bin(1, &f("realized_loss")),
value_created: BiMap::new_bin(1, &f("value_created")),
value_destroyed: BiMap::new_bin(1, &f("value_destroyed")),
spent_output_profit_ratio: BiMap::new_bin(2, &f("spent_output_profit_ratio")),
negative_realized_loss: BiMap::new_bin(2, &f("negative_realized_loss")),
net_realized_profit_and_loss: BiMap::new_bin(1, &f("net_realized_profit_and_loss")),
net_realized_profit_and_loss_to_market_cap_ratio: BiMap::new_bin(
// ---
// Inserted
// ---
realized_profit: HeightMap::new_bin(1, MapKind::Inserted, &f("realized_profit")),
realized_loss: HeightMap::new_bin(1, MapKind::Inserted, &f("realized_loss")),
value_created: HeightMap::new_bin(1, MapKind::Inserted, &f("value_created")),
adjusted_value_created: HeightMap::new_bin(
1,
MapKind::Inserted,
&f("adjusted_value_created"),
),
value_destroyed: HeightMap::new_bin(1, MapKind::Inserted, &f("value_destroyed")),
adjusted_value_destroyed: HeightMap::new_bin(
1,
MapKind::Inserted,
&f("adjusted_value_destroyed"),
),
realized_profit_1d_sum: DateMap::new_bin(
1,
MapKind::Inserted,
&f("realized_profit_1d_sum"),
),
realized_loss_1d_sum: DateMap::new_bin(
1,
MapKind::Inserted,
&f("realized_loss_1d_sum"),
),
value_created_1d_sum: DateMap::new_bin(
1,
MapKind::Inserted,
&f("value_created_1d_sum"),
),
adjusted_value_created_1d_sum: DateMap::new_bin(
1,
MapKind::Inserted,
&f("adjusted_value_created_1d_sum"),
),
value_destroyed_1d_sum: DateMap::new_bin(
1,
MapKind::Inserted,
&f("value_destroyed_1d_sum"),
),
adjusted_value_destroyed_1d_sum: DateMap::new_bin(
1,
MapKind::Inserted,
&f("adjusted_value_destroyed_1d_sum"),
),
spent_output_profit_ratio: BiMap::new_bin(
2,
MapKind::Inserted,
&f("spent_output_profit_ratio"),
),
adjusted_spent_output_profit_ratio: BiMap::new_bin(
2,
MapKind::Inserted,
&f("adjusted_spent_output_profit_ratio"),
),
// ---
// Computed
// ---
negative_realized_loss: HeightMap::new_bin(
2,
MapKind::Computed,
&f("negative_realized_loss"),
),
negative_realized_loss_1d_sum: DateMap::new_bin(
2,
MapKind::Computed,
&f("negative_realized_loss_1d_sum"),
),
net_realized_profit_and_loss: HeightMap::new_bin(
1,
MapKind::Computed,
&f("net_realized_profit_and_loss"),
),
net_realized_profit_and_loss_1d_sum: DateMap::new_bin(
1,
MapKind::Computed,
&f("net_realized_profit_and_loss_1d_sum"),
),
net_realized_profit_and_loss_1d_sum_to_market_cap_ratio: DateMap::new_bin(
2,
MapKind::Computed,
&f("net_realized_profit_and_loss_to_market_cap_ratio"),
),
cumulative_realized_profit: BiMap::new_bin(1, &f("cumulative_realized_profit")),
cumulative_realized_loss: BiMap::new_bin(1, &f("cumulative_realized_loss")),
cumulative_realized_profit: BiMap::new_bin(
1,
MapKind::Computed,
&f("cumulative_realized_profit"),
),
cumulative_realized_loss: BiMap::new_bin(
1,
MapKind::Computed,
&f("cumulative_realized_loss"),
),
cumulative_net_realized_profit_and_loss: BiMap::new_bin(
1,
MapKind::Computed,
&f("cumulative_net_realized_profit_and_loss"),
),
cumulative_net_realized_profit_and_loss_1m_net_change: BiMap::new_bin(
1,
MapKind::Computed,
&f("cumulative_net_realized_profit_and_loss_1m_net_change"),
),
realized_value: HeightMap::new_bin(1, MapKind::Computed, &f("realized_value")),
realized_value_1d_sum: DateMap::new_bin(
1,
MapKind::Computed,
&f("realized_value_1d_sum"),
),
sell_side_risk_ratio: DateMap::new_bin(
1,
MapKind::Computed,
&f("sell_side_risk_ratio"),
),
realized_profit_to_loss_ratio: HeightMap::new_bin(
1,
MapKind::Computed,
&f("realized_profit_to_loss_ratio"),
),
realized_profit_to_loss_1d_sum_ratio: DateMap::new_bin(
1,
MapKind::Computed,
&f("realized_profit_to_loss_1d_sum_ratio"),
),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
.consume(MinInitialStates::compute_from_dataset(&s, config));
Ok(s)
}
@@ -83,47 +207,80 @@ impl RealizedSubDataset {
height_state: &RealizedState,
) {
self.realized_profit
.height
.insert(height, height_state.realized_profit.to_dollar() as f32);
.insert(height, height_state.realized_profit().to_dollar() as f32);
self.realized_loss
.height
.insert(height, height_state.realized_loss.to_dollar() as f32);
.insert(height, height_state.realized_loss().to_dollar() as f32);
self.value_created
.height
.insert(height, height_state.value_created.to_dollar() as f32);
.insert(height, height_state.value_created().to_dollar() as f32);
self.adjusted_value_created.insert(
height,
height_state.adjusted_value_created().to_dollar() as f32,
);
self.value_destroyed
.height
.insert(height, height_state.value_destroyed.to_dollar() as f32);
.insert(height, height_state.value_destroyed().to_dollar() as f32);
self.adjusted_value_destroyed.insert(
height,
height_state.adjusted_value_destroyed().to_dollar() as f32,
);
self.spent_output_profit_ratio.height.insert(height, {
if height_state.value_destroyed > Price::ZERO {
(height_state.value_created.to_cent() as f64
/ height_state.value_destroyed.to_cent() as f64) as f32
if height_state.value_destroyed() > Price::ZERO {
(height_state.value_created().to_cent() as f64
/ height_state.value_destroyed().to_cent() as f64) as f32
} else {
1.0
}
});
self.adjusted_spent_output_profit_ratio
.height
.insert(height, {
if height_state.adjusted_value_destroyed() > Price::ZERO {
(height_state.adjusted_value_created().to_cent() as f64
/ height_state.adjusted_value_destroyed().to_cent() as f64)
as f32
} else {
1.0
}
});
if is_date_last_block {
self.realized_profit
.date_insert_sum_range(date, date_blocks_range);
self.realized_profit_1d_sum
.insert(date, self.realized_profit.sum_range(date_blocks_range));
self.realized_loss
.date_insert_sum_range(date, date_blocks_range);
self.realized_loss_1d_sum
.insert(date, self.realized_loss.sum_range(date_blocks_range));
self.value_created
.date_insert_sum_range(date, date_blocks_range);
let value_created_1d_sum = self
.value_created_1d_sum
.insert(date, self.value_created.sum_range(date_blocks_range));
self.value_destroyed
.date_insert_sum_range(date, date_blocks_range);
self.spent_output_profit_ratio.date.insert(
let adjusted_value_created_1d_sum = self.adjusted_value_created_1d_sum.insert(
date,
self.value_created.height.sum_range(date_blocks_range)
/ self.value_destroyed.height.sum_range(date_blocks_range),
self.adjusted_value_created.sum_range(date_blocks_range),
);
let value_destroyed_1d_sum = self
.value_destroyed_1d_sum
.insert(date, self.value_destroyed.sum_range(date_blocks_range));
let adjusted_value_destroyed_1d_sum = self.adjusted_value_destroyed_1d_sum.insert(
date,
self.adjusted_value_destroyed.sum_range(date_blocks_range),
);
self.spent_output_profit_ratio
.date
.insert(date, value_created_1d_sum / value_destroyed_1d_sum);
self.adjusted_spent_output_profit_ratio.date.insert(
date,
adjusted_value_created_1d_sum / adjusted_value_destroyed_1d_sum,
);
}
}
@@ -135,40 +292,53 @@ impl RealizedSubDataset {
) {
self.negative_realized_loss.multi_insert_simple_transform(
heights,
dates,
&mut self.realized_loss,
&|v| v * -1.0,
|v, _| v * -1.0,
);
self.negative_realized_loss_1d_sum
.multi_insert_simple_transform(dates, &mut self.realized_loss_1d_sum, |v, _| v * -1.0);
self.net_realized_profit_and_loss.multi_insert_subtract(
heights,
dates,
&mut self.realized_profit,
&mut self.realized_loss,
);
self.net_realized_profit_and_loss_to_market_cap_ratio
.multi_insert_percentage(
heights,
self.net_realized_profit_and_loss_1d_sum
.multi_insert_subtract(
dates,
&mut self.net_realized_profit_and_loss,
market_cap,
&mut self.realized_profit_1d_sum,
&mut self.realized_loss_1d_sum,
);
self.cumulative_realized_profit.multi_insert_cumulative(
heights,
dates,
&mut self.realized_profit,
);
self.net_realized_profit_and_loss_1d_sum_to_market_cap_ratio
.multi_insert_percentage(
dates,
&mut self.net_realized_profit_and_loss_1d_sum,
&mut market_cap.date,
);
self.cumulative_realized_loss.multi_insert_cumulative(
heights,
dates,
&mut self.realized_loss,
);
self.cumulative_realized_profit
.height
.multi_insert_cumulative(heights, &mut self.realized_profit);
self.cumulative_realized_profit
.date
.multi_insert_cumulative(dates, &mut self.realized_profit_1d_sum);
self.cumulative_realized_loss
.height
.multi_insert_cumulative(heights, &mut self.realized_loss);
self.cumulative_realized_loss
.date
.multi_insert_cumulative(dates, &mut self.realized_loss_1d_sum);
self.cumulative_net_realized_profit_and_loss
.multi_insert_cumulative(heights, dates, &mut self.net_realized_profit_and_loss);
.height
.multi_insert_cumulative(heights, &mut self.net_realized_profit_and_loss);
self.cumulative_net_realized_profit_and_loss
.date
.multi_insert_cumulative(dates, &mut self.net_realized_profit_and_loss_1d_sum);
self.cumulative_net_realized_profit_and_loss_1m_net_change
.multi_insert_net_change(
@@ -177,6 +347,36 @@ impl RealizedSubDataset {
&mut self.cumulative_net_realized_profit_and_loss,
ONE_MONTH_IN_DAYS,
);
self.realized_value.multi_insert_add(
heights,
&mut self.realized_profit,
&mut self.realized_loss,
);
self.realized_value_1d_sum.multi_insert_add(
dates,
&mut self.realized_profit_1d_sum,
&mut self.realized_loss_1d_sum,
);
self.sell_side_risk_ratio.multi_insert_percentage(
dates,
&mut self.realized_value_1d_sum,
&mut market_cap.date,
);
self.realized_profit_to_loss_ratio.multi_insert_divide(
heights,
&mut self.realized_profit,
&mut self.realized_loss,
);
self.realized_profit_to_loss_1d_sum_ratio
.multi_insert_divide(
dates,
&mut self.realized_profit_1d_sum,
&mut self.realized_loss_1d_sum,
);
}
}
@@ -184,48 +384,4 @@ impl AnyDataset for RealizedSubDataset {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![
&self.realized_loss,
&self.realized_profit,
&self.value_created,
&self.value_destroyed,
&self.spent_output_profit_ratio,
]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![
&mut self.realized_loss,
&mut self.realized_profit,
&mut self.value_created,
&mut self.value_destroyed,
&mut self.spent_output_profit_ratio,
]
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![
&self.negative_realized_loss,
&self.net_realized_profit_and_loss,
&self.net_realized_profit_and_loss_to_market_cap_ratio,
&self.cumulative_realized_profit,
&self.cumulative_realized_loss,
&self.cumulative_net_realized_profit_and_loss,
&self.cumulative_net_realized_profit_and_loss_1m_net_change,
]
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![
&mut self.negative_realized_loss,
&mut self.net_realized_profit_and_loss,
&mut self.net_realized_profit_and_loss_to_market_cap_ratio,
&mut self.cumulative_realized_profit,
&mut self.cumulative_realized_loss,
&mut self.cumulative_net_realized_profit_and_loss,
&mut self.cumulative_net_realized_profit_and_loss_1m_net_change,
]
}
}
+38 -115
View File
@@ -3,7 +3,7 @@ use std::{iter::Sum, ops::Add};
use allocative::Allocative;
use crate::{
structs::{DateMapChunkId, GenericMap, MapKey, MapSerialized, MapValue},
structs::{DateMapChunkId, GenericMap, MapKey, MapKind, MapSerialized, MapValue},
utils::{get_percentile, LossyFrom},
Date, MapChunkId, SerializedBTreeMap,
};
@@ -95,17 +95,36 @@ where
let f = |s: &str| format!("{parent_path}/{s}");
let s = Self {
min: options.min.then(|| GenericMap::new_bin(1, &f("min"))),
max: options.max.then(|| GenericMap::new_bin(1, &f("max"))),
median: options.median.then(|| GenericMap::new_bin(1, &f("median"))),
// ---
// Computed
// ---
min: options
.min
.then(|| GenericMap::new_bin(1, MapKind::Computed, &f("min"))),
max: options
.max
.then(|| GenericMap::new_bin(1, MapKind::Computed, &f("max"))),
median: options
.median
.then(|| GenericMap::new_bin(1, MapKind::Computed, &f("median"))),
average: options
.average
.then(|| GenericMap::new_bin(1, &f("average"))),
sum: options.sum.then(|| GenericMap::new_bin(1, &f("sum"))),
_90p: options._90p.then(|| GenericMap::new_bin(1, &f("90p"))),
_75p: options._75p.then(|| GenericMap::new_bin(1, &f("75p"))),
_25p: options._25p.then(|| GenericMap::new_bin(1, &f("25p"))),
_10p: options._10p.then(|| GenericMap::new_bin(1, &f("10p"))),
.then(|| GenericMap::new_bin(1, MapKind::Computed, &f("average"))),
sum: options
.sum
.then(|| GenericMap::new_bin(1, MapKind::Computed, &f("sum"))),
_90p: options
._90p
.then(|| GenericMap::new_bin(1, MapKind::Computed, &f("90p"))),
_75p: options
._75p
.then(|| GenericMap::new_bin(1, MapKind::Computed, &f("75p"))),
_25p: options
._25p
.then(|| GenericMap::new_bin(1, MapKind::Computed, &f("25p"))),
_10p: options
._10p
.then(|| GenericMap::new_bin(1, MapKind::Computed, &f("10p"))),
};
Ok(s)
@@ -128,31 +147,31 @@ where
values.sort_unstable();
if let Some(max) = self.max.as_mut() {
max.insert(key, Value::lossy_from(*values.last().unwrap()));
max.insert_computed(key, Value::lossy_from(*values.last().unwrap()));
}
if let Some(_90p) = self._90p.as_mut() {
_90p.insert(key, Value::lossy_from(get_percentile(values, 0.90)));
_90p.insert_computed(key, Value::lossy_from(get_percentile(values, 0.90)));
}
if let Some(_75p) = self._75p.as_mut() {
_75p.insert(key, Value::lossy_from(get_percentile(values, 0.75)));
_75p.insert_computed(key, Value::lossy_from(get_percentile(values, 0.75)));
}
if let Some(median) = self.median.as_mut() {
median.insert(key, Value::lossy_from(get_percentile(values, 0.50)));
median.insert_computed(key, Value::lossy_from(get_percentile(values, 0.50)));
}
if let Some(_25p) = self._25p.as_mut() {
_25p.insert(key, Value::lossy_from(get_percentile(values, 0.25)));
_25p.insert_computed(key, Value::lossy_from(get_percentile(values, 0.25)));
}
if let Some(_10p) = self._10p.as_mut() {
_10p.insert(key, Value::lossy_from(get_percentile(values, 0.10)));
_10p.insert_computed(key, Value::lossy_from(get_percentile(values, 0.10)));
}
if let Some(min) = self.min.as_mut() {
min.insert(key, Value::lossy_from(*values.first().unwrap()));
min.insert_computed(key, Value::lossy_from(*values.first().unwrap()));
}
}
@@ -160,12 +179,12 @@ where
let sum = Value::lossy_from(values.iter().sum::<Value2>());
if let Some(sum_map) = self.sum.as_mut() {
sum_map.insert(key, sum);
sum_map.insert_computed(key, sum);
}
if let Some(average) = self.average.as_mut() {
let len = values.len() as f32;
average.insert(key, Value::lossy_from(f32::lossy_from(sum) / len));
average.insert_computed(key, Value::lossy_from(f32::lossy_from(sum) / len));
}
}
}
@@ -254,99 +273,3 @@ where
v
}
}
// impl<Key, Value, ChunkId, Serialized> AnyDataset for RecapDataset<Key, Value, ChunkId, Serialized>
// where
// Value: MapValue,
// ChunkId: MapChunkId,
// Key: MapKey<ChunkId>,
// Serialized: MapSerialized<Key, Value, ChunkId>,
// {
// fn get_min_initial_states(&self) -> &MinInitialStates {
// &self.min_initial_states
// }
// fn to_computed_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
// let mut v: Vec<&(dyn AnyDateMap + Send + Sync)> = vec![];
// if let Some(min) = self.min.as_ref() {
// v.push(min);
// }
// if let Some(max) = self.max.as_ref() {
// v.push(max);
// }
// if let Some(median) = self.median.as_ref() {
// v.push(median);
// }
// if let Some(average) = self.average.as_ref() {
// v.push(average);
// }
// if let Some(sum) = self.sum.as_ref() {
// v.push(sum);
// }
// if let Some(_90p) = self._90p.as_ref() {
// v.push(_90p);
// }
// if let Some(_75p) = self._75p.as_ref() {
// v.push(_75p);
// }
// if let Some(_25p) = self._25p.as_ref() {
// v.push(_25p);
// }
// if let Some(_10p) = self._10p.as_ref() {
// v.push(_10p);
// }
// v
// }
// fn to_computed_mut_date_map_vec(&mut self) -> Vec<&mut dyn AnyDateMap> {
// let mut v: Vec<&mut dyn AnyDateMap> = vec![];
// if let Some(min) = self.min.as_mut() {
// v.push(min);
// }
// if let Some(max) = self.max.as_mut() {
// v.push(max);
// }
// if let Some(median) = self.median.as_mut() {
// v.push(median);
// }
// if let Some(average) = self.average.as_mut() {
// v.push(average);
// }
// if let Some(sum) = self.sum.as_mut() {
// v.push(sum);
// }
// if let Some(_90p) = self._90p.as_mut() {
// v.push(_90p);
// }
// if let Some(_75p) = self._75p.as_mut() {
// v.push(_75p);
// }
// if let Some(_25p) = self._25p.as_mut() {
// v.push(_25p);
// }
// if let Some(_10p) = self._10p.as_mut() {
// v.push(_10p);
// }
// v
// }
// }
+21 -34
View File
@@ -1,26 +1,28 @@
use allocative::Allocative;
use struct_iterable::Iterable;
use crate::{
datasets::{AnyDataset, ComputeData, InsertData, MinInitialStates},
states::SupplyState,
structs::{AnyBiMap, BiMap},
structs::{BiMap, Config, MapKind},
};
#[derive(Default, Allocative)]
#[derive(Allocative, Iterable)]
pub struct SupplySubDataset {
min_initial_states: MinInitialStates,
// Inserted
pub supply: BiMap<f64>,
// Computed
pub supply_to_circulating_supply_ratio: BiMap<f64>,
pub halved_supply: BiMap<f64>,
pub halved_supply_to_circulating_supply_ratio: BiMap<f64>,
}
impl SupplySubDataset {
pub fn import(parent_path: &str, name: &Option<String>) -> color_eyre::Result<Self> {
pub fn import(
parent_path: &str,
name: &Option<String>,
config: &Config,
) -> color_eyre::Result<Self> {
let f = |s: &str| {
if let Some(name) = name {
format!("{parent_path}/{name}/{s}")
@@ -32,20 +34,29 @@ impl SupplySubDataset {
let mut s = Self {
min_initial_states: MinInitialStates::default(),
supply: BiMap::new_bin(1, &f("supply")),
// ---
// Inserted
// ---
supply: BiMap::new_bin(1, MapKind::Inserted, &f("supply")),
// ---
// Computed,
// ---
supply_to_circulating_supply_ratio: BiMap::new_bin(
1,
MapKind::Computed,
&f("supply_to_circulating_supply_ratio"),
),
halved_supply: BiMap::new_bin(1, &f("halved_supply")),
halved_supply: BiMap::new_bin(1, MapKind::Computed, &f("halved_supply")),
halved_supply_to_circulating_supply_ratio: BiMap::new_bin(
1,
MapKind::Computed,
&f("halved_supply_to_circulating_supply_ratio"),
),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
.consume(MinInitialStates::compute_from_dataset(&s, config));
Ok(s)
}
@@ -60,7 +71,7 @@ impl SupplySubDataset {
}: &InsertData,
state: &SupplyState,
) {
let total_supply = self.supply.height.insert(height, state.supply.to_btc());
let total_supply = self.supply.height.insert(height, state.supply().to_btc());
if is_date_last_block {
self.supply.date.insert(date, total_supply);
@@ -93,28 +104,4 @@ impl AnyDataset for SupplySubDataset {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![&self.supply]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.supply]
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![
&self.supply_to_circulating_supply_ratio,
&self.halved_supply,
&self.halved_supply_to_circulating_supply_ratio,
]
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![
&mut self.supply_to_circulating_supply_ratio,
&mut self.halved_supply,
&mut self.halved_supply_to_circulating_supply_ratio,
]
}
}
+41 -61
View File
@@ -1,21 +1,19 @@
use allocative::Allocative;
use struct_iterable::Iterable;
use crate::{
datasets::{AnyDataset, ComputeData, InsertData, MinInitialStates},
states::UnrealizedState,
structs::{AnyBiMap, BiMap},
structs::{BiMap, Config, MapKind},
};
#[derive(Default, Allocative)]
#[derive(Allocative, Iterable)]
pub struct UnrealizedSubDataset {
min_initial_states: MinInitialStates,
// Inserted
supply_in_profit: BiMap<f64>,
unrealized_profit: BiMap<f32>,
unrealized_loss: BiMap<f32>,
// Computed
supply_in_loss: BiMap<f64>,
negative_unrealized_loss: BiMap<f32>,
net_unrealized_profit_and_loss: BiMap<f32>,
@@ -27,7 +25,11 @@ pub struct UnrealizedSubDataset {
}
impl UnrealizedSubDataset {
pub fn import(parent_path: &str, name: &Option<String>) -> color_eyre::Result<Self> {
pub fn import(
parent_path: &str,
name: &Option<String>,
config: &Config,
) -> color_eyre::Result<Self> {
let f = |s: &str| {
if let Some(name) = name {
format!("{parent_path}/{name}/{s}")
@@ -39,36 +41,56 @@ impl UnrealizedSubDataset {
let mut s = Self {
min_initial_states: MinInitialStates::default(),
supply_in_profit: BiMap::new_bin(1, &f("supply_in_profit")),
supply_in_loss: BiMap::new_bin(1, &f("supply_in_loss")),
unrealized_profit: BiMap::new_bin(1, &f("unrealized_profit")),
unrealized_loss: BiMap::new_bin(1, &f("unrealized_loss")),
negative_unrealized_loss: BiMap::new_bin(1, &f("negative_unrealized_loss")),
net_unrealized_profit_and_loss: BiMap::new_bin(1, &f("net_unrealized_profit_and_loss")),
// ---
// Inserted
// ---
supply_in_profit: BiMap::new_bin(1, MapKind::Inserted, &f("supply_in_profit")),
unrealized_profit: BiMap::new_bin(1, MapKind::Inserted, &f("unrealized_profit")),
unrealized_loss: BiMap::new_bin(1, MapKind::Inserted, &f("unrealized_loss")),
// ---
// Inserted
// ---
supply_in_loss: BiMap::new_bin(1, MapKind::Computed, &f("supply_in_loss")),
negative_unrealized_loss: BiMap::new_bin(
1,
MapKind::Computed,
&f("negative_unrealized_loss"),
),
net_unrealized_profit_and_loss: BiMap::new_bin(
1,
MapKind::Computed,
&f("net_unrealized_profit_and_loss"),
),
net_unrealized_profit_and_loss_to_market_cap_ratio: BiMap::new_bin(
2,
MapKind::Computed,
&f("net_unrealized_profit_and_loss_to_market_cap_ratio"),
),
supply_in_profit_to_own_supply_ratio: BiMap::new_bin(
1,
MapKind::Computed,
&f("supply_in_profit_to_own_supply_ratio"),
),
supply_in_profit_to_circulating_supply_ratio: BiMap::new_bin(
1,
MapKind::Computed,
&f("supply_in_profit_to_circulating_supply_ratio"),
),
supply_in_loss_to_own_supply_ratio: BiMap::new_bin(
1,
MapKind::Computed,
&f("supply_in_loss_to_own_supply_ratio"),
),
supply_in_loss_to_circulating_supply_ratio: BiMap::new_bin(
1,
MapKind::Computed,
&f("supply_in_loss_to_circulating_supply_ratio"),
),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
.consume(MinInitialStates::compute_from_dataset(&s, config));
Ok(s)
}
@@ -86,30 +108,30 @@ impl UnrealizedSubDataset {
) {
self.supply_in_profit
.height
.insert(height, block_state.supply_in_profit.to_btc());
.insert(height, block_state.supply_in_profit().to_btc());
self.unrealized_profit
.height
.insert(height, block_state.unrealized_profit.to_dollar() as f32);
.insert(height, block_state.unrealized_profit().to_dollar() as f32);
self.unrealized_loss
.height
.insert(height, block_state.unrealized_loss.to_dollar() as f32);
.insert(height, block_state.unrealized_loss().to_dollar() as f32);
if is_date_last_block {
let date_state = date_state.as_ref().unwrap();
self.supply_in_profit
.date
.insert(date, date_state.supply_in_profit.to_btc());
.insert(date, date_state.supply_in_profit().to_btc());
self.unrealized_profit
.date
.insert(date, date_state.unrealized_profit.to_dollar() as f32);
.insert(date, date_state.unrealized_profit().to_dollar() as f32);
self.unrealized_loss
.date
.insert(date, date_state.unrealized_loss.to_dollar() as f32);
.insert(date, date_state.unrealized_loss().to_dollar() as f32);
}
}
@@ -172,46 +194,4 @@ impl AnyDataset for UnrealizedSubDataset {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![
&self.supply_in_profit,
&self.unrealized_profit,
&self.unrealized_loss,
]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![
&mut self.supply_in_profit,
&mut self.unrealized_profit,
&mut self.unrealized_loss,
]
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![
&self.supply_in_loss,
&self.negative_unrealized_loss,
&self.net_unrealized_profit_and_loss,
&self.net_unrealized_profit_and_loss_to_market_cap_ratio,
&self.supply_in_profit_to_own_supply_ratio,
&self.supply_in_profit_to_circulating_supply_ratio,
&self.supply_in_loss_to_own_supply_ratio,
&self.supply_in_loss_to_circulating_supply_ratio,
]
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![
&mut self.supply_in_loss,
&mut self.negative_unrealized_loss,
&mut self.net_unrealized_profit_and_loss,
&mut self.net_unrealized_profit_and_loss_to_market_cap_ratio,
&mut self.supply_in_profit_to_own_supply_ratio,
&mut self.supply_in_profit_to_circulating_supply_ratio,
&mut self.supply_in_loss_to_own_supply_ratio,
&mut self.supply_in_loss_to_circulating_supply_ratio,
]
}
}
+15 -16
View File
@@ -1,21 +1,25 @@
use allocative::Allocative;
use struct_iterable::Iterable;
use crate::{
datasets::{AnyDataset, InsertData, MinInitialStates},
states::UTXOState,
structs::{AnyBiMap, BiMap},
structs::{BiMap, Config, MapKind},
};
#[derive(Default, Allocative)]
#[derive(Allocative, Iterable)]
pub struct UTXOSubDataset {
min_initial_states: MinInitialStates,
// Inserted
count: BiMap<usize>,
count: BiMap<f64>,
}
impl UTXOSubDataset {
pub fn import(parent_path: &str, name: &Option<String>) -> color_eyre::Result<Self> {
pub fn import(
parent_path: &str,
name: &Option<String>,
config: &Config,
) -> color_eyre::Result<Self> {
let f = |s: &str| {
if let Some(name) = name {
format!("{parent_path}/{name}/{s}")
@@ -27,11 +31,14 @@ impl UTXOSubDataset {
let mut s = Self {
min_initial_states: MinInitialStates::default(),
count: BiMap::new_bin(1, &f("utxo_count")),
// ---
// Inserted
// ---
count: BiMap::new_bin(1, MapKind::Inserted, &f("utxo_count")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
.consume(MinInitialStates::compute_from_dataset(&s, config));
Ok(s)
}
@@ -46,7 +53,7 @@ impl UTXOSubDataset {
}: &InsertData,
state: &UTXOState,
) {
let count = self.count.height.insert(height, state.count);
let count = self.count.height.insert(height, state.count());
if is_date_last_block {
self.count.date.insert(date, count);
@@ -58,12 +65,4 @@ impl AnyDataset for UTXOSubDataset {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![&self.count]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.count]
}
}
+174 -105
View File
@@ -1,21 +1,27 @@
use allocative::Allocative;
use struct_iterable::Iterable;
use crate::{
datasets::InsertData,
structs::{AnyBiMap, BiMap, HeightMap},
utils::{ONE_DAY_IN_S, ONE_MONTH_IN_DAYS, ONE_WEEK_IN_DAYS, ONE_YEAR_IN_DAYS},
structs::{BiMap, Config, HeightMap, MapKind},
utils::{
ONE_DAY_IN_S, ONE_MONTH_IN_DAYS, ONE_WEEK_IN_DAYS, ONE_YEAR_IN_DAYS, TARGET_BLOCKS_PER_DAY,
},
DateMap,
};
use super::{AnyDataset, ComputeData, MinInitialStates};
#[derive(Allocative)]
#[derive(Allocative, Iterable)]
pub struct TransactionDataset {
min_initial_states: MinInitialStates,
// Inserted
pub count: BiMap<usize>,
pub volume: BiMap<f64>,
pub volume_in_dollars: BiMap<f32>,
pub count: HeightMap<usize>,
pub count_1d_sum: DateMap<usize>,
pub volume: HeightMap<f64>,
pub volume_1d_sum: DateMap<f64>,
pub volume_in_dollars: HeightMap<f32>,
pub volume_in_dollars_1d_sum: DateMap<f32>,
// Average sent
// Average sent in dollars
// Median sent
@@ -25,51 +31,136 @@ pub struct TransactionDataset {
// 10th 25th 75th 90th percentiles
// type
// version
// Computed
pub count_1w_sma: BiMap<f32>,
pub count_1m_sma: BiMap<f32>,
pub volume_1w_sma: BiMap<f32>,
pub volume_1m_sma: BiMap<f32>,
pub volume_in_dollars_1w_sma: BiMap<f32>,
pub volume_in_dollars_1m_sma: BiMap<f32>,
pub annualized_volume: BiMap<f32>,
pub annualized_volume_in_dollars: BiMap<f32>,
pub velocity: BiMap<f32>,
pub count_1w_sma: HeightMap<f32>,
pub count_1d_sum_1w_sma: DateMap<f32>,
pub count_1m_sma: HeightMap<f32>,
pub count_1d_sum_1m_sma: DateMap<f32>,
pub volume_1w_sma: HeightMap<f32>,
pub volume_1d_sum_1w_sma: DateMap<f32>,
pub volume_1m_sma: HeightMap<f32>,
pub volume_1d_sum_1m_sma: DateMap<f32>,
pub volume_in_dollars_1w_sma: HeightMap<f32>,
pub volume_in_dollars_1d_sum_1w_sma: DateMap<f32>,
pub volume_in_dollars_1m_sma: HeightMap<f32>,
pub volume_in_dollars_1d_sum_1m_sma: DateMap<f32>,
pub annualized_volume: DateMap<f32>,
pub annualized_volume_in_dollars: DateMap<f32>,
pub velocity: DateMap<f32>,
pub transactions_per_second: BiMap<f32>,
pub transactions_per_second_1w_sma: BiMap<f32>,
pub transactions_per_second_1m_sma: BiMap<f32>,
}
impl TransactionDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
pub fn import(parent_path: &str, config: &Config) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
count: BiMap::new_bin(1, &f("transaction_count")),
count_1w_sma: BiMap::new_bin(1, &f("transaction_count_1w_sma")),
count_1m_sma: BiMap::new_bin(1, &f("transaction_count_1m_sma")),
volume: BiMap::new_bin(1, &f("transaction_volume")),
volume_1w_sma: BiMap::new_bin(1, &f("transaction_volume_1w_sma")),
volume_1m_sma: BiMap::new_bin(1, &f("transaction_volume_1m_sma")),
volume_in_dollars: BiMap::new_bin(1, &f("transaction_volume_in_dollars")),
volume_in_dollars_1w_sma: BiMap::new_bin(1, &f("transaction_volume_in_dollars_1w_sma")),
volume_in_dollars_1m_sma: BiMap::new_bin(1, &f("transaction_volume_in_dollars_1m_sma")),
annualized_volume: BiMap::new_bin(1, &f("annualized_transaction_volume")),
annualized_volume_in_dollars: BiMap::new_bin(
// ---
// Inserted
// ---
count: HeightMap::new_bin(1, MapKind::Inserted, &f("transaction_count")),
count_1d_sum: DateMap::new_bin(1, MapKind::Inserted, &f("transaction_count_1d_sum")),
volume: HeightMap::new_bin(1, MapKind::Inserted, &f("transaction_volume")),
volume_1d_sum: DateMap::new_bin(1, MapKind::Inserted, &f("transaction_volume_1d_sum")),
volume_in_dollars: HeightMap::new_bin(
1,
MapKind::Inserted,
&f("transaction_volume_in_dollars"),
),
volume_in_dollars_1d_sum: DateMap::new_bin(
1,
MapKind::Inserted,
&f("transaction_volume_in_dollars_1d_sum"),
),
// ---
// Inserted
// ---
count_1w_sma: HeightMap::new_bin(1, MapKind::Computed, &f("transaction_count_1w_sma")),
count_1d_sum_1w_sma: DateMap::new_bin(
1,
MapKind::Computed,
&f("transaction_count_1d_sum_1w_sma"),
),
count_1m_sma: HeightMap::new_bin(1, MapKind::Computed, &f("transaction_count_1m_sma")),
count_1d_sum_1m_sma: DateMap::new_bin(
1,
MapKind::Computed,
&f("transaction_count_1d_sum_1m_sma"),
),
volume_1w_sma: HeightMap::new_bin(
1,
MapKind::Computed,
&f("transaction_volume_1w_sma"),
),
volume_1d_sum_1w_sma: DateMap::new_bin(
1,
MapKind::Computed,
&f("transaction_volume_1d_sum_1w_sma"),
),
volume_1m_sma: HeightMap::new_bin(
1,
MapKind::Computed,
&f("transaction_volume_1m_sma"),
),
volume_1d_sum_1m_sma: DateMap::new_bin(
1,
MapKind::Computed,
&f("transaction_volume_1d_sum_1m_sma"),
),
volume_in_dollars_1w_sma: HeightMap::new_bin(
1,
MapKind::Computed,
&f("transaction_volume_in_dollars_1w_sma"),
),
volume_in_dollars_1d_sum_1w_sma: DateMap::new_bin(
1,
MapKind::Computed,
&f("transaction_volume_in_dollars_1d_sum_1w_sma"),
),
volume_in_dollars_1m_sma: HeightMap::new_bin(
1,
MapKind::Computed,
&f("transaction_volume_in_dollars_1m_sma"),
),
volume_in_dollars_1d_sum_1m_sma: DateMap::new_bin(
1,
MapKind::Computed,
&f("transaction_volume_in_dollars_1d_sum_1m_sma"),
),
annualized_volume: DateMap::new_bin(
1,
MapKind::Computed,
&f("annualized_transaction_volume"),
),
annualized_volume_in_dollars: DateMap::new_bin(
2,
MapKind::Computed,
&f("annualized_transaction_volume_in_dollars"),
),
velocity: BiMap::new_bin(1, &f("transaction_velocity")),
transactions_per_second: BiMap::new_bin(1, &f("transactions_per_second")),
transactions_per_second_1w_sma: BiMap::new_bin(1, &f("transactions_per_second_1w_sma")),
transactions_per_second_1m_sma: BiMap::new_bin(1, &f("transactions_per_second_1m_sma")),
velocity: DateMap::new_bin(1, MapKind::Computed, &f("transaction_velocity")),
transactions_per_second: BiMap::new_bin(
1,
MapKind::Computed,
&f("transactions_per_second"),
),
transactions_per_second_1w_sma: BiMap::new_bin(
1,
MapKind::Computed,
&f("transactions_per_second_1w_sma"),
),
transactions_per_second_1m_sma: BiMap::new_bin(
1,
MapKind::Computed,
&f("transactions_per_second_1m_sma"),
),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
.consume(MinInitialStates::compute_from_dataset(&s, config));
Ok(s)
}
@@ -87,21 +178,22 @@ impl TransactionDataset {
..
}: &InsertData,
) {
self.count.height.insert(height, transaction_count);
self.count.insert(height, transaction_count);
self.volume.height.insert(height, amount_sent.to_btc());
self.volume.insert(height, amount_sent.to_btc());
self.volume_in_dollars
.height
.insert(height, (block_price * amount_sent).to_dollar() as f32);
if is_date_last_block {
self.count.date_insert_sum_range(date, date_blocks_range);
self.count_1d_sum
.insert(date, self.count.sum_range(date_blocks_range));
self.volume.date_insert_sum_range(date, date_blocks_range);
self.volume_1d_sum
.insert(date, self.volume.sum_range(date_blocks_range));
self.volume_in_dollars
.date_insert_sum_range(date, date_blocks_range);
self.volume_in_dollars_1d_sum
.insert(date, self.volume_in_dollars.sum_range(date_blocks_range));
}
}
@@ -113,77 +205,100 @@ impl TransactionDataset {
) {
self.count_1w_sma.multi_insert_simple_average(
heights,
dates,
&mut self.count,
TARGET_BLOCKS_PER_DAY * ONE_WEEK_IN_DAYS,
);
self.count_1d_sum_1w_sma.multi_insert_simple_average(
dates,
&mut self.count_1d_sum,
ONE_WEEK_IN_DAYS,
);
self.count_1m_sma.multi_insert_simple_average(
heights,
dates,
&mut self.count,
TARGET_BLOCKS_PER_DAY * ONE_MONTH_IN_DAYS,
);
self.count_1d_sum_1m_sma.multi_insert_simple_average(
dates,
&mut self.count_1d_sum,
ONE_MONTH_IN_DAYS,
);
self.volume_1w_sma.multi_insert_simple_average(
heights,
dates,
&mut self.volume,
TARGET_BLOCKS_PER_DAY * ONE_WEEK_IN_DAYS,
);
self.volume_1d_sum_1w_sma.multi_insert_simple_average(
dates,
&mut self.volume_1d_sum,
ONE_WEEK_IN_DAYS,
);
self.volume_1m_sma.multi_insert_simple_average(
heights,
dates,
&mut self.volume,
TARGET_BLOCKS_PER_DAY * ONE_MONTH_IN_DAYS,
);
self.volume_1d_sum_1m_sma.multi_insert_simple_average(
dates,
&mut self.volume_1d_sum,
ONE_MONTH_IN_DAYS,
);
self.volume_in_dollars_1w_sma.multi_insert_simple_average(
heights,
dates,
&mut self.volume_in_dollars,
ONE_WEEK_IN_DAYS,
TARGET_BLOCKS_PER_DAY * ONE_WEEK_IN_DAYS,
);
self.volume_in_dollars_1d_sum_1w_sma
.multi_insert_simple_average(
dates,
&mut self.volume_in_dollars_1d_sum,
ONE_WEEK_IN_DAYS,
);
self.volume_in_dollars_1m_sma.multi_insert_simple_average(
heights,
dates,
&mut self.volume_in_dollars,
ONE_MONTH_IN_DAYS,
TARGET_BLOCKS_PER_DAY * ONE_MONTH_IN_DAYS,
);
self.volume_in_dollars_1d_sum_1m_sma
.multi_insert_simple_average(
dates,
&mut self.volume_in_dollars_1d_sum,
ONE_MONTH_IN_DAYS,
);
self.annualized_volume.multi_insert_last_x_sum(
heights,
dates,
&mut self.volume,
&mut self.volume_1d_sum,
ONE_YEAR_IN_DAYS,
);
self.annualized_volume_in_dollars.multi_insert_last_x_sum(
heights,
dates,
&mut self.volume_in_dollars,
&mut self.volume_in_dollars_1d_sum,
ONE_YEAR_IN_DAYS,
);
self.velocity.multi_insert_divide(
heights,
dates,
&mut self.annualized_volume,
circulating_supply,
&mut circulating_supply.date,
);
self.transactions_per_second.height.multi_insert_divide(
heights,
&mut self.count.height,
&mut self.count,
block_interval,
);
self.transactions_per_second
.date
.multi_insert_simple_transform(dates, &mut self.count.date, |count| {
count as f32 / ONE_DAY_IN_S as f32
.multi_insert_simple_transform(dates, &mut self.count_1d_sum, |count, date| {
count as f32 / (date.get_day_completion() as f32 * ONE_DAY_IN_S as f32)
});
self.transactions_per_second_1w_sma
@@ -208,50 +323,4 @@ impl AnyDataset for TransactionDataset {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![&self.count, &self.volume, &self.volume_in_dollars]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![
&mut self.count,
&mut self.volume,
&mut self.volume_in_dollars,
]
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![
&self.count_1w_sma,
&self.count_1m_sma,
&self.volume_1w_sma,
&self.volume_1m_sma,
&self.volume_in_dollars_1w_sma,
&self.volume_in_dollars_1m_sma,
&self.annualized_volume,
&self.annualized_volume_in_dollars,
&self.velocity,
&self.transactions_per_second,
&self.transactions_per_second_1w_sma,
&self.transactions_per_second_1m_sma,
]
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![
&mut self.count_1w_sma,
&mut self.count_1m_sma,
&mut self.volume_1w_sma,
&mut self.volume_1m_sma,
&mut self.volume_in_dollars_1w_sma,
&mut self.volume_in_dollars_1m_sma,
&mut self.annualized_volume,
&mut self.annualized_volume_in_dollars,
&mut self.velocity,
&mut self.transactions_per_second,
&mut self.transactions_per_second_1w_sma,
&mut self.transactions_per_second_1m_sma,
]
}
}
+11 -105
View File
@@ -1,15 +1,13 @@
use allocative::Allocative;
use itertools::Itertools;
use struct_iterable::Iterable;
use crate::{
datasets::{
AnyDataset, AnyDatasetGroup, ComputeData, InsertData, MinInitialStates, SubDataset,
},
datasets::{AnyDataset, ComputeData, InsertData, MinInitialStates, SubDataset},
states::UTXOCohortId,
structs::{AnyBiMap, AnyDateMap, AnyHeightMap, BiMap, Date, Height},
structs::{BiMap, Config, Date, Height},
};
#[derive(Default, Allocative)]
#[derive(Allocative, Iterable)]
pub struct UTXODataset {
id: UTXOCohortId,
@@ -19,17 +17,21 @@ pub struct UTXODataset {
}
impl UTXODataset {
pub fn import(parent_path: &str, id: UTXOCohortId) -> color_eyre::Result<Self> {
pub fn import(
parent_path: &str,
id: UTXOCohortId,
config: &Config,
) -> color_eyre::Result<Self> {
let name = id.name().to_owned();
let mut s = Self {
min_initial_states: MinInitialStates::default(),
id,
subs: SubDataset::import(parent_path, &Some(name))?,
subs: SubDataset::import(parent_path, &Some(name), config)?,
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
.consume(MinInitialStates::compute_from_dataset(&s, config));
Ok(s)
}
@@ -192,100 +194,4 @@ impl AnyDataset for UTXODataset {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_inserted_height_map_vec(&self) -> Vec<&(dyn AnyHeightMap + Send + Sync)> {
self.subs
.as_vec()
.into_iter()
.flat_map(|d| d.to_inserted_height_map_vec())
.collect_vec()
}
fn to_inserted_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
self.subs
.as_vec()
.into_iter()
.flat_map(|d| d.to_inserted_date_map_vec())
.collect_vec()
}
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
self.subs
.as_vec()
.into_iter()
.flat_map(|d| d.to_inserted_bi_map_vec())
.collect_vec()
}
fn to_inserted_mut_height_map_vec(&mut self) -> Vec<&mut dyn AnyHeightMap> {
self.subs
.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_inserted_mut_height_map_vec())
.collect_vec()
}
fn to_inserted_mut_date_map_vec(&mut self) -> Vec<&mut dyn AnyDateMap> {
self.subs
.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_inserted_mut_date_map_vec())
.collect_vec()
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
self.subs
.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_inserted_mut_bi_map_vec())
.collect_vec()
}
fn to_computed_height_map_vec(&self) -> Vec<&(dyn AnyHeightMap + Send + Sync)> {
self.subs
.as_vec()
.into_iter()
.flat_map(|d| d.to_computed_height_map_vec())
.collect_vec()
}
fn to_computed_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
self.subs
.as_vec()
.into_iter()
.flat_map(|d| d.to_computed_date_map_vec())
.collect_vec()
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
self.subs
.as_vec()
.into_iter()
.flat_map(|d| d.to_computed_bi_map_vec())
.collect_vec()
}
fn to_computed_mut_height_map_vec(&mut self) -> Vec<&mut dyn AnyHeightMap> {
self.subs
.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_computed_mut_height_map_vec())
.collect_vec()
}
fn to_computed_mut_date_map_vec(&mut self) -> Vec<&mut dyn AnyDateMap> {
self.subs
.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_computed_mut_date_map_vec())
.collect_vec()
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
self.subs
.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_computed_mut_bi_map_vec())
.collect_vec()
}
}
+7 -7
View File
@@ -9,7 +9,7 @@ use itertools::Itertools;
use crate::{
datasets::AnyDatasets,
states::{SplitByUTXOCohort, UTXOCohortId},
structs::{BiMap, Date, Height},
structs::{BiMap, Config, Date, Height},
};
use super::{AnyDataset, ComputeData, InsertData, MinInitialStates};
@@ -22,28 +22,28 @@ pub struct UTXODatasets {
}
impl UTXODatasets {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
let mut cohorts = SplitByUTXOCohort::<UTXODataset>::default();
pub fn import(parent_path: &str, config: &Config) -> color_eyre::Result<Self> {
let mut cohorts = SplitByUTXOCohort::<Option<UTXODataset>>::default();
cohorts
.as_vec()
.into_par_iter()
.map(|(_, id)| (id, UTXODataset::import(parent_path, id)))
.map(|(_, id)| (id, UTXODataset::import(parent_path, id, config)))
.collect::<Vec<_>>()
.into_iter()
.try_for_each(|(id, dataset)| -> color_eyre::Result<()> {
*cohorts.get_mut(&id) = dataset?;
cohorts.get_mut(&id).replace(dataset?);
Ok(())
})?;
let mut s = Self {
min_initial_states: MinInitialStates::default(),
cohorts,
cohorts: cohorts.unwrap(),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_datasets(&s));
.consume(MinInitialStates::compute_from_datasets(&s, config));
Ok(s)
}
+3 -1
View File
@@ -60,7 +60,7 @@ impl Binary {
let config = config::standard();
let decoded = decode_from_slice::<T, _>(&decompressed, config).unwrap().0;
let decoded = decode_from_slice::<T, _>(&decompressed, config)?.0;
Ok(decoded)
}
@@ -69,6 +69,8 @@ impl Binary {
where
T: Debug + Encode,
{
// log(&format!("Exporting: {:?}", path));
match Self::type_from_path(path) {
BinaryType::Compressed => Self::export_compressed(path, value),
BinaryType::Raw => Self::export_raw(path, value),
+1 -1
View File
@@ -95,7 +95,7 @@ impl Serialization {
let path = path.to_str().unwrap();
let res = Binary::export(
Path::new(&format!("{}.{COMPRESSED_BIN_EXTENSION}", path,)),
Path::new(&format!("{}.{COMPRESSED_BIN_EXTENSION}", path)),
value,
);
+4 -4
View File
@@ -9,11 +9,11 @@ mod utils;
pub use crate::{
actions::iter_blocks,
datasets::OHLC,
io::{Binary, Json, Serialization},
databases::{AnyDatabase, Database},
io::{Binary, Json, Serialization, COMPRESSED_BIN_EXTENSION, JSON_EXTENSION},
structs::{
Config, Date, DateMap, Height, HeightMap, MapChunkId, SerializedBTreeMap, SerializedVec,
HEIGHT_MAP_CHUNK_SIZE,
Amount, Config, Date, DateMap, Exit, Height, HeightMap, MapChunkId, MapValue,
SerializedBTreeMap, SerializedVec, TxoutIndex, HEIGHT_MAP_CHUNK_SIZE, OHLC,
},
utils::{create_rpc, log, reset_logs},
};
+8 -5
View File
@@ -1,31 +1,34 @@
use std::{thread::sleep, time::Duration};
use biter::bitcoincore_rpc::RpcApi;
use parser::{create_rpc, iter_blocks, log, reset_logs, Config};
use parser::{create_rpc, iter_blocks, log, reset_logs, Config, Exit};
fn main() -> color_eyre::Result<()> {
color_eyre::install()?;
reset_logs();
let config = Config::import();
let mut config = Config::import()?;
let rpc = create_rpc(&config).unwrap();
let exit = Exit::new();
loop {
let block_count = rpc.get_blockchain_info().unwrap().blocks as usize;
log(&format!("{block_count} blocks found."));
iter_blocks(&config, &rpc, block_count)?;
iter_blocks(&mut config, &rpc, block_count, exit.clone())?;
if let Some(delay) = config.delay {
sleep(Duration::from_secs(delay))
}
log("Waiting for new block...");
log("Waiting for a new block...\n");
while block_count == rpc.get_blockchain_info().unwrap().blocks as usize {
sleep(Duration::from_secs(5))
sleep(Duration::from_secs(1))
}
}
+6 -6
View File
@@ -7,9 +7,8 @@ use itertools::Itertools;
use serde_json::Value;
use crate::{
datasets::OHLC,
io::{Json, INPUTS_FOLDER_PATH},
structs::Date,
structs::{Date, Timestamp, OHLC},
utils::{log, retry},
};
@@ -146,8 +145,8 @@ impl Binance {
})
.collect::<BTreeMap<_, _>>())
},
30,
10,
5,
)
}
@@ -169,9 +168,10 @@ impl Binance {
// [timestamp, open, high, low, close, volume, ...]
let array = value.as_array().unwrap();
let date = Date::from_timestamp(
let date = Timestamp::wrap(
(array.first().unwrap().as_u64().unwrap() / 1_000) as u32,
);
)
.to_date();
let get_f32 = |index: usize| {
array
@@ -195,7 +195,7 @@ impl Binance {
})
.collect::<BTreeMap<_, _>>())
},
10,
30,
10,
)
}
+3 -4
View File
@@ -6,8 +6,7 @@ use itertools::Itertools;
use serde_json::Value;
use crate::{
datasets::OHLC,
structs::{Date, DateMapChunkId, HeightMapChunkId},
structs::{Date, DateMapChunkId, HeightMapChunkId, OHLC},
utils::{log, retry},
MapChunkId,
};
@@ -56,7 +55,7 @@ impl Kibo {
.map(Self::value_to_ohlc)
.collect_vec())
},
10,
30,
RETRIES,
)
}
@@ -93,7 +92,7 @@ impl Kibo {
})
.collect::<BTreeMap<_, _>>())
},
10,
30,
RETRIES,
)
}
+5 -6
View File
@@ -4,8 +4,7 @@ use color_eyre::eyre::ContextCompat;
use serde_json::Value;
use crate::{
datasets::OHLC,
structs::Date,
structs::{Date, Timestamp, OHLC},
utils::{log, retry},
};
@@ -61,7 +60,7 @@ impl Kraken {
})
.collect::<BTreeMap<_, _>>())
},
10,
30,
10,
)
}
@@ -91,8 +90,8 @@ impl Kraken {
.map(|value| {
let array = value.as_array().unwrap();
let date =
Date::from_timestamp(array.first().unwrap().as_u64().unwrap() as u32);
let date = Timestamp::wrap(array.first().unwrap().as_u64().unwrap() as u32)
.to_date();
let get_f32 = |index: usize| {
array
@@ -116,7 +115,7 @@ impl Kraken {
})
.collect::<BTreeMap<_, _>>())
},
10,
30,
10,
)
}
@@ -1,278 +1,80 @@
use std::ops::AddAssign;
use allocative::Allocative;
use crate::{
states::{DurableStates, OneShotStates, PriceToValue, UnrealizedState},
structs::{Amount, LiquiditySplitResult, Price, SplitByLiquidity},
states::{DurableStates, IsZero, OneShotStates, PriceToValue, UnrealizedState},
structs::{Amount, Price},
};
#[derive(Default, Debug, Allocative)]
pub struct AddressCohortDurableStates {
pub address_count: usize,
pub split_durable_states: SplitByLiquidity<DurableStates>,
pub price_to_split_amount: PriceToValue<SplitByLiquidity<Amount>>,
pub address_count: f64,
pub durable_states: DurableStates,
pub price_to_amount: PriceToValue<Amount>,
}
const ONE_THIRD: f64 = 1.0 / 3.0;
// TODO: Clean that mess, move to a generic liquidity split and somehow support rest for non floats
impl AddressCohortDurableStates {
#[allow(clippy::too_many_arguments)]
pub fn increment(
&mut self,
address_count: f64,
amount: Amount,
utxo_count: usize,
utxo_count: f64,
realized_cap: Price,
mean_price_paid: Price,
split_sat_amount_result: &LiquiditySplitResult,
split_utxo_count_result: &LiquiditySplitResult,
split_realized_cap_result: &LiquiditySplitResult,
) -> color_eyre::Result<()> {
self.address_count += 1;
self.address_count += address_count;
self._crement(
amount,
utxo_count,
realized_cap,
mean_price_paid,
split_sat_amount_result,
split_utxo_count_result,
split_realized_cap_result,
true,
)
self._crement(amount, utxo_count, realized_cap, mean_price_paid, true)
}
#[allow(clippy::too_many_arguments)]
pub fn decrement(
&mut self,
address_count: f64,
amount: Amount,
utxo_count: usize,
utxo_count: f64,
realized_cap: Price,
mean_price_paid: Price,
split_sat_amount_result: &LiquiditySplitResult,
split_utxo_count_result: &LiquiditySplitResult,
split_realized_cap_result: &LiquiditySplitResult,
) -> color_eyre::Result<()> {
self.address_count -= 1;
self.address_count -= address_count;
self._crement(
amount,
utxo_count,
realized_cap,
mean_price_paid,
split_sat_amount_result,
split_utxo_count_result,
split_realized_cap_result,
false,
)
self._crement(amount, utxo_count, realized_cap, mean_price_paid, false)
}
#[allow(clippy::too_many_arguments)]
pub fn _crement(
&mut self,
amount: Amount,
utxo_count: usize,
utxo_count: f64,
realized_cap: Price,
mean_price_paid: Price,
split_sat_amount_result: &LiquiditySplitResult,
split_utxo_count_result: &LiquiditySplitResult,
split_realized_cap_result: &LiquiditySplitResult,
increment: bool,
) -> color_eyre::Result<()> {
if increment {
self.split_durable_states
.all
self.durable_states
.increment(amount, utxo_count, realized_cap)
} else {
self.split_durable_states
.all
self.durable_states
.decrement(amount, utxo_count, realized_cap)
}
.inspect_err(|report| {
dbg!(
report,
"split all failed",
split_sat_amount_result,
split_utxo_count_result
);
dbg!(report);
})?;
let illiquid_amount = split_sat_amount_result.illiquid.trunc();
let illiquid_amount_rest = split_sat_amount_result.illiquid - illiquid_amount;
let mut illiquid_amount = Amount::from_sat(illiquid_amount as u64);
let mut illiquid_utxo_count = split_utxo_count_result.illiquid.trunc() as usize;
let illiquid_utxo_count_rest = split_utxo_count_result.illiquid.fract();
let mut illiquid_realized_cap =
Price::from_cent(split_realized_cap_result.illiquid.trunc() as u64);
let illiquid_realized_cap_rest = split_realized_cap_result.illiquid.fract();
let liquid_amount = split_sat_amount_result.liquid.trunc();
let liquid_amount_rest = split_sat_amount_result.liquid - liquid_amount;
let mut liquid_amount = Amount::from_sat(liquid_amount as u64);
let mut liquid_utxo_count = split_utxo_count_result.liquid.trunc() as usize;
let liquid_utxo_count_rest = split_utxo_count_result.liquid.fract();
let mut liquid_realized_cap =
Price::from_cent(split_realized_cap_result.liquid.trunc() as u64);
let liquid_realized_cap_rest = split_realized_cap_result.liquid.fract();
let mut highly_liquid_amount = amount - illiquid_amount - liquid_amount;
let mut highly_liquid_utxo_count = utxo_count - illiquid_utxo_count - liquid_utxo_count;
let mut highly_liquid_realized_cap =
realized_cap - illiquid_realized_cap - liquid_realized_cap;
let amount_diff = amount - illiquid_amount - liquid_amount - highly_liquid_amount;
if amount_diff > Amount::ZERO {
if illiquid_amount_rest >= ONE_THIRD && illiquid_amount_rest > liquid_amount_rest {
illiquid_amount += amount_diff;
} else if illiquid_amount_rest >= ONE_THIRD {
liquid_amount += amount_diff;
if !amount.is_zero()? {
if increment {
self.price_to_amount.increment(mean_price_paid, amount);
} else {
highly_liquid_amount += amount_diff;
self.price_to_amount
.decrement(mean_price_paid, amount)
.inspect_err(|report| {
dbg!(report, "cents_to_split_amount decrement",);
})?;
}
}
let utxo_count_diff =
utxo_count - illiquid_utxo_count - liquid_utxo_count - highly_liquid_utxo_count;
if utxo_count_diff > 0 {
if illiquid_utxo_count_rest >= ONE_THIRD
&& illiquid_utxo_count_rest > liquid_utxo_count_rest
{
illiquid_utxo_count += utxo_count_diff;
} else if illiquid_utxo_count_rest >= ONE_THIRD {
liquid_utxo_count += utxo_count_diff;
} else {
highly_liquid_utxo_count += utxo_count_diff;
}
}
let realized_cap_diff =
realized_cap - illiquid_realized_cap - liquid_realized_cap - highly_liquid_realized_cap;
if realized_cap_diff > Price::ZERO {
if illiquid_realized_cap_rest >= ONE_THIRD
&& illiquid_realized_cap_rest > liquid_realized_cap_rest
{
illiquid_realized_cap += realized_cap_diff;
} else if illiquid_realized_cap_rest >= ONE_THIRD {
liquid_realized_cap += realized_cap_diff;
} else {
highly_liquid_realized_cap += realized_cap_diff;
}
}
let split_amount = SplitByLiquidity {
all: amount,
illiquid: illiquid_amount,
liquid: liquid_amount,
highly_liquid: highly_liquid_amount,
};
let split_utxo_count = SplitByLiquidity {
all: utxo_count,
illiquid: illiquid_utxo_count,
liquid: liquid_utxo_count,
highly_liquid: highly_liquid_utxo_count,
};
let split_realized_cap = SplitByLiquidity {
all: realized_cap,
illiquid: illiquid_realized_cap,
liquid: liquid_realized_cap,
highly_liquid: highly_liquid_realized_cap,
};
if increment {
self.price_to_split_amount
.increment(mean_price_paid, split_amount);
} else {
self.price_to_split_amount
.decrement(mean_price_paid, split_amount)
.inspect_err(|report| {
dbg!(
report,
"cents_to_split_amount decrement",
split_sat_amount_result,
split_utxo_count_result,
split_amount,
split_utxo_count,
split_realized_cap,
);
})?;
}
if increment {
self.split_durable_states.illiquid.increment(
illiquid_amount,
illiquid_utxo_count,
illiquid_realized_cap,
)
} else {
self.split_durable_states.illiquid.decrement(
illiquid_amount,
illiquid_utxo_count,
illiquid_realized_cap,
)
}
.inspect_err(|report| {
dbg!(
report,
"split illiquid failed",
split_sat_amount_result,
split_utxo_count_result,
split_amount,
split_utxo_count,
split_realized_cap,
);
})?;
if increment {
self.split_durable_states.liquid.increment(
liquid_amount,
liquid_utxo_count,
liquid_realized_cap,
)
} else {
self.split_durable_states.liquid.decrement(
liquid_amount,
liquid_utxo_count,
liquid_realized_cap,
)
}
.inspect_err(|report| {
dbg!(
report,
"split liquid failed",
split_sat_amount_result,
split_utxo_count_result,
split_amount,
split_utxo_count,
split_realized_cap,
);
})?;
if increment {
self.split_durable_states.highly_liquid.increment(
highly_liquid_amount,
highly_liquid_utxo_count,
highly_liquid_realized_cap,
)
} else {
self.split_durable_states.highly_liquid.decrement(
highly_liquid_amount,
highly_liquid_utxo_count,
highly_liquid_realized_cap,
)
}
.inspect_err(|report| {
dbg!(
report,
"split highly liquid failed",
split_sat_amount_result,
split_utxo_count_result,
split_amount,
split_utxo_count,
split_realized_cap,
);
})?;
Ok(())
}
@@ -280,132 +82,40 @@ impl AddressCohortDurableStates {
&self,
block_price: Price,
date_price: Option<Price>,
) -> SplitByLiquidity<OneShotStates> {
let mut one_shot_states: SplitByLiquidity<OneShotStates> = SplitByLiquidity::default();
) -> OneShotStates {
let mut one_shot_states = OneShotStates::default();
if date_price.is_some() {
one_shot_states
.all
.unrealized_date_state
.replace(UnrealizedState::default());
one_shot_states
.illiquid
.unrealized_date_state
.replace(UnrealizedState::default());
one_shot_states
.liquid
.unrealized_date_state
.replace(UnrealizedState::default());
one_shot_states
.highly_liquid
.unrealized_date_state
.replace(UnrealizedState::default());
}
let all_supply = self.split_durable_states.all.supply_state.supply;
let illiquid_supply = self.split_durable_states.illiquid.supply_state.supply;
let liquid_supply = self.split_durable_states.liquid.supply_state.supply;
let highly_liquid_supply = self.split_durable_states.highly_liquid.supply_state.supply;
let one_shot_states_ref = &mut one_shot_states;
self.price_to_split_amount.iterate(
SplitByLiquidity {
all: all_supply,
illiquid: illiquid_supply,
liquid: liquid_supply,
highly_liquid: highly_liquid_supply,
},
|price_paid, split_amount| {
one_shot_states_ref.all.price_paid_state.iterate(
price_paid,
split_amount.all,
all_supply,
);
one_shot_states_ref.all.unrealized_block_state.iterate(
price_paid,
block_price,
split_amount.all,
);
if let Some(unrealized_date_state) =
one_shot_states_ref.all.unrealized_date_state.as_mut()
{
unrealized_date_state.iterate(
price_paid,
date_price.unwrap(),
split_amount.all,
);
}
let supply = self.durable_states.supply_state.supply();
if split_amount.illiquid > Amount::ZERO {
one_shot_states_ref.illiquid.price_paid_state.iterate(
price_paid,
split_amount.illiquid,
illiquid_supply,
);
one_shot_states_ref.illiquid.unrealized_block_state.iterate(
price_paid,
block_price,
split_amount.illiquid,
);
if let Some(unrealized_date_state) =
one_shot_states_ref.illiquid.unrealized_date_state.as_mut()
{
unrealized_date_state.iterate(
price_paid,
date_price.unwrap(),
split_amount.illiquid,
);
}
}
if split_amount.liquid > Amount::ZERO {
one_shot_states_ref.liquid.price_paid_state.iterate(
price_paid,
split_amount.liquid,
liquid_supply,
);
one_shot_states_ref.liquid.unrealized_block_state.iterate(
price_paid,
block_price,
split_amount.liquid,
);
if let Some(unrealized_date_state) =
one_shot_states_ref.liquid.unrealized_date_state.as_mut()
{
unrealized_date_state.iterate(
price_paid,
date_price.unwrap(),
split_amount.liquid,
);
}
}
if split_amount.highly_liquid > Amount::ZERO {
one_shot_states_ref.highly_liquid.price_paid_state.iterate(
price_paid,
split_amount.highly_liquid,
highly_liquid_supply,
);
one_shot_states_ref
.highly_liquid
.unrealized_block_state
.iterate(price_paid, block_price, split_amount.highly_liquid);
if let Some(unrealized_date_state) = one_shot_states_ref
.highly_liquid
.unrealized_date_state
.as_mut()
{
unrealized_date_state.iterate(
price_paid,
date_price.unwrap(),
split_amount.highly_liquid,
);
}
}
},
);
self.price_to_amount.iterate(supply, |price_paid, amount| {
one_shot_states_ref
.price_paid_state
.iterate(price_paid, amount, supply);
one_shot_states_ref
.unrealized_block_state
.iterate(price_paid, block_price, amount);
if let Some(unrealized_date_state) = one_shot_states_ref.unrealized_date_state.as_mut()
{
unrealized_date_state.iterate(price_paid, date_price.unwrap(), amount);
}
});
one_shot_states
}
}
impl AddAssign for AddressCohortDurableStates {
fn add_assign(&mut self, rhs: Self) {
self.address_count += rhs.address_count;
self.durable_states += rhs.durable_states;
self.price_to_amount += rhs.price_to_amount;
}
}
@@ -1,9 +1,13 @@
use crate::structs::{AddressSize, AddressSplit, AddressType};
use crate::structs::{AddressLiquidity, AddressSize, AddressSplit, AddressType};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum AddressCohortId {
All,
Illiquid,
Liquid,
HighlyLiquid,
Plankton,
Shrimp,
Crab,
@@ -26,6 +30,10 @@ impl AddressCohortId {
match self {
Self::All => None,
Self::Illiquid => Some("illiquid"),
Self::Liquid => Some("liquid"),
Self::HighlyLiquid => Some("highly_liquid"),
Self::Plankton => Some("plankton"),
Self::Shrimp => Some("shrimp"),
Self::Crab => Some("crab"),
@@ -48,6 +56,10 @@ impl AddressCohortId {
match self {
Self::All => AddressSplit::All,
Self::Illiquid => AddressSplit::Liquidity(AddressLiquidity::Illiquid),
Self::Liquid => AddressSplit::Liquidity(AddressLiquidity::Liquid),
Self::HighlyLiquid => AddressSplit::Liquidity(AddressLiquidity::HighlyLiquid),
Self::Plankton => AddressSplit::Size(AddressSize::Plankton),
Self::Shrimp => AddressSplit::Size(AddressSize::Shrimp),
Self::Crab => AddressSplit::Size(AddressSize::Crab),
@@ -1,11 +1,12 @@
use std::iter::Sum;
use allocative::Allocative;
use color_eyre::eyre::eyre;
use derive_deref::{Deref, DerefMut};
use rayon::prelude::*;
use crate::{
databases::AddressIndexToAddressData,
structs::{AddressData, AddressRealizedData, Price},
structs::{AddressData, AddressRealizedData, Amount, Price},
};
use super::{AddressCohortDurableStates, AddressCohortsOneShotStates, SplitByAddressCohort};
@@ -15,13 +16,7 @@ pub struct AddressCohortsDurableStates(SplitByAddressCohort<AddressCohortDurable
impl AddressCohortsDurableStates {
pub fn init(address_index_to_address_data: &mut AddressIndexToAddressData) -> Self {
let mut s = Self::default();
// Paralize that, different s could be added together
address_index_to_address_data
.iter(&mut |(_, address_data)| s.increment(address_data).unwrap());
s
address_index_to_address_data.compute_addres_cohorts_durable_states()
}
pub fn iterate(
@@ -46,7 +41,7 @@ impl AddressCohortsDurableStates {
}
/// Should always increment using current address data state
fn increment(&mut self, address_data: &AddressData) -> color_eyre::Result<()> {
pub fn increment(&mut self, address_data: &AddressData) -> color_eyre::Result<()> {
self._crement(address_data, true)
}
@@ -62,57 +57,66 @@ impl AddressCohortsDurableStates {
}
let amount = address_data.amount;
let utxo_count = address_data.outputs_len as usize;
let utxo_count = address_data.outputs_len as f64;
let realized_cap = address_data.realized_cap;
let mean_price_paid = address_data.realized_cap / amount;
let liquidity_classification = address_data.compute_liquidity_classification();
let split_address_count = liquidity_classification.split(1.0);
let split_sat_amount = liquidity_classification.split(amount.to_sat() as f64);
let split_utxo_count = liquidity_classification.split(utxo_count as f64);
let split_realized_cap = liquidity_classification.split(utxo_count as f64);
let split_utxo_count = liquidity_classification.split(utxo_count);
let split_realized_cap = liquidity_classification.split(realized_cap.to_dollar());
self.0
.iterate(address_data, |state: &mut AddressCohortDurableStates| {
self.0.iterate(
address_data,
|state| {
// Unsplit it must be one
let address_count = 1.0;
if increment {
if let Err(report) = state.increment(
state.increment(
address_count,
amount,
utxo_count,
realized_cap,
mean_price_paid,
&split_sat_amount,
&split_utxo_count,
&split_realized_cap,
) {
dbg!(
report.to_string(),
&state,
&address_data,
&liquidity_classification
);
return Err(eyre!("increment error"));
}
} else if let Err(report) = state.decrement(
amount,
utxo_count,
realized_cap,
mean_price_paid,
&split_sat_amount,
&split_utxo_count,
&split_realized_cap,
) {
dbg!(
report.to_string(),
&state,
&address_data,
&liquidity_classification
);
return Err(eyre!("decrement error"));
)
} else {
state.decrement(
address_count,
amount,
utxo_count,
realized_cap,
mean_price_paid,
)
}
},
|liquidity, state| {
let address_count = split_address_count.from(liquidity);
let amount = Amount::from_sat(split_sat_amount.from(liquidity).floor() as u64);
let utxo_count = split_utxo_count.from(liquidity);
let realized_cap = Price::from_dollar(split_realized_cap.from(liquidity));
Ok(())
})?;
if increment {
state.increment(
address_count,
amount,
utxo_count,
realized_cap,
mean_price_paid,
)
} else {
state.decrement(
address_count,
amount,
utxo_count,
realized_cap,
mean_price_paid,
)
}
},
)?;
Ok(())
}
@@ -141,3 +145,12 @@ impl AddressCohortsDurableStates {
one_shot_states
}
}
impl Sum for AddressCohortsDurableStates {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::default(), |mut a, b| {
a.0 += b.0;
a
})
}
}
@@ -2,13 +2,13 @@ use derive_deref::{Deref, DerefMut};
use crate::{
states::InputState,
structs::{AddressRealizedData, Amount, LiquidityClassification, SplitByLiquidity},
structs::{AddressRealizedData, Amount, LiquidityClassification},
};
use super::SplitByAddressCohort;
#[derive(Deref, DerefMut, Default)]
pub struct AddressCohortsInputStates(SplitByAddressCohort<SplitByLiquidity<InputState>>);
pub struct AddressCohortsInputStates(SplitByAddressCohort<InputState>);
impl AddressCohortsInputStates {
pub fn iterate_input(
@@ -19,30 +19,27 @@ impl AddressCohortsInputStates {
let count = realized_data.utxos_destroyed as f64;
let sent = realized_data.sent;
let split_count = liquidity_classification.split(count);
let split_volume = liquidity_classification.split(sent.to_sat() as f64);
let iterate = move |state: &mut SplitByLiquidity<InputState>| -> color_eyre::Result<()> {
state.all.iterate(count, sent);
state.illiquid.iterate(
split_count.illiquid,
Amount::from_sat(split_volume.illiquid.round() as u64),
);
state.liquid.iterate(
split_count.liquid,
Amount::from_sat(split_volume.liquid.round() as u64),
);
state.highly_liquid.iterate(
split_count.highly_liquid,
Amount::from_sat(split_volume.highly_liquid.round() as u64),
);
let normal_iteration = move |state: &mut InputState| -> color_eyre::Result<()> {
state.iterate(count, sent);
Ok(())
};
self.iterate(&realized_data.initial_address_data, iterate)
let split_count = liquidity_classification.split(count);
let split_sent = liquidity_classification.split(sent.to_sat() as f64);
let liquified_iteration =
move |liquidity, state: &mut InputState| -> color_eyre::Result<()> {
state.iterate(
split_count.from(liquidity),
Amount::from_sat(split_sent.from(liquidity).round() as u64),
);
Ok(())
};
self.iterate(
&realized_data.initial_address_data,
normal_iteration,
liquified_iteration,
)
}
}
@@ -1,8 +1,8 @@
use derive_deref::{Deref, DerefMut};
use crate::{states::OneShotStates, structs::SplitByLiquidity};
use crate::states::OneShotStates;
use super::SplitByAddressCohort;
#[derive(Deref, DerefMut, Default)]
pub struct AddressCohortsOneShotStates(pub SplitByAddressCohort<SplitByLiquidity<OneShotStates>>);
pub struct AddressCohortsOneShotStates(pub SplitByAddressCohort<OneShotStates>);
@@ -2,13 +2,13 @@ use derive_deref::{Deref, DerefMut};
use crate::{
states::OutputState,
structs::{AddressRealizedData, Amount, LiquidityClassification, SplitByLiquidity},
structs::{AddressRealizedData, Amount, LiquidityClassification},
};
use super::SplitByAddressCohort;
#[derive(Deref, DerefMut, Default)]
pub struct AddressCohortsOutputStates(SplitByAddressCohort<SplitByLiquidity<OutputState>>);
pub struct AddressCohortsOutputStates(SplitByAddressCohort<OutputState>);
impl AddressCohortsOutputStates {
pub fn iterate_output(
@@ -19,30 +19,27 @@ impl AddressCohortsOutputStates {
let count = realized_data.utxos_created as f64;
let volume = realized_data.received;
let split_count = liquidity_classification.split(count);
let split_volume = liquidity_classification.split(volume.to_sat() as f64);
let iterate = move |state: &mut SplitByLiquidity<OutputState>| -> color_eyre::Result<()> {
state.all.iterate(count, volume);
state.illiquid.iterate(
split_count.illiquid,
Amount::from_sat(split_volume.illiquid.round() as u64),
);
state.liquid.iterate(
split_count.liquid,
Amount::from_sat(split_volume.liquid.round() as u64),
);
state.highly_liquid.iterate(
split_count.highly_liquid,
Amount::from_sat(split_volume.highly_liquid.round() as u64),
);
let normal_iteration = move |state: &mut OutputState| -> color_eyre::Result<()> {
state.iterate(count, volume);
Ok(())
};
self.iterate(&realized_data.initial_address_data, iterate)
let split_count = liquidity_classification.split(count);
let split_volume = liquidity_classification.split(volume.to_sat() as f64);
let liquified_iteration =
move |liquidity, state: &mut OutputState| -> color_eyre::Result<()> {
state.iterate(
split_count.from(liquidity),
Amount::from_sat(split_volume.from(liquidity).round() as u64),
);
Ok(())
};
self.iterate(
&realized_data.initial_address_data,
normal_iteration,
liquified_iteration,
)
}
}
@@ -2,13 +2,13 @@ use derive_deref::{Deref, DerefMut};
use crate::{
states::RealizedState,
structs::{AddressRealizedData, LiquidityClassification, Price, SplitByLiquidity},
structs::{AddressRealizedData, LiquidityClassification, Price},
};
use super::SplitByAddressCohort;
#[derive(Deref, DerefMut, Default)]
pub struct AddressCohortsRealizedStates(SplitByAddressCohort<SplitByLiquidity<RealizedState>>);
pub struct AddressCohortsRealizedStates(SplitByAddressCohort<RealizedState>);
impl AddressCohortsRealizedStates {
pub fn iterate_realized(
@@ -19,47 +19,50 @@ impl AddressCohortsRealizedStates {
let realized_profit = realized_data.profit;
let realized_loss = realized_data.loss;
let value_created = realized_data.value_created;
let adjusted_value_created = realized_data.adjusted_value_created;
let value_destroyed = realized_data.value_destroyed;
let adjusted_value_destroyed = realized_data.adjusted_value_destroyed;
let normal_iteration = move |state: &mut RealizedState| -> color_eyre::Result<()> {
state.iterate(
realized_profit,
realized_loss,
value_created,
adjusted_value_created,
value_destroyed,
adjusted_value_destroyed,
);
Ok(())
};
let split_realized_profit =
liquidity_classification.split(realized_profit.to_cent() as f64);
let split_realized_loss = liquidity_classification.split(realized_loss.to_cent() as f64);
let split_value_created = liquidity_classification.split(value_created.to_cent() as f64);
let split_adjusted_value_created =
liquidity_classification.split(adjusted_value_created.to_cent() as f64);
let split_value_destroyed =
liquidity_classification.split(value_destroyed.to_cent() as f64);
let split_adjusted_value_destroyed =
liquidity_classification.split(adjusted_value_destroyed.to_cent() as f64);
let iterate = move |state: &mut SplitByLiquidity<RealizedState>| -> color_eyre::Result<()> {
state.all.iterate(
realized_profit,
realized_loss,
value_created,
value_destroyed,
);
let liquified_iteration =
move |liquidity, state: &mut RealizedState| -> color_eyre::Result<()> {
state.iterate(
Price::from_cent(split_realized_profit.from(liquidity) as u64),
Price::from_cent(split_realized_loss.from(liquidity) as u64),
Price::from_cent(split_value_created.from(liquidity) as u64),
Price::from_cent(split_adjusted_value_created.from(liquidity) as u64),
Price::from_cent(split_value_destroyed.from(liquidity) as u64),
Price::from_cent(split_adjusted_value_destroyed.from(liquidity) as u64),
);
Ok(())
};
state.illiquid.iterate(
Price::from_cent(split_realized_profit.illiquid as u64),
Price::from_cent(split_realized_loss.illiquid as u64),
Price::from_cent(split_value_created.illiquid as u64),
Price::from_cent(split_value_destroyed.illiquid as u64),
);
state.liquid.iterate(
Price::from_cent(split_realized_profit.liquid as u64),
Price::from_cent(split_realized_loss.liquid as u64),
Price::from_cent(split_value_created.liquid as u64),
Price::from_cent(split_value_destroyed.liquid as u64),
);
state.highly_liquid.iterate(
Price::from_cent(split_realized_profit.highly_liquid as u64),
Price::from_cent(split_realized_loss.highly_liquid as u64),
Price::from_cent(split_value_created.highly_liquid as u64),
Price::from_cent(split_value_destroyed.highly_liquid as u64),
);
Ok(())
};
self.iterate(&realized_data.initial_address_data, iterate)
self.iterate(
&realized_data.initial_address_data,
normal_iteration,
liquified_iteration,
)
}
}
@@ -1,6 +1,8 @@
use std::ops::AddAssign;
use allocative::Allocative;
use crate::structs::{AddressData, AddressSize, AddressSplit, AddressType};
use crate::structs::{AddressData, AddressLiquidity, AddressSize, AddressSplit, AddressType};
use super::AddressCohortId;
@@ -8,6 +10,10 @@ use super::AddressCohortId;
pub struct SplitByAddressCohort<T> {
pub all: T,
pub illiquid: T,
pub liquid: T,
pub highly_liquid: T,
pub plankton: T,
pub shrimp: T,
pub crab: T,
@@ -30,6 +36,12 @@ impl<T> SplitByAddressCohort<T> {
match &split {
AddressSplit::All => Some(&self.all),
AddressSplit::Liquidity(address_liquidity) => match address_liquidity {
AddressLiquidity::Illiquid => Some(&self.illiquid),
AddressLiquidity::Liquid => Some(&self.liquid),
AddressLiquidity::HighlyLiquid => Some(&self.highly_liquid),
},
AddressSplit::Type(address_type) => match address_type {
AddressType::P2PK => Some(&self.p2pk),
AddressType::P2PKH => Some(&self.p2pkh),
@@ -61,21 +73,32 @@ impl<T> SplitByAddressCohort<T> {
pub fn iterate(
&mut self,
address_data: &AddressData,
iterate: impl Fn(&mut T) -> color_eyre::Result<()>,
normal_iteration: impl Fn(&mut T) -> color_eyre::Result<()>,
liquified_iteration: impl Fn(AddressLiquidity, &mut T) -> color_eyre::Result<()>,
) -> color_eyre::Result<()> {
if let Some(state) = self.get_mut_from_split(&AddressSplit::All) {
iterate(state)?;
}
normal_iteration(self.get_mut_from_split(&AddressSplit::All).unwrap())?;
let mut _liquified_iteration = |address_liquidity| {
liquified_iteration(
address_liquidity,
self.get_mut_from_split(&AddressSplit::Liquidity(address_liquidity))
.unwrap(),
)
};
_liquified_iteration(AddressLiquidity::Illiquid)?;
_liquified_iteration(AddressLiquidity::Liquid)?;
_liquified_iteration(AddressLiquidity::HighlyLiquid)?;
if let Some(state) = self.get_mut_from_split(&AddressSplit::Type(address_data.address_type))
{
iterate(state)?;
normal_iteration(state)?;
}
if let Some(state) = self.get_mut_from_split(&AddressSplit::Size(AddressSize::from_amount(
address_data.amount,
))) {
iterate(state)?;
normal_iteration(state)?;
}
Ok(())
@@ -85,6 +108,12 @@ impl<T> SplitByAddressCohort<T> {
match &split {
AddressSplit::All => Some(&mut self.all),
AddressSplit::Liquidity(address_liquidity) => match address_liquidity {
AddressLiquidity::Illiquid => Some(&mut self.illiquid),
AddressLiquidity::Liquid => Some(&mut self.liquid),
AddressLiquidity::HighlyLiquid => Some(&mut self.highly_liquid),
},
AddressSplit::Type(address_type) => match address_type {
AddressType::P2PK => Some(&mut self.p2pk),
AddressType::P2PKH => Some(&mut self.p2pkh),
@@ -117,6 +146,10 @@ impl<T> SplitByAddressCohort<T> {
match id {
AddressCohortId::All => &mut self.all,
AddressCohortId::Illiquid => &mut self.illiquid,
AddressCohortId::Liquid => &mut self.liquid,
AddressCohortId::HighlyLiquid => &mut self.highly_liquid,
AddressCohortId::Plankton => &mut self.plankton,
AddressCohortId::Shrimp => &mut self.shrimp,
AddressCohortId::Crab => &mut self.crab,
@@ -138,6 +171,9 @@ impl<T> SplitByAddressCohort<T> {
pub fn as_vec(&self) -> Vec<(&T, AddressCohortId)> {
vec![
(&self.all, AddressCohortId::All),
(&self.illiquid, AddressCohortId::Illiquid),
(&self.liquid, AddressCohortId::Liquid),
(&self.highly_liquid, AddressCohortId::HighlyLiquid),
(&self.plankton, AddressCohortId::Plankton),
(&self.shrimp, AddressCohortId::Shrimp),
(&self.crab, AddressCohortId::Crab),
@@ -158,6 +194,9 @@ impl<T> SplitByAddressCohort<T> {
pub fn as_mut_vec(&mut self) -> Vec<(&mut T, AddressCohortId)> {
vec![
(&mut self.all, AddressCohortId::All),
(&mut self.illiquid, AddressCohortId::Illiquid),
(&mut self.liquid, AddressCohortId::Liquid),
(&mut self.highly_liquid, AddressCohortId::HighlyLiquid),
(&mut self.plankton, AddressCohortId::Plankton),
(&mut self.shrimp, AddressCohortId::Shrimp),
(&mut self.crab, AddressCohortId::Crab),
@@ -175,3 +214,60 @@ impl<T> SplitByAddressCohort<T> {
]
}
}
impl<T> AddAssign for SplitByAddressCohort<T>
where
T: AddAssign,
{
fn add_assign(&mut self, rhs: Self) {
self.all += rhs.all;
self.illiquid += rhs.illiquid;
self.liquid += rhs.liquid;
self.highly_liquid += rhs.highly_liquid;
self.plankton += rhs.plankton;
self.shrimp += rhs.shrimp;
self.crab += rhs.crab;
self.fish += rhs.fish;
self.shark += rhs.shark;
self.whale += rhs.whale;
self.humpback += rhs.humpback;
self.megalodon += rhs.megalodon;
self.p2pk += rhs.p2pk;
self.p2pkh += rhs.p2pkh;
self.p2sh += rhs.p2sh;
self.p2wpkh += rhs.p2wpkh;
self.p2wsh += rhs.p2wsh;
self.p2tr += rhs.p2tr;
}
}
impl<T> SplitByAddressCohort<Option<T>> {
pub fn unwrap(self) -> SplitByAddressCohort<T> {
SplitByAddressCohort {
all: self.all.unwrap(),
illiquid: self.illiquid.unwrap(),
liquid: self.liquid.unwrap(),
highly_liquid: self.highly_liquid.unwrap(),
plankton: self.plankton.unwrap(),
shrimp: self.shrimp.unwrap(),
crab: self.crab.unwrap(),
fish: self.fish.unwrap(),
shark: self.shark.unwrap(),
whale: self.whale.unwrap(),
humpback: self.humpback.unwrap(),
megalodon: self.megalodon.unwrap(),
p2pk: self.p2pk.unwrap(),
p2pkh: self.p2pkh.unwrap(),
p2sh: self.p2sh.unwrap(),
p2wpkh: self.p2wpkh.unwrap(),
p2wsh: self.p2wsh.unwrap(),
p2tr: self.p2tr.unwrap(),
}
}
}
@@ -1,13 +1,19 @@
use std::ops::AddAssign;
use allocative::Allocative;
use crate::structs::Price;
#[derive(Debug, Default, Allocative)]
pub struct CapitalizationState {
pub realized_cap: Price,
realized_cap: Price,
}
impl CapitalizationState {
pub fn realized_cap(&self) -> Price {
self.realized_cap
}
pub fn increment(&mut self, realized_cap: Price) {
self.realized_cap += realized_cap;
}
@@ -16,3 +22,9 @@ impl CapitalizationState {
self.realized_cap -= realized_cap;
}
}
impl AddAssign for CapitalizationState {
fn add_assign(&mut self, rhs: Self) {
self.realized_cap += rhs.realized_cap;
}
}
@@ -1,5 +1,6 @@
use std::ops::AddAssign;
use allocative::Allocative;
use color_eyre::eyre::eyre;
use crate::structs::{Amount, Price};
@@ -16,19 +17,12 @@ impl DurableStates {
pub fn increment(
&mut self,
amount: Amount,
utxo_count: usize,
utxo_count: f64,
realized_cap: Price,
) -> color_eyre::Result<()> {
if amount == Amount::ZERO {
if utxo_count != 0 {
dbg!(amount, utxo_count);
return Err(eyre!("Shouldn't be possible"));
}
} else {
self.capitalization_state.increment(realized_cap);
self.supply_state.increment(amount);
self.utxo_state.increment(utxo_count);
}
self.utxo_state.increment(utxo_count);
self.capitalization_state.increment(realized_cap);
self.supply_state.increment(amount);
Ok(())
}
@@ -36,20 +30,21 @@ impl DurableStates {
pub fn decrement(
&mut self,
amount: Amount,
utxo_count: usize,
utxo_count: f64,
realized_cap: Price,
) -> color_eyre::Result<()> {
if amount == Amount::ZERO {
if utxo_count != 0 {
dbg!(amount, utxo_count);
unreachable!("Shouldn't be possible")
}
} else {
self.capitalization_state.decrement(realized_cap);
self.supply_state.decrement(amount)?;
self.utxo_state.decrement(utxo_count)?;
}
self.utxo_state.decrement(utxo_count)?;
self.capitalization_state.decrement(realized_cap);
self.supply_state.decrement(amount)?;
Ok(())
}
}
impl AddAssign for DurableStates {
fn add_assign(&mut self, rhs: Self) {
self.capitalization_state += rhs.capitalization_state;
self.supply_state += rhs.supply_state;
self.utxo_state += rhs.utxo_state;
}
}

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