Compare commits

...

67 Commits

Author SHA1 Message Date
nym21 dac66c988d release: v0.3.0-beta.1 2026-04-08 17:12:32 +02:00
nym21 303d168681 docs: update generated docs 2026-04-08 17:12:03 +02:00
nym21 1ddb3385e2 website: css 2026-04-08 17:06:54 +02:00
nym21 eb75274dbf website: fixes 2026-04-08 13:11:03 +02:00
nym21 3a7887348c global: snapshot 2026-04-08 12:09:35 +02:00
nym21 0a4cb0601f release: v0.3.0-beta.0 2026-04-08 01:46:43 +02:00
nym21 861e29277c docs: update generated docs 2026-04-08 01:46:13 +02:00
nym21 c76b149ef9 website: fixes 2026-04-08 01:43:58 +02:00
nym21 4c4c6fc840 global: snapshot 2026-04-08 01:38:03 +02:00
nym21 0c14dfe924 query: more optimizations 2026-04-07 17:57:57 +02:00
nym21 17e531b4ee query: more optimizations 2026-04-07 17:43:11 +02:00
nym21 f022f62cce global: snap 2026-04-07 13:49:02 +02:00
nym21 e91f1386b1 website: snap 2026-04-06 22:30:02 +02:00
nym21 02f543af38 release: v0.3.0-alpha.6 2026-04-05 22:48:37 +02:00
nym21 20c96fb551 docs: update generated docs 2026-04-05 22:48:10 +02:00
nym21 acd3d6f425 server: cache fixes 2026-04-05 22:43:30 +02:00
nym21 2b15a24b6d website: add pool logos 2026-04-05 19:46:41 +02:00
nym21 7fac0bc613 global: snap 2026-04-04 20:13:03 +02:00
nym21 62f51761ee global: snap 2026-04-04 18:19:11 +02:00
nym21 5340cc288e release: v0.3.0-alpha.5 2026-04-04 13:10:48 +02:00
nym21 befe3c8fb7 docs: update generated docs 2026-04-04 13:10:28 +02:00
nym21 41ec24c81e server: ms endpoint fixes 2026-04-04 13:05:39 +02:00
nym21 42b497ff65 server: ms endpoint fixes 2026-04-04 12:16:15 +02:00
nym21 01d908a560 release: v0.3.0-alpha.4 2026-04-04 11:59:17 +02:00
nym21 42debcce80 docs: update generated docs 2026-04-04 11:58:50 +02:00
nym21 8bc993eceb global: fixes 2026-04-04 11:53:27 +02:00
nym21 366ac33e23 release: v0.3.0-alpha.3 2026-04-04 01:05:04 +02:00
nym21 b5a7023bd3 docs: update generated docs 2026-04-04 01:04:38 +02:00
nym21 883b38c77c global: snap 2026-04-04 00:59:37 +02:00
nym21 59c767a9e2 release: v0.3.0-alpha.2 2026-04-03 17:56:37 +02:00
nym21 9b5bb848f7 docs: update generated docs 2026-04-03 17:56:12 +02:00
nym21 5bf06530ce store: replace fjal reset by dir nuking 2026-04-03 17:49:46 +02:00
nym21 768e6870cb global: snap 2026-04-03 15:51:27 +02:00
nym21 79829ddd53 changelog: updated 2026-04-03 01:19:47 +02:00
nym21 78082801c6 clients: bump versions 2026-04-03 00:52:09 +02:00
nym21 50771ddccc release: v0.3.0-alpha.1 2026-04-03 00:16:03 +02:00
nym21 3a8a9ddecc docs: update generated docs 2026-04-03 00:15:43 +02:00
nym21 6cd45c1f1f deps: bumped 2026-04-02 23:54:12 +02:00
nym21 1a2db43cf5 fmt: global 2026-04-02 23:50:01 +02:00
nym21 4840e564f4 server: moved params from brk_types 2026-04-02 23:49:01 +02:00
nym21 744dce932c types: docs 2026-04-02 23:08:25 +02:00
nym21 8dfc1bc932 server: ms endpoint fixes 2026-04-02 22:37:34 +02:00
nym21 d92cf43c57 server: reorg 2026-04-02 13:19:56 +02:00
nym21 099699872e global: fixes 2026-04-02 12:39:20 +02:00
nym21 5099903043 clients: bump versions 2026-04-01 23:00:31 +02:00
nym21 982fe47a33 pr: #32
v0.3.0-alpha.0
2026-04-01 22:41:39 +02:00
nym21 65d5fadd13 release: v0.3.0-alpha.0 2026-04-01 22:17:00 +02:00
nym21 b55f5255ad docs: update generated docs 2026-04-01 22:16:40 +02:00
nym21 83edef4806 coinbase: lossy to latin 2026-04-01 21:54:02 +02:00
nym21 d4936d889a clients: regened 2026-04-01 21:37:16 +02:00
nym21 c938cc8eae types: coinbase lossy format 2026-04-01 21:15:45 +02:00
nym21 0558834eef global: fixes 2026-04-01 21:11:20 +02:00
nym21 098950fdde deps: bumped 2026-04-01 18:25:11 +02:00
nym21 91e68a1d1e global: fixes 2026-04-01 18:18:56 +02:00
nym21 7172ddb247 global: snapshot 2026-04-01 17:51:50 +02:00
nym21 96f2e058f7 global: snapshot 2026-04-01 15:50:49 +02:00
nym21 8782944191 readme: add supporter 2026-03-31 23:00:15 +02:00
nym21 ae26db6df2 global: snapshot 2026-03-31 22:53:25 +02:00
nym21 d038141a8a global: snapshot 2026-03-29 23:10:31 +02:00
nym21 f6960c61d6 clients: regened 2026-03-29 17:47:47 +02:00
nym21 07fa2d2c9a release: v0.2.5 2026-03-29 17:33:10 +02:00
nym21 82c6d69a0b docs: update generated docs 2026-03-29 17:32:44 +02:00
nym21 d4dc1b9e49 deps: bumped 2026-03-29 17:26:48 +02:00
nym21 24d2b7b142 global: fmt 2026-03-28 11:56:51 +01:00
nym21 b6e56c4e9f Merge pull request #30 from yashbhutwala/codex/brk-website-static-serving-tests
[codex] add brk_website static serving tests
2026-03-27 23:02:39 +01:00
nym21 45c77a4c3b global: delay compaction 2026-03-27 23:02:31 +01:00
Yash Bhutwala 09af190ac0 add brk_website serving tests 2026-03-27 10:00:37 -04:00
1069 changed files with 25926 additions and 10842 deletions
Generated
+125 -128
View File
@@ -338,7 +338,7 @@ checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
[[package]] [[package]]
name = "brk" name = "brk"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"brk_bencher", "brk_bencher",
"brk_bindgen", "brk_bindgen",
@@ -399,7 +399,7 @@ dependencies = [
[[package]] [[package]]
name = "brk_alloc" name = "brk_alloc"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"libmimalloc-sys", "libmimalloc-sys",
"mimalloc", "mimalloc",
@@ -407,7 +407,7 @@ dependencies = [
[[package]] [[package]]
name = "brk_bencher" name = "brk_bencher"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"brk_error", "brk_error",
"brk_logger", "brk_logger",
@@ -417,14 +417,14 @@ dependencies = [
[[package]] [[package]]
name = "brk_bencher_visualizer" name = "brk_bencher_visualizer"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"plotters", "plotters",
] ]
[[package]] [[package]]
name = "brk_bindgen" name = "brk_bindgen"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"brk_cohort", "brk_cohort",
"brk_query", "brk_query",
@@ -437,14 +437,13 @@ dependencies = [
[[package]] [[package]]
name = "brk_cli" name = "brk_cli"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"brk_alloc", "brk_alloc",
"brk_computer", "brk_computer",
"brk_error", "brk_error",
"brk_indexer", "brk_indexer",
"brk_iterator",
"brk_logger", "brk_logger",
"brk_mempool", "brk_mempool",
"brk_query", "brk_query",
@@ -463,7 +462,7 @@ dependencies = [
[[package]] [[package]]
name = "brk_client" name = "brk_client"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"brk_cohort", "brk_cohort",
"brk_types", "brk_types",
@@ -474,7 +473,7 @@ dependencies = [
[[package]] [[package]]
name = "brk_cohort" name = "brk_cohort"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"brk_error", "brk_error",
"brk_traversable", "brk_traversable",
@@ -486,7 +485,7 @@ dependencies = [
[[package]] [[package]]
name = "brk_computer" name = "brk_computer"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"bitcoin", "bitcoin",
"brk_alloc", "brk_alloc",
@@ -494,12 +493,10 @@ dependencies = [
"brk_cohort", "brk_cohort",
"brk_error", "brk_error",
"brk_indexer", "brk_indexer",
"brk_iterator",
"brk_logger", "brk_logger",
"brk_oracle", "brk_oracle",
"brk_reader", "brk_reader",
"brk_rpc", "brk_rpc",
"brk_store",
"brk_traversable", "brk_traversable",
"brk_types", "brk_types",
"color-eyre", "color-eyre",
@@ -517,7 +514,7 @@ dependencies = [
[[package]] [[package]]
name = "brk_error" name = "brk_error"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"bitcoin", "bitcoin",
"bitcoincore-rpc", "bitcoincore-rpc",
@@ -534,7 +531,7 @@ dependencies = [
[[package]] [[package]]
name = "brk_fetcher" name = "brk_fetcher"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"brk_error", "brk_error",
"brk_logger", "brk_logger",
@@ -546,14 +543,13 @@ dependencies = [
[[package]] [[package]]
name = "brk_indexer" name = "brk_indexer"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"bitcoin", "bitcoin",
"brk_alloc", "brk_alloc",
"brk_bencher", "brk_bencher",
"brk_cohort", "brk_cohort",
"brk_error", "brk_error",
"brk_iterator",
"brk_logger", "brk_logger",
"brk_reader", "brk_reader",
"brk_rpc", "brk_rpc",
@@ -562,8 +558,8 @@ dependencies = [
"brk_types", "brk_types",
"color-eyre", "color-eyre",
"fjall", "fjall",
"parking_lot",
"rayon", "rayon",
"rlimit",
"rustc-hash", "rustc-hash",
"schemars", "schemars",
"serde", "serde",
@@ -573,7 +569,7 @@ dependencies = [
[[package]] [[package]]
name = "brk_iterator" name = "brk_iterator"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"brk_error", "brk_error",
"brk_reader", "brk_reader",
@@ -583,7 +579,7 @@ dependencies = [
[[package]] [[package]]
name = "brk_logger" name = "brk_logger"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"jiff", "jiff",
"owo-colors", "owo-colors",
@@ -594,7 +590,7 @@ dependencies = [
[[package]] [[package]]
name = "brk_mempool" name = "brk_mempool"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"brk_error", "brk_error",
"brk_logger", "brk_logger",
@@ -609,7 +605,7 @@ dependencies = [
[[package]] [[package]]
name = "brk_oracle" name = "brk_oracle"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"brk_indexer", "brk_indexer",
"brk_types", "brk_types",
@@ -619,7 +615,7 @@ dependencies = [
[[package]] [[package]]
name = "brk_query" name = "brk_query"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"bitcoin", "bitcoin",
"brk_computer", "brk_computer",
@@ -641,7 +637,7 @@ dependencies = [
[[package]] [[package]]
name = "brk_reader" name = "brk_reader"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"bitcoin", "bitcoin",
"brk_error", "brk_error",
@@ -651,12 +647,13 @@ dependencies = [
"derive_more", "derive_more",
"parking_lot", "parking_lot",
"rayon", "rayon",
"rlimit",
"tracing", "tracing",
] ]
[[package]] [[package]]
name = "brk_rpc" name = "brk_rpc"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"bitcoin", "bitcoin",
"bitcoincore-rpc", "bitcoincore-rpc",
@@ -673,7 +670,7 @@ dependencies = [
[[package]] [[package]]
name = "brk_server" name = "brk_server"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"aide", "aide",
"axum", "axum",
@@ -708,7 +705,7 @@ dependencies = [
[[package]] [[package]]
name = "brk_store" name = "brk_store"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"brk_error", "brk_error",
"brk_types", "brk_types",
@@ -719,7 +716,7 @@ dependencies = [
[[package]] [[package]]
name = "brk_traversable" name = "brk_traversable"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"brk_traversable_derive", "brk_traversable_derive",
"brk_types", "brk_types",
@@ -732,7 +729,7 @@ dependencies = [
[[package]] [[package]]
name = "brk_traversable_derive" name = "brk_traversable_derive"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -741,7 +738,7 @@ dependencies = [
[[package]] [[package]]
name = "brk_types" name = "brk_types"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"bitcoin", "bitcoin",
"brk_error", "brk_error",
@@ -764,7 +761,7 @@ dependencies = [
[[package]] [[package]]
name = "brk_website" name = "brk_website"
version = "0.2.4" version = "0.3.0-beta.1"
dependencies = [ dependencies = [
"axum", "axum",
"brk_logger", "brk_logger",
@@ -836,9 +833,9 @@ checksum = "1c53ba0f290bfc610084c05582d9c5d421662128fc69f4bf236707af6fd321b9"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.57" version = "1.2.58"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1"
dependencies = [ dependencies = [
"find-msvc-tools", "find-msvc-tools",
"jobserver", "jobserver",
@@ -1308,9 +1305,9 @@ checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
[[package]] [[package]]
name = "fjall" name = "fjall"
version = "3.1.2" version = "3.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a9530ff159bc3ad3a15da746da0f6e95375c2ac64708cbb85ec1ebd26761a84" checksum = "0ebf22b812878dcd767879cb19e03124fd62563dce6410f96538175fba0c132d"
dependencies = [ dependencies = [
"byteorder-lite", "byteorder-lite",
"byteview", "byteview",
@@ -1318,7 +1315,7 @@ dependencies = [
"flume", "flume",
"log", "log",
"lsm-tree", "lsm-tree",
"lz4_flex", "lz4_flex 0.11.6",
"tempfile", "tempfile",
"xxhash-rust", "xxhash-rust",
] ]
@@ -1672,9 +1669,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]] [[package]]
name = "hyper" name = "hyper"
version = "1.8.1" version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca"
dependencies = [ dependencies = [
"atomic-waker", "atomic-waker",
"bytes", "bytes",
@@ -1686,7 +1683,6 @@ dependencies = [
"httpdate", "httpdate",
"itoa", "itoa",
"pin-project-lite", "pin-project-lite",
"pin-utils",
"smallvec", "smallvec",
"tokio", "tokio",
] ]
@@ -1732,12 +1728,13 @@ dependencies = [
[[package]] [[package]]
name = "icu_collections" name = "icu_collections"
version = "2.1.1" version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c"
dependencies = [ dependencies = [
"displaydoc", "displaydoc",
"potential_utf", "potential_utf",
"utf8_iter",
"yoke", "yoke",
"zerofrom", "zerofrom",
"zerovec", "zerovec",
@@ -1745,9 +1742,9 @@ dependencies = [
[[package]] [[package]]
name = "icu_locale_core" name = "icu_locale_core"
version = "2.1.1" version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29"
dependencies = [ dependencies = [
"displaydoc", "displaydoc",
"litemap", "litemap",
@@ -1758,9 +1755,9 @@ dependencies = [
[[package]] [[package]]
name = "icu_normalizer" name = "icu_normalizer"
version = "2.1.1" version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4"
dependencies = [ dependencies = [
"icu_collections", "icu_collections",
"icu_normalizer_data", "icu_normalizer_data",
@@ -1772,15 +1769,15 @@ dependencies = [
[[package]] [[package]]
name = "icu_normalizer_data" name = "icu_normalizer_data"
version = "2.1.1" version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38"
[[package]] [[package]]
name = "icu_properties" name = "icu_properties"
version = "2.1.2" version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de"
dependencies = [ dependencies = [
"icu_collections", "icu_collections",
"icu_locale_core", "icu_locale_core",
@@ -1792,15 +1789,15 @@ dependencies = [
[[package]] [[package]]
name = "icu_properties_data" name = "icu_properties_data"
version = "2.1.2" version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14"
[[package]] [[package]]
name = "icu_provider" name = "icu_provider"
version = "2.1.1" version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421"
dependencies = [ dependencies = [
"displaydoc", "displaydoc",
"icu_locale_core", "icu_locale_core",
@@ -1967,9 +1964,9 @@ checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07"
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.91" version = "0.3.94"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"wasm-bindgen", "wasm-bindgen",
@@ -2007,9 +2004,9 @@ checksum = "803ec87c9cfb29b9d2633f20cba1f488db3fd53f2158b1024cbefb47ba05d413"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.183" version = "0.2.184"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af"
[[package]] [[package]]
name = "libloading" name = "libloading"
@@ -2060,9 +2057,9 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
[[package]] [[package]]
name = "litemap" name = "litemap"
version = "0.8.1" version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
[[package]] [[package]]
name = "litrs" name = "litrs"
@@ -2087,9 +2084,9 @@ checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]] [[package]]
name = "lsm-tree" name = "lsm-tree"
version = "3.1.2" version = "3.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d67f95fd716870329c30aaeedf87f23d426564e6ce46efa045a91444faf2a19" checksum = "e9bfd2a6ea0c1d430c13643002f35800a87f200fc8ac4827f18a2db9d9fd0644"
dependencies = [ dependencies = [
"byteorder-lite", "byteorder-lite",
"byteview", "byteview",
@@ -2097,7 +2094,7 @@ dependencies = [
"enum_dispatch", "enum_dispatch",
"interval-heap", "interval-heap",
"log", "log",
"lz4_flex", "lz4_flex 0.11.6",
"quick_cache", "quick_cache",
"rustc-hash", "rustc-hash",
"self_cell", "self_cell",
@@ -2109,13 +2106,19 @@ dependencies = [
[[package]] [[package]]
name = "lz4_flex" name = "lz4_flex"
version = "0.13.0" version = "0.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db9a0d582c2874f68138a16ce1867e0ffde6c0bb0a0df85e1f36d04146db488a" checksum = "373f5eceeeab7925e0c1098212f2fbc4d416adec9d35051a6ab251e824c1854a"
dependencies = [ dependencies = [
"twox-hash", "twox-hash",
] ]
[[package]]
name = "lz4_flex"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db9a0d582c2874f68138a16ce1867e0ffde6c0bb0a0df85e1f36d04146db488a"
[[package]] [[package]]
name = "matchit" name = "matchit"
version = "0.8.4" version = "0.8.4"
@@ -2180,9 +2183,9 @@ dependencies = [
[[package]] [[package]]
name = "mio" name = "mio"
version = "1.1.1" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
dependencies = [ dependencies = [
"libc", "libc",
"wasi", "wasi",
@@ -2324,12 +2327,6 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.32" version = "0.3.32"
@@ -2412,9 +2409,9 @@ dependencies = [
[[package]] [[package]]
name = "potential_utf" name = "potential_utf"
version = "0.1.4" version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564"
dependencies = [ dependencies = [
"zerovec", "zerovec",
] ]
@@ -2545,9 +2542,9 @@ dependencies = [
[[package]] [[package]]
name = "rawdb" name = "rawdb"
version = "0.8.0" version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ebc4ac8e255d001f609b3d3002c7209e1668b9ab0aedf9a6a263e2e7e2c3cdb" checksum = "f23b5d5fae99af33e8d0c82763b890c469dcf18b48600ed78b0d70fce4dbe189"
dependencies = [ dependencies = [
"libc", "libc",
"log", "log",
@@ -2678,9 +2675,9 @@ checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"
[[package]] [[package]]
name = "rustc-hash" name = "rustc-hash"
version = "2.1.1" version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"
[[package]] [[package]]
name = "rustc_version" name = "rustc_version"
@@ -2916,9 +2913,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_spanned" name = "serde_spanned"
version = "1.1.0" version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "876ac351060d4f882bb1032b6369eb0aef79ad9df1ea8bc404874d8cc3d0cd98" checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26"
dependencies = [ dependencies = [
"serde_core", "serde_core",
] ]
@@ -2963,9 +2960,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]] [[package]]
name = "simd-adler32" name = "simd-adler32"
version = "0.3.8" version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
[[package]] [[package]]
name = "slab" name = "slab"
@@ -3134,9 +3131,9 @@ dependencies = [
[[package]] [[package]]
name = "tinystr" name = "tinystr"
version = "0.8.2" version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
dependencies = [ dependencies = [
"displaydoc", "displaydoc",
"zerovec", "zerovec",
@@ -3182,9 +3179,9 @@ dependencies = [
[[package]] [[package]]
name = "toml" name = "toml"
version = "1.1.0+spec-1.1.0" version = "1.1.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8195ca05e4eb728f4ba94f3e3291661320af739c4e43779cbdfae82ab239fcc" checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"serde_core", "serde_core",
@@ -3197,27 +3194,27 @@ dependencies = [
[[package]] [[package]]
name = "toml_datetime" name = "toml_datetime"
version = "1.1.0+spec-1.1.0" version = "1.1.1+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97251a7c317e03ad83774a8752a7e81fb6067740609f75ea2b585b569a59198f" checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
dependencies = [ dependencies = [
"serde_core", "serde_core",
] ]
[[package]] [[package]]
name = "toml_parser" name = "toml_parser"
version = "1.1.0+spec-1.1.0" version = "1.1.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011" checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
dependencies = [ dependencies = [
"winnow", "winnow",
] ]
[[package]] [[package]]
name = "toml_writer" name = "toml_writer"
version = "1.1.0+spec-1.1.0" version = "1.1.1+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d282ade6016312faf3e41e57ebbba0c073e4056dab1232ab1cb624199648f8ed" checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db"
[[package]] [[package]]
name = "tower" name = "tower"
@@ -3439,14 +3436,14 @@ checksum = "8f54a172d0620933a27a4360d3db3e2ae0dd6cceae9730751a036bbf182c4b23"
[[package]] [[package]]
name = "vecdb" name = "vecdb"
version = "0.8.0" version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68e0237a44ee8ea6692e815154cc477a8c1936b27dca79bb1b9e093fa55e04a2" checksum = "a5fe60956ddba8c141ca8020aaf5bea55683475b83d19006c5f44b85c71bf974"
dependencies = [ dependencies = [
"itoa", "itoa",
"libc", "libc",
"log", "log",
"lz4_flex", "lz4_flex 0.13.0",
"parking_lot", "parking_lot",
"pco", "pco",
"rawdb", "rawdb",
@@ -3462,9 +3459,9 @@ dependencies = [
[[package]] [[package]]
name = "vecdb_derive" name = "vecdb_derive"
version = "0.8.0" version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fef159303d1f54cbb08b8249da70a9e1573145074949a91e9072addde209d65" checksum = "789897c1999d5d74f977020ad3d449846df046194103a4afcbac6d49baeaaffc"
dependencies = [ dependencies = [
"quote", "quote",
"syn", "syn",
@@ -3512,9 +3509,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.114" version = "0.2.117"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"once_cell", "once_cell",
@@ -3525,9 +3522,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.114" version = "0.2.117"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be"
dependencies = [ dependencies = [
"quote", "quote",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
@@ -3535,9 +3532,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.114" version = "0.2.117"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"proc-macro2", "proc-macro2",
@@ -3548,9 +3545,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.114" version = "0.2.117"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@@ -3591,9 +3588,9 @@ dependencies = [
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.91" version = "0.3.94"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" checksum = "cd70027e39b12f0849461e08ffc50b9cd7688d942c1c8e3c7b22273236b4dd0a"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",
@@ -3788,9 +3785,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "1.0.0" version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5"
[[package]] [[package]]
name = "wio" name = "wio"
@@ -3891,9 +3888,9 @@ dependencies = [
[[package]] [[package]]
name = "writeable" name = "writeable"
version = "0.6.2" version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
[[package]] [[package]]
name = "xxhash-rust" name = "xxhash-rust"
@@ -3914,9 +3911,9 @@ dependencies = [
[[package]] [[package]]
name = "yoke" name = "yoke"
version = "0.8.1" version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca"
dependencies = [ dependencies = [
"stable_deref_trait", "stable_deref_trait",
"yoke-derive", "yoke-derive",
@@ -3925,9 +3922,9 @@ dependencies = [
[[package]] [[package]]
name = "yoke-derive" name = "yoke-derive"
version = "0.8.1" version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -3937,18 +3934,18 @@ dependencies = [
[[package]] [[package]]
name = "zerocopy" name = "zerocopy"
version = "0.8.47" version = "0.8.48"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efbb2a062be311f2ba113ce66f697a4dc589f85e78a4aea276200804cea0ed87" checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
dependencies = [ dependencies = [
"zerocopy-derive", "zerocopy-derive",
] ]
[[package]] [[package]]
name = "zerocopy-derive" name = "zerocopy-derive"
version = "0.8.47" version = "0.8.48"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e8bc7269b54418e7aeeef514aa68f8690b8c0489a06b0136e5f57c4c5ccab89" checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -3957,18 +3954,18 @@ dependencies = [
[[package]] [[package]]
name = "zerofrom" name = "zerofrom"
version = "0.1.6" version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df"
dependencies = [ dependencies = [
"zerofrom-derive", "zerofrom-derive",
] ]
[[package]] [[package]]
name = "zerofrom-derive" name = "zerofrom-derive"
version = "0.1.6" version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -3984,9 +3981,9 @@ checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
[[package]] [[package]]
name = "zerotrie" name = "zerotrie"
version = "0.2.3" version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf"
dependencies = [ dependencies = [
"displaydoc", "displaydoc",
"yoke", "yoke",
@@ -3995,9 +3992,9 @@ dependencies = [
[[package]] [[package]]
name = "zerovec" name = "zerovec"
version = "0.11.5" version = "0.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
dependencies = [ dependencies = [
"yoke", "yoke",
"zerofrom", "zerofrom",
@@ -4006,9 +4003,9 @@ dependencies = [
[[package]] [[package]]
name = "zerovec-derive" name = "zerovec-derive"
version = "0.11.2" version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
+28 -27
View File
@@ -4,7 +4,7 @@ members = ["crates/*"]
package.description = "The Bitcoin Research Kit is a suite of tools designed to extract, compute and display data stored on a Bitcoin Core node" package.description = "The Bitcoin Research Kit is a suite of tools designed to extract, compute and display data stored on a Bitcoin Core node"
package.license = "MIT" package.license = "MIT"
package.edition = "2024" package.edition = "2024"
package.version = "0.2.4" package.version = "0.3.0-beta.1"
package.homepage = "https://bitcoinresearchkit.org" package.homepage = "https://bitcoinresearchkit.org"
package.repository = "https://github.com/bitcoinresearchkit/brk" package.repository = "https://github.com/bitcoinresearchkit/brk"
package.readme = "README.md" package.readme = "README.md"
@@ -40,42 +40,42 @@ aide = { version = "0.16.0-alpha.3", features = ["axum-json", "axum-query"] }
axum = { version = "0.8.8", default-features = false, features = ["http1", "json", "query", "tokio", "tracing"] } axum = { version = "0.8.8", default-features = false, features = ["http1", "json", "query", "tokio", "tracing"] }
bitcoin = { version = "0.32.8", features = ["serde"] } bitcoin = { version = "0.32.8", features = ["serde"] }
bitcoincore-rpc = "0.19.0" bitcoincore-rpc = "0.19.0"
brk_alloc = { version = "0.2.4", path = "crates/brk_alloc" } brk_alloc = { version = "0.3.0-beta.1", path = "crates/brk_alloc" }
brk_bencher = { version = "0.2.4", path = "crates/brk_bencher" } brk_bencher = { version = "0.3.0-beta.1", path = "crates/brk_bencher" }
brk_bindgen = { version = "0.2.4", path = "crates/brk_bindgen" } brk_bindgen = { version = "0.3.0-beta.1", path = "crates/brk_bindgen" }
brk_cli = { version = "0.2.4", path = "crates/brk_cli" } brk_cli = { version = "0.3.0-beta.1", path = "crates/brk_cli" }
brk_client = { version = "0.2.4", path = "crates/brk_client" } brk_client = { version = "0.3.0-beta.1", path = "crates/brk_client" }
brk_cohort = { version = "0.2.4", path = "crates/brk_cohort" } brk_cohort = { version = "0.3.0-beta.1", path = "crates/brk_cohort" }
brk_computer = { version = "0.2.4", path = "crates/brk_computer" } brk_computer = { version = "0.3.0-beta.1", path = "crates/brk_computer" }
brk_error = { version = "0.2.4", path = "crates/brk_error" } brk_error = { version = "0.3.0-beta.1", path = "crates/brk_error" }
brk_fetcher = { version = "0.2.4", path = "crates/brk_fetcher" } brk_fetcher = { version = "0.3.0-beta.1", path = "crates/brk_fetcher" }
brk_indexer = { version = "0.2.4", path = "crates/brk_indexer" } brk_indexer = { version = "0.3.0-beta.1", path = "crates/brk_indexer" }
brk_iterator = { version = "0.2.4", path = "crates/brk_iterator" } brk_iterator = { version = "0.3.0-beta.1", path = "crates/brk_iterator" }
brk_logger = { version = "0.2.4", path = "crates/brk_logger" } brk_logger = { version = "0.3.0-beta.1", path = "crates/brk_logger" }
brk_mempool = { version = "0.2.4", path = "crates/brk_mempool" } brk_mempool = { version = "0.3.0-beta.1", path = "crates/brk_mempool" }
brk_oracle = { version = "0.2.4", path = "crates/brk_oracle" } brk_oracle = { version = "0.3.0-beta.1", path = "crates/brk_oracle" }
brk_query = { version = "0.2.4", path = "crates/brk_query", features = ["tokio"] } brk_query = { version = "0.3.0-beta.1", path = "crates/brk_query", features = ["tokio"] }
brk_reader = { version = "0.2.4", path = "crates/brk_reader" } brk_reader = { version = "0.3.0-beta.1", path = "crates/brk_reader" }
brk_rpc = { version = "0.2.4", path = "crates/brk_rpc" } brk_rpc = { version = "0.3.0-beta.1", path = "crates/brk_rpc" }
brk_server = { version = "0.2.4", path = "crates/brk_server" } brk_server = { version = "0.3.0-beta.1", path = "crates/brk_server" }
brk_store = { version = "0.2.4", path = "crates/brk_store" } brk_store = { version = "0.3.0-beta.1", path = "crates/brk_store" }
brk_traversable = { version = "0.2.4", path = "crates/brk_traversable", features = ["pco", "derive"] } brk_traversable = { version = "0.3.0-beta.1", path = "crates/brk_traversable", features = ["pco", "derive"] }
brk_traversable_derive = { version = "0.2.4", path = "crates/brk_traversable_derive" } brk_traversable_derive = { version = "0.3.0-beta.1", path = "crates/brk_traversable_derive" }
brk_types = { version = "0.2.4", path = "crates/brk_types" } brk_types = { version = "0.3.0-beta.1", path = "crates/brk_types" }
brk_website = { version = "0.2.4", path = "crates/brk_website" } brk_website = { version = "0.3.0-beta.1", path = "crates/brk_website" }
byteview = "0.10.1" byteview = "0.10.1"
color-eyre = "0.6.5" color-eyre = "0.6.5"
corepc-client = { package = "brk-corepc-client", version = "0.11.0", features = ["client-sync"] } corepc-client = { package = "brk-corepc-client", version = "0.11.0", features = ["client-sync"] }
corepc-jsonrpc = { package = "brk-corepc-jsonrpc", version = "0.19.0", features = ["simple_http"], default-features = false } corepc-jsonrpc = { package = "brk-corepc-jsonrpc", version = "0.19.0", features = ["simple_http"], default-features = false }
derive_more = { version = "2.1.1", features = ["deref", "deref_mut"] } derive_more = { version = "2.1.1", features = ["deref", "deref_mut"] }
fjall = "3.1.2" fjall = "=3.0.4"
indexmap = { version = "2.13.0", features = ["serde"] } indexmap = { version = "2.13.0", features = ["serde"] }
jiff = { version = "0.2.23", features = ["perf-inline", "tz-system"], default-features = false } jiff = { version = "0.2.23", features = ["perf-inline", "tz-system"], default-features = false }
owo-colors = "4.3.0" owo-colors = "4.3.0"
parking_lot = "0.12.5" parking_lot = "0.12.5"
pco = "1.0.1" pco = "1.0.1"
rayon = "1.11.0" rayon = "1.11.0"
rustc-hash = "2.1.1" rustc-hash = "2.1.2"
schemars = { version = "1.2.1", features = ["indexmap2"] } schemars = { version = "1.2.1", features = ["indexmap2"] }
serde = "1.0.228" serde = "1.0.228"
serde_bytes = "0.11.19" serde_bytes = "0.11.19"
@@ -87,7 +87,7 @@ tower-http = { version = "0.6.8", features = ["catch-panic", "compression-br", "
tower-layer = "0.3" tower-layer = "0.3"
tracing = { version = "0.1", default-features = false, features = ["std"] } tracing = { version = "0.1", default-features = false, features = ["std"] }
ureq = { version = "3.3.0", features = ["json"] } ureq = { version = "3.3.0", features = ["json"] }
vecdb = { version = "0.8.0", features = ["derive", "serde_json", "pco", "schemars"] } vecdb = { version = "0.9.3", features = ["derive", "serde_json", "pco", "schemars"] }
# vecdb = { path = "../anydb/crates/vecdb", features = ["derive", "serde_json", "pco", "schemars"] } # vecdb = { path = "../anydb/crates/vecdb", features = ["derive", "serde_json", "pco", "schemars"] }
[workspace.metadata.release] [workspace.metadata.release]
@@ -95,6 +95,7 @@ shared-version = true
tag-name = "v{{version}}" tag-name = "v{{version}}"
pre-release-commit-message = "release: v{{version}}" pre-release-commit-message = "release: v{{version}}"
tag-message = "release: v{{version}}" tag-message = "release: v{{version}}"
allow-branch = ["main", "next"]
[workspace.metadata.dist] [workspace.metadata.dist]
cargo-dist-version = "0.30.2" cargo-dist-version = "0.30.2"
+293 -66
View File
@@ -108,7 +108,13 @@ fn fill_mixed_empty_field_parts(
// Recurse first (bottom-up) // Recurse first (bottom-up)
for (field_name, child_node) in children { for (field_name, child_node) in children {
let child_path = build_child_path(path, field_name); let child_path = build_child_path(path, field_name);
fill_mixed_empty_field_parts(child_node, &child_path, pattern_lookup, patterns, node_bases); fill_mixed_empty_field_parts(
child_node,
&child_path,
pattern_lookup,
patterns,
node_bases,
);
} }
// Check if this node has mixed empty/non-empty field_parts // Check if this node has mixed empty/non-empty field_parts
@@ -351,16 +357,18 @@ fn try_embedded_disc(
} }
/// Strategy 2: suffix discriminator (e.g., all field_parts differ by `_4y` suffix) /// Strategy 2: suffix discriminator (e.g., all field_parts differ by `_4y` suffix)
fn try_suffix_disc( fn try_suffix_disc(majority: &[&InstanceAnalysis], fields: &[PatternField]) -> Option<PatternMode> {
majority: &[&InstanceAnalysis],
fields: &[PatternField],
) -> Option<PatternMode> {
let first = &majority[0]; let first = &majority[0];
// Use a non-empty field to detect the suffix // Use a non-empty field to detect the suffix
let ref_field = fields let ref_field = fields
.iter() .iter()
.find(|f| first.field_parts.get(&f.name).is_some_and(|v| !v.is_empty())) .find(|f| {
first
.field_parts
.get(&f.name)
.is_some_and(|v| !v.is_empty())
})
.map(|f| &f.name)?; .map(|f| &f.name)?;
let ref_first = first.field_parts.get(ref_field)?; let ref_first = first.field_parts.get(ref_field)?;
@@ -763,19 +771,51 @@ mod tests {
fn test_embedded_disc_percentile_bands() { fn test_embedded_disc_percentile_bands() {
use std::collections::BTreeSet; use std::collections::BTreeSet;
let fields = vec![ let fields = vec![
PatternField { name: "bps".into(), rust_type: "T".into(), json_type: "n".into(), indexes: BTreeSet::new(), type_param: None }, PatternField {
PatternField { name: "price".into(), rust_type: "T".into(), json_type: "n".into(), indexes: BTreeSet::new(), type_param: None }, name: "bps".into(),
PatternField { name: "ratio".into(), rust_type: "T".into(), json_type: "n".into(), indexes: BTreeSet::new(), type_param: None }, rust_type: "T".into(),
json_type: "n".into(),
indexes: BTreeSet::new(),
type_param: None,
},
PatternField {
name: "price".into(),
rust_type: "T".into(),
json_type: "n".into(),
indexes: BTreeSet::new(),
type_param: None,
},
PatternField {
name: "ratio".into(),
rust_type: "T".into(),
json_type: "n".into(),
indexes: BTreeSet::new(),
type_param: None,
},
]; ];
let pct99 = InstanceAnalysis { let pct99 = InstanceAnalysis {
base: "realized_price".into(), base: "realized_price".into(),
field_parts: [("bps".into(), "ratio_pct99_bps".into()), ("price".into(), "pct99".into()), ("ratio".into(), "ratio_pct99".into())].into_iter().collect(), field_parts: [
is_suffix_mode: true, has_outlier: false, ("bps".into(), "ratio_pct99_bps".into()),
("price".into(), "pct99".into()),
("ratio".into(), "ratio_pct99".into()),
]
.into_iter()
.collect(),
is_suffix_mode: true,
has_outlier: false,
}; };
let pct1 = InstanceAnalysis { let pct1 = InstanceAnalysis {
base: "realized_price".into(), base: "realized_price".into(),
field_parts: [("bps".into(), "ratio_pct1_bps".into()), ("price".into(), "pct1".into()), ("ratio".into(), "ratio_pct1".into())].into_iter().collect(), field_parts: [
is_suffix_mode: true, has_outlier: false, ("bps".into(), "ratio_pct1_bps".into()),
("price".into(), "pct1".into()),
("ratio".into(), "ratio_pct1".into()),
]
.into_iter()
.collect(),
is_suffix_mode: true,
has_outlier: false,
}; };
let mode = determine_pattern_mode(&[pct99, pct1], &fields); let mode = determine_pattern_mode(&[pct99, pct1], &fields);
assert!(mode.is_some()); assert!(mode.is_some());
@@ -793,19 +833,51 @@ mod tests {
fn test_suffix_disc_period_windows() { fn test_suffix_disc_period_windows() {
use std::collections::BTreeSet; use std::collections::BTreeSet;
let fields = vec![ let fields = vec![
PatternField { name: "p1sd".into(), rust_type: "T".into(), json_type: "n".into(), indexes: BTreeSet::new(), type_param: None }, PatternField {
PatternField { name: "sd".into(), rust_type: "T".into(), json_type: "n".into(), indexes: BTreeSet::new(), type_param: None }, name: "p1sd".into(),
PatternField { name: "zscore".into(), rust_type: "T".into(), json_type: "n".into(), indexes: BTreeSet::new(), type_param: None }, rust_type: "T".into(),
json_type: "n".into(),
indexes: BTreeSet::new(),
type_param: None,
},
PatternField {
name: "sd".into(),
rust_type: "T".into(),
json_type: "n".into(),
indexes: BTreeSet::new(),
type_param: None,
},
PatternField {
name: "zscore".into(),
rust_type: "T".into(),
json_type: "n".into(),
indexes: BTreeSet::new(),
type_param: None,
},
]; ];
let all_time = InstanceAnalysis { let all_time = InstanceAnalysis {
base: "realized_price".into(), base: "realized_price".into(),
field_parts: [("p1sd".into(), "p1sd".into()), ("sd".into(), "ratio_sd".into()), ("zscore".into(), "ratio_zscore".into())].into_iter().collect(), field_parts: [
is_suffix_mode: true, has_outlier: false, ("p1sd".into(), "p1sd".into()),
("sd".into(), "ratio_sd".into()),
("zscore".into(), "ratio_zscore".into()),
]
.into_iter()
.collect(),
is_suffix_mode: true,
has_outlier: false,
}; };
let four_year = InstanceAnalysis { let four_year = InstanceAnalysis {
base: "realized_price".into(), base: "realized_price".into(),
field_parts: [("p1sd".into(), "p1sd_4y".into()), ("sd".into(), "ratio_sd_4y".into()), ("zscore".into(), "ratio_zscore_4y".into())].into_iter().collect(), field_parts: [
is_suffix_mode: true, has_outlier: false, ("p1sd".into(), "p1sd_4y".into()),
("sd".into(), "ratio_sd_4y".into()),
("zscore".into(), "ratio_zscore_4y".into()),
]
.into_iter()
.collect(),
is_suffix_mode: true,
has_outlier: false,
}; };
let mode = determine_pattern_mode(&[all_time, four_year], &fields); let mode = determine_pattern_mode(&[all_time, four_year], &fields);
assert!(mode.is_some()); assert!(mode.is_some());
@@ -823,18 +895,39 @@ mod tests {
fn test_suffix_disc_with_empty_fields() { fn test_suffix_disc_with_empty_fields() {
use std::collections::BTreeSet; use std::collections::BTreeSet;
let fields = vec![ let fields = vec![
PatternField { name: "band".into(), rust_type: "T".into(), json_type: "n".into(), indexes: BTreeSet::new(), type_param: None }, PatternField {
PatternField { name: "sd".into(), rust_type: "T".into(), json_type: "n".into(), indexes: BTreeSet::new(), type_param: None }, name: "band".into(),
rust_type: "T".into(),
json_type: "n".into(),
indexes: BTreeSet::new(),
type_param: None,
},
PatternField {
name: "sd".into(),
rust_type: "T".into(),
json_type: "n".into(),
indexes: BTreeSet::new(),
type_param: None,
},
]; ];
let all_time = InstanceAnalysis { let all_time = InstanceAnalysis {
base: "price".into(), base: "price".into(),
field_parts: [("band".into(), "".into()), ("sd".into(), "ratio_sd".into())].into_iter().collect(), field_parts: [("band".into(), "".into()), ("sd".into(), "ratio_sd".into())]
is_suffix_mode: true, has_outlier: false, .into_iter()
.collect(),
is_suffix_mode: true,
has_outlier: false,
}; };
let four_year = InstanceAnalysis { let four_year = InstanceAnalysis {
base: "price".into(), base: "price".into(),
field_parts: [("band".into(), "".into()), ("sd".into(), "ratio_sd_4y".into())].into_iter().collect(), field_parts: [
is_suffix_mode: true, has_outlier: false, ("band".into(), "".into()),
("sd".into(), "ratio_sd_4y".into()),
]
.into_iter()
.collect(),
is_suffix_mode: true,
has_outlier: false,
}; };
let mode = determine_pattern_mode(&[all_time, four_year], &fields); let mode = determine_pattern_mode(&[all_time, four_year], &fields);
assert!(mode.is_some()); assert!(mode.is_some());
@@ -851,18 +944,39 @@ mod tests {
fn test_suffix_disc_empty_to_nonempty() { fn test_suffix_disc_empty_to_nonempty() {
use std::collections::BTreeSet; use std::collections::BTreeSet;
let fields = vec![ let fields = vec![
PatternField { name: "all".into(), rust_type: "T".into(), json_type: "n".into(), indexes: BTreeSet::new(), type_param: None }, PatternField {
PatternField { name: "sth".into(), rust_type: "T".into(), json_type: "n".into(), indexes: BTreeSet::new(), type_param: None }, name: "all".into(),
rust_type: "T".into(),
json_type: "n".into(),
indexes: BTreeSet::new(),
type_param: None,
},
PatternField {
name: "sth".into(),
rust_type: "T".into(),
json_type: "n".into(),
indexes: BTreeSet::new(),
type_param: None,
},
]; ];
let regular = InstanceAnalysis { let regular = InstanceAnalysis {
base: "supply".into(), base: "supply".into(),
field_parts: [("all".into(), "".into()), ("sth".into(), "sth_".into())].into_iter().collect(), field_parts: [("all".into(), "".into()), ("sth".into(), "sth_".into())]
is_suffix_mode: true, has_outlier: false, .into_iter()
.collect(),
is_suffix_mode: true,
has_outlier: false,
}; };
let profitability = InstanceAnalysis { let profitability = InstanceAnalysis {
base: "utxos_in_profit".into(), base: "utxos_in_profit".into(),
field_parts: [("all".into(), "supply".into()), ("sth".into(), "sth_supply".into())].into_iter().collect(), field_parts: [
is_suffix_mode: true, has_outlier: false, ("all".into(), "supply".into()),
("sth".into(), "sth_supply".into()),
]
.into_iter()
.collect(),
is_suffix_mode: true,
has_outlier: false,
}; };
let mode = determine_pattern_mode(&[regular, profitability], &fields); let mode = determine_pattern_mode(&[regular, profitability], &fields);
assert!(mode.is_some()); assert!(mode.is_some());
@@ -879,43 +993,91 @@ mod tests {
fn test_outlier_rejects_pattern() { fn test_outlier_rejects_pattern() {
use std::collections::BTreeSet; use std::collections::BTreeSet;
let fields = vec![ let fields = vec![
PatternField { name: "ratio".into(), rust_type: "T".into(), json_type: "n".into(), indexes: BTreeSet::new(), type_param: None }, PatternField {
PatternField { name: "value".into(), rust_type: "T".into(), json_type: "n".into(), indexes: BTreeSet::new(), type_param: None }, name: "ratio".into(),
rust_type: "T".into(),
json_type: "n".into(),
indexes: BTreeSet::new(),
type_param: None,
},
PatternField {
name: "value".into(),
rust_type: "T".into(),
json_type: "n".into(),
indexes: BTreeSet::new(),
type_param: None,
},
]; ];
// SOPR case: one instance has outlier naming (no common prefix) // SOPR case: one instance has outlier naming (no common prefix)
let normal = InstanceAnalysis { let normal = InstanceAnalysis {
base: "series".into(), base: "series".into(),
field_parts: [("ratio".into(), "ratio".into()), ("value".into(), "value".into())].into_iter().collect(), field_parts: [
is_suffix_mode: true, has_outlier: false, ("ratio".into(), "ratio".into()),
("value".into(), "value".into()),
]
.into_iter()
.collect(),
is_suffix_mode: true,
has_outlier: false,
}; };
let outlier = InstanceAnalysis { let outlier = InstanceAnalysis {
base: "".into(), base: "".into(),
field_parts: [("ratio".into(), "asopr".into()), ("value".into(), "adj_value".into())].into_iter().collect(), field_parts: [
is_suffix_mode: true, has_outlier: true, ("ratio".into(), "asopr".into()),
("value".into(), "adj_value".into()),
]
.into_iter()
.collect(),
is_suffix_mode: true,
has_outlier: true,
}; };
let mode = determine_pattern_mode(&[normal, outlier], &fields); let mode = determine_pattern_mode(&[normal, outlier], &fields);
assert!(mode.is_some(), "Outlier should be filtered out, leaving a valid pattern from non-outlier instances"); assert!(
mode.is_some(),
"Outlier should be filtered out, leaving a valid pattern from non-outlier instances"
);
} }
#[test] #[test]
fn test_unanimity_rejects_disagreeing_instances() { fn test_unanimity_rejects_disagreeing_instances() {
use std::collections::BTreeSet; use std::collections::BTreeSet;
let fields = vec![ let fields = vec![
PatternField { name: "a".into(), rust_type: "T".into(), json_type: "n".into(), indexes: BTreeSet::new(), type_param: None }, PatternField {
PatternField { name: "b".into(), rust_type: "T".into(), json_type: "n".into(), indexes: BTreeSet::new(), type_param: None }, name: "a".into(),
rust_type: "T".into(),
json_type: "n".into(),
indexes: BTreeSet::new(),
type_param: None,
},
PatternField {
name: "b".into(),
rust_type: "T".into(),
json_type: "n".into(),
indexes: BTreeSet::new(),
type_param: None,
},
]; ];
let inst1 = InstanceAnalysis { let inst1 = InstanceAnalysis {
base: "x".into(), base: "x".into(),
field_parts: [("a".into(), "foo".into()), ("b".into(), "bar".into())].into_iter().collect(), field_parts: [("a".into(), "foo".into()), ("b".into(), "bar".into())]
is_suffix_mode: true, has_outlier: false, .into_iter()
.collect(),
is_suffix_mode: true,
has_outlier: false,
}; };
let inst2 = InstanceAnalysis { let inst2 = InstanceAnalysis {
base: "y".into(), base: "y".into(),
field_parts: [("a".into(), "baz".into()), ("b".into(), "qux".into())].into_iter().collect(), field_parts: [("a".into(), "baz".into()), ("b".into(), "qux".into())]
is_suffix_mode: true, has_outlier: false, .into_iter()
.collect(),
is_suffix_mode: true,
has_outlier: false,
}; };
let mode = determine_pattern_mode(&[inst1, inst2], &fields); let mode = determine_pattern_mode(&[inst1, inst2], &fields);
assert!(mode.is_none(), "Should be non-parameterizable when no pattern detected"); assert!(
mode.is_none(),
"Should be non-parameterizable when no pattern detected"
);
} }
#[test] #[test]
@@ -925,20 +1087,43 @@ mod tests {
// Should keep identity (empty parts) so both children receive acc unchanged. // Should keep identity (empty parts) so both children receive acc unchanged.
use std::collections::BTreeSet; use std::collections::BTreeSet;
let fields = vec![ let fields = vec![
PatternField { name: "absolute".into(), rust_type: "TypeA".into(), json_type: "n".into(), indexes: BTreeSet::new(), type_param: None }, PatternField {
PatternField { name: "rate".into(), rust_type: "TypeB".into(), json_type: "n".into(), indexes: BTreeSet::new(), type_param: None }, name: "absolute".into(),
rust_type: "TypeA".into(),
json_type: "n".into(),
indexes: BTreeSet::new(),
type_param: None,
},
PatternField {
name: "rate".into(),
rust_type: "TypeB".into(),
json_type: "n".into(),
indexes: BTreeSet::new(),
type_param: None,
},
]; ];
let inst = InstanceAnalysis { let inst = InstanceAnalysis {
base: "supply_delta".into(), base: "supply_delta".into(),
field_parts: [("absolute".into(), "".into()), ("rate".into(), "".into())].into_iter().collect(), field_parts: [("absolute".into(), "".into()), ("rate".into(), "".into())]
is_suffix_mode: true, has_outlier: false, .into_iter()
.collect(),
is_suffix_mode: true,
has_outlier: false,
}; };
let mode = determine_pattern_mode(&[inst], &fields); let mode = determine_pattern_mode(&[inst], &fields);
assert!(mode.is_some()); assert!(mode.is_some());
match mode.unwrap() { match mode.unwrap() {
PatternMode::Suffix { relatives } => { PatternMode::Suffix { relatives } => {
assert_eq!(relatives.get("absolute"), Some(&"".to_string()), "absolute should be identity"); assert_eq!(
assert_eq!(relatives.get("rate"), Some(&"".to_string()), "rate should be identity"); relatives.get("absolute"),
Some(&"".to_string()),
"absolute should be identity"
);
assert_eq!(
relatives.get("rate"),
Some(&"".to_string()),
"rate should be identity"
);
} }
other => panic!("Expected Suffix with identity, got {:?}", other), other => panic!("Expected Suffix with identity, got {:?}", other),
} }
@@ -975,16 +1160,26 @@ mod tests {
// Parent patterns containing non-parameterizable children should also // Parent patterns containing non-parameterizable children should also
// be detected via metadata.is_parameterizable (recursive check). // be detected via metadata.is_parameterizable (recursive check).
use std::collections::BTreeSet; use std::collections::BTreeSet;
let fields = vec![ let fields = vec![PatternField {
PatternField { name: "a".into(), rust_type: "T".into(), json_type: "n".into(), indexes: BTreeSet::new(), type_param: None }, name: "a".into(),
]; rust_type: "T".into(),
json_type: "n".into(),
indexes: BTreeSet::new(),
type_param: None,
}];
let inst = InstanceAnalysis { let inst = InstanceAnalysis {
base: "".into(), base: "".into(),
field_parts: [("a".into(), "standalone_name".into())].into_iter().collect(), field_parts: [("a".into(), "standalone_name".into())]
is_suffix_mode: true, has_outlier: true, .into_iter()
.collect(),
is_suffix_mode: true,
has_outlier: true,
}; };
let mode = determine_pattern_mode(&[inst], &fields); let mode = determine_pattern_mode(&[inst], &fields);
assert!(mode.is_none(), "Pattern with outlier should be non-parameterizable"); assert!(
mode.is_none(),
"Pattern with outlier should be non-parameterizable"
);
} }
#[test] #[test]
@@ -998,9 +1193,27 @@ mod tests {
let pattern = StructuralPattern { let pattern = StructuralPattern {
name: "TestPattern".into(), name: "TestPattern".into(),
fields: vec![ fields: vec![
PatternField { name: "_0sd".into(), rust_type: "T".into(), json_type: "n".into(), indexes: BTreeSet::new(), type_param: None }, PatternField {
PatternField { name: "p1sd".into(), rust_type: "T".into(), json_type: "n".into(), indexes: BTreeSet::new(), type_param: None }, name: "_0sd".into(),
PatternField { name: "sd".into(), rust_type: "T".into(), json_type: "n".into(), indexes: BTreeSet::new(), type_param: None }, rust_type: "T".into(),
json_type: "n".into(),
indexes: BTreeSet::new(),
type_param: None,
},
PatternField {
name: "p1sd".into(),
rust_type: "T".into(),
json_type: "n".into(),
indexes: BTreeSet::new(),
type_param: None,
},
PatternField {
name: "sd".into(),
rust_type: "T".into(),
json_type: "n".into(),
indexes: BTreeSet::new(),
type_param: None,
},
], ],
mode: Some(PatternMode::Templated { mode: Some(PatternMode::Templated {
templates: [ templates: [
@@ -1059,9 +1272,15 @@ mod tests {
assert_eq!(analysis.field_parts.get("loss"), Some(&"".to_string())); assert_eq!(analysis.field_parts.get("loss"), Some(&"".to_string()));
assert_eq!(analysis.field_parts.get("supply"), Some(&"".to_string())); assert_eq!(analysis.field_parts.get("supply"), Some(&"".to_string()));
// others should be non-empty // others should be non-empty
assert_eq!(analysis.field_parts.get("cap"), Some(&"realized_cap".to_string())); assert_eq!(
analysis.field_parts.get("cap"),
Some(&"realized_cap".to_string())
);
assert_eq!(analysis.field_parts.get("mvrv"), Some(&"mvrv".to_string())); assert_eq!(analysis.field_parts.get("mvrv"), Some(&"mvrv".to_string()));
assert_eq!(analysis.field_parts.get("price"), Some(&"realized_price".to_string())); assert_eq!(
analysis.field_parts.get("price"),
Some(&"realized_price".to_string())
);
} }
#[test] #[test]
@@ -1111,12 +1330,20 @@ mod tests {
&mut path_to_pattern, &mut path_to_pattern,
); );
let result = node_bases.get("test").expect("should have node_bases entry"); let result = node_bases
.get("test")
.expect("should have node_bases entry");
assert_eq!(result.base, "utxos"); assert_eq!(result.base, "utxos");
assert!(!result.has_outlier); assert!(!result.has_outlier);
assert_eq!(result.field_parts.get("cap"), Some(&"realized_cap".to_string())); assert_eq!(
result.field_parts.get("cap"),
Some(&"realized_cap".to_string())
);
assert_eq!(result.field_parts.get("mvrv"), Some(&"mvrv".to_string())); assert_eq!(result.field_parts.get("mvrv"), Some(&"mvrv".to_string()));
// loss branch returns base "utxos_realized_loss" which yields field_part "realized_loss" // loss branch returns base "utxos_realized_loss" which yields field_part "realized_loss"
assert_eq!(result.field_parts.get("loss"), Some(&"realized_loss".to_string())); assert_eq!(
result.field_parts.get("loss"),
Some(&"realized_loss".to_string())
);
} }
} }
+7 -4
View File
@@ -6,9 +6,9 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use brk_cohort::{ use brk_cohort::{
AGE_RANGE_NAMES, AMOUNT_RANGE_NAMES, CLASS_NAMES, EPOCH_NAMES, LOSS_NAMES, AGE_RANGE_NAMES, AMOUNT_RANGE_NAMES, CLASS_NAMES, EPOCH_NAMES, LOSS_NAMES, OVER_AGE_NAMES,
OVER_AGE_NAMES, OVER_AMOUNT_NAMES, PROFITABILITY_RANGE_NAMES, PROFIT_NAMES, OVER_AMOUNT_NAMES, PROFIT_NAMES, PROFITABILITY_RANGE_NAMES, SPENDABLE_TYPE_NAMES, TERM_NAMES,
SPENDABLE_TYPE_NAMES, TERM_NAMES, UNDER_AGE_NAMES, UNDER_AMOUNT_NAMES, UNDER_AGE_NAMES, UNDER_AMOUNT_NAMES,
}; };
use brk_types::{Index, PoolSlug, pools}; use brk_types::{Index, PoolSlug, pools};
use serde::Serialize; use serde::Serialize;
@@ -64,7 +64,10 @@ impl CohortConstants {
("AMOUNT_RANGE_NAMES", to_value(&AMOUNT_RANGE_NAMES)), ("AMOUNT_RANGE_NAMES", to_value(&AMOUNT_RANGE_NAMES)),
("OVER_AMOUNT_NAMES", to_value(&OVER_AMOUNT_NAMES)), ("OVER_AMOUNT_NAMES", to_value(&OVER_AMOUNT_NAMES)),
("UNDER_AMOUNT_NAMES", to_value(&UNDER_AMOUNT_NAMES)), ("UNDER_AMOUNT_NAMES", to_value(&UNDER_AMOUNT_NAMES)),
("PROFITABILITY_RANGE_NAMES", to_value(&PROFITABILITY_RANGE_NAMES)), (
"PROFITABILITY_RANGE_NAMES",
to_value(&PROFITABILITY_RANGE_NAMES),
),
("PROFIT_NAMES", to_value(&PROFIT_NAMES)), ("PROFIT_NAMES", to_value(&PROFIT_NAMES)),
("LOSS_NAMES", to_value(&LOSS_NAMES)), ("LOSS_NAMES", to_value(&LOSS_NAMES)),
] ]
+4 -4
View File
@@ -8,7 +8,9 @@ use std::fmt::Write;
use brk_types::SeriesLeafWithSchema; use brk_types::SeriesLeafWithSchema;
use crate::{ClientMetadata, LanguageSyntax, PatternBaseResult, PatternField, PatternMode, StructuralPattern}; use crate::{
ClientMetadata, LanguageSyntax, PatternBaseResult, PatternField, PatternMode, StructuralPattern,
};
/// Create a path suffix from a name. /// Create a path suffix from a name.
fn path_suffix(name: &str) -> String { fn path_suffix(name: &str) -> String {
@@ -33,9 +35,7 @@ fn compute_parameterized_value<S: LanguageSyntax>(
if let Some(child_pattern) = metadata.find_pattern(&field.rust_type) if let Some(child_pattern) = metadata.find_pattern(&field.rust_type)
&& child_pattern.is_templated() && child_pattern.is_templated()
{ {
let disc_template = pattern let disc_template = pattern.get_field_part(&field.name).unwrap_or(&field.name);
.get_field_part(&field.name)
.unwrap_or(&field.name);
let disc_arg = syntax.disc_arg_expr(disc_template); let disc_arg = syntax.disc_arg_expr(disc_template);
let acc_arg = syntax.owned_expr("acc"); let acc_arg = syntax.owned_expr("acc");
return syntax.constructor(&field.rust_type, &format!("{acc_arg}, {disc_arg}")); return syntax.constructor(&field.rust_type, &format!("{acc_arg}, {disc_arg}"));
+2 -2
View File
@@ -125,8 +125,8 @@ pub fn prepare_tree_node<'a>(
p.is_suffix_mode() == base_result.is_suffix_mode p.is_suffix_mode() == base_result.is_suffix_mode
&& p.field_parts_match(&base_result.field_parts) && p.field_parts_match(&base_result.field_parts)
}); });
let is_parameterizable = matching_pattern let is_parameterizable =
.is_none_or(|p| metadata.is_parameterizable(&p.name)); matching_pattern.is_none_or(|p| metadata.is_parameterizable(&p.name));
// should_inline determines if we generate an inline struct type // should_inline determines if we generate an inline struct type
let should_inline = !is_leaf let should_inline = !is_leaf
@@ -69,31 +69,48 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) {
.unwrap(); .unwrap();
} }
writeln!(
output,
" * @param {{{{ signal?: AbortSignal, onUpdate?: (value: {}) => void }}}} [options]",
return_type
)
.unwrap();
writeln!(output, " * @returns {{Promise<{}>}}", return_type).unwrap(); writeln!(output, " * @returns {{Promise<{}>}}", return_type).unwrap();
writeln!(output, " */").unwrap(); writeln!(output, " */").unwrap();
let params = build_method_params(endpoint); let params = build_method_params(endpoint);
writeln!(output, " async {}({}) {{", method_name, params).unwrap(); let params_with_opts = if params.is_empty() {
"{ signal, onUpdate } = {}".to_string()
} else {
format!("{}, {{ signal, onUpdate }} = {{}}", params)
};
writeln!(output, " async {}({}) {{", method_name, params_with_opts).unwrap();
let path = build_path_template(&endpoint.path, &endpoint.path_params); let path = build_path_template(&endpoint.path, &endpoint.path_params);
if endpoint.query_params.is_empty() { if endpoint.query_params.is_empty() {
writeln!(output, " return this.getJson(`{}`);", path).unwrap(); writeln!(
output,
" return this.getJson(`{}`, {{ signal, onUpdate }});",
path
)
.unwrap();
} else { } else {
writeln!(output, " const params = new URLSearchParams();").unwrap(); writeln!(output, " const params = new URLSearchParams();").unwrap();
for param in &endpoint.query_params { for param in &endpoint.query_params {
let ident = sanitize_ident(&param.name);
if param.required { if param.required {
writeln!( writeln!(
output, output,
" params.set('{}', String({}));", " params.set('{}', String({}));",
param.name, param.name param.name, ident
) )
.unwrap(); .unwrap();
} else { } else {
writeln!( writeln!(
output, output,
" if ({} !== undefined) params.set('{}', String({}));", " if ({} !== undefined) params.set('{}', String({}));",
param.name, param.name, param.name ident, param.name, ident
) )
.unwrap(); .unwrap();
} }
@@ -108,11 +125,19 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) {
if endpoint.supports_csv { if endpoint.supports_csv {
writeln!(output, " if (format === 'csv') {{").unwrap(); writeln!(output, " if (format === 'csv') {{").unwrap();
writeln!(output, " return this.getText(path);").unwrap(); writeln!(output, " return this.getText(path, {{ signal }});").unwrap();
writeln!(output, " }}").unwrap(); writeln!(output, " }}").unwrap();
writeln!(output, " return this.getJson(path);").unwrap(); writeln!(
output,
" return this.getJson(path, {{ signal, onUpdate }});"
)
.unwrap();
} else { } else {
writeln!(output, " return this.getJson(path);").unwrap(); writeln!(
output,
" return this.getJson(path, {{ signal, onUpdate }});"
)
.unwrap();
} }
} }
@@ -127,14 +152,19 @@ fn endpoint_to_method_name(endpoint: &Endpoint) -> String {
fn build_method_params(endpoint: &Endpoint) -> String { fn build_method_params(endpoint: &Endpoint) -> String {
let mut params = Vec::new(); let mut params = Vec::new();
for param in &endpoint.path_params { for param in &endpoint.path_params {
params.push(param.name.clone()); params.push(sanitize_ident(&param.name));
} }
for param in &endpoint.query_params { for param in &endpoint.query_params {
params.push(param.name.clone()); params.push(sanitize_ident(&param.name));
} }
params.join(", ") params.join(", ")
} }
/// Strip characters invalid in JS identifiers (e.g. `[]` from `txId[]`).
fn sanitize_ident(name: &str) -> String {
name.replace(['[', ']'], "")
}
fn build_path_template(path: &str, path_params: &[Parameter]) -> String { fn build_path_template(path: &str, path_params: &[Parameter]) -> String {
let mut result = path.to_string(); let mut result = path.to_string();
for param in path_params { for param in path_params {
@@ -22,6 +22,20 @@ pub fn generate_base_client(output: &mut String) {
const _isBrowser = typeof window !== 'undefined' && 'caches' in window; const _isBrowser = typeof window !== 'undefined' && 'caches' in window;
const _runIdle = (/** @type {{VoidFunction}} */ fn) => (globalThis.requestIdleCallback ?? setTimeout)(fn); const _runIdle = (/** @type {{VoidFunction}} */ fn) => (globalThis.requestIdleCallback ?? setTimeout)(fn);
const _defaultCacheName = '__BRK_CLIENT__'; const _defaultCacheName = '__BRK_CLIENT__';
/** @param {{*}} v */
const _addCamelGetters = (v) => {{
if (Array.isArray(v)) {{ v.forEach(_addCamelGetters); return v; }}
if (v && typeof v === 'object' && v.constructor === Object) {{
for (const k in v) {{
if (k.includes('_')) {{
const c = k.replace(/_([a-z])/g, (_, l) => l.toUpperCase());
if (!(c in v)) Object.defineProperty(v, c, {{ get() {{ return this[k]; }} }});
}}
_addCamelGetters(v[k]);
}}
}}
return v;
}};
/** /**
* @param {{string|boolean|undefined}} cache * @param {{string|boolean|undefined}} cache
@@ -390,11 +404,14 @@ class BrkClientBase {{
/** /**
* @param {{string}} path * @param {{string}} path
* @param {{{{ signal?: AbortSignal }}}} [options]
* @returns {{Promise<Response>}} * @returns {{Promise<Response>}}
*/ */
async get(path) {{ async get(path, {{ signal }} = {{}}) {{
const url = `${{this.baseUrl}}${{path}}`; const url = `${{this.baseUrl}}${{path}}`;
const res = await fetch(url, {{ signal: AbortSignal.timeout(this.timeout) }}); const signals = [AbortSignal.timeout(this.timeout)];
if (signal) signals.push(signal);
const res = await fetch(url, {{ signal: AbortSignal.any(signals) }});
if (!res.ok) throw new BrkError(`HTTP ${{res.status}}: ${{url}}`, res.status); if (!res.ok) throw new BrkError(`HTTP ${{res.status}}: ${{url}}`, res.status);
return res; return res;
}} }}
@@ -403,10 +420,10 @@ class BrkClientBase {{
* Make a GET request - races cache vs network, first to resolve calls onUpdate * Make a GET request - races cache vs network, first to resolve calls onUpdate
* @template T * @template T
* @param {{string}} path * @param {{string}} path
* @param {{(value: T) => void}} [onUpdate] - Called when data is available (may be called twice: cache then network) * @param {{{{ onUpdate?: (value: T) => void, signal?: AbortSignal }}}} [options]
* @returns {{Promise<T>}} * @returns {{Promise<T>}}
*/ */
async getJson(path, onUpdate) {{ async getJson(path, {{ onUpdate, signal }} = {{}}) {{
const url = `${{this.baseUrl}}${{path}}`; const url = `${{this.baseUrl}}${{path}}`;
const cache = this._cache ?? await this._cachePromise; const cache = this._cache ?? await this._cachePromise;
@@ -418,7 +435,7 @@ class BrkClientBase {{
const cachePromise = cache?.match(url).then(async (res) => {{ const cachePromise = cache?.match(url).then(async (res) => {{
cachedRes = res ?? null; cachedRes = res ?? null;
if (!res) return null; if (!res) return null;
const json = await res.json(); const json = _addCamelGetters(await res.json());
if (!resolved && onUpdate) {{ if (!resolved && onUpdate) {{
resolved = true; resolved = true;
onUpdate(json); onUpdate(json);
@@ -426,9 +443,9 @@ class BrkClientBase {{
return json; return json;
}}); }});
const networkPromise = this.get(path).then(async (res) => {{ const networkPromise = this.get(path, {{ signal }}).then(async (res) => {{
const cloned = res.clone(); const cloned = res.clone();
const json = await res.json(); const json = _addCamelGetters(await res.json());
// Skip update if ETag matches and cache already delivered // Skip update if ETag matches and cache already delivered
if (cachedRes?.headers.get('ETag') === res.headers.get('ETag')) {{ if (cachedRes?.headers.get('ETag') === res.headers.get('ETag')) {{
if (!resolved && onUpdate) {{ if (!resolved && onUpdate) {{
@@ -458,10 +475,11 @@ class BrkClientBase {{
/** /**
* Make a GET request and return raw text (for CSV responses) * Make a GET request and return raw text (for CSV responses)
* @param {{string}} path * @param {{string}} path
* @param {{{{ signal?: AbortSignal }}}} [options]
* @returns {{Promise<string>}} * @returns {{Promise<string>}}
*/ */
async getText(path) {{ async getText(path, {{ signal }} = {{}}) {{
const res = await this.get(path); const res = await this.get(path, {{ signal }});
return res.text(); return res.text();
}} }}
@@ -474,7 +492,7 @@ class BrkClientBase {{
*/ */
async _fetchSeriesData(path, onUpdate) {{ async _fetchSeriesData(path, onUpdate) {{
const wrappedOnUpdate = onUpdate ? (/** @type {{SeriesData<T>}} */ raw) => onUpdate(_wrapSeriesData(raw)) : undefined; const wrappedOnUpdate = onUpdate ? (/** @type {{SeriesData<T>}} */ raw) => onUpdate(_wrapSeriesData(raw)) : undefined;
const raw = await this.getJson(path, wrappedOnUpdate); const raw = await this.getJson(path, {{ onUpdate: wrappedOnUpdate }});
return _wrapSeriesData(raw); return _wrapSeriesData(raw);
}} }}
}} }}
@@ -726,7 +744,12 @@ pub fn generate_structural_patterns(
writeln!(output, " */").unwrap(); writeln!(output, " */").unwrap();
if pattern.is_templated() { if pattern.is_templated() {
writeln!(output, "function create{}(client, acc, disc) {{", pattern.name).unwrap(); writeln!(
output,
"function create{}(client, acc, disc) {{",
pattern.name
)
.unwrap();
} else { } else {
writeln!(output, "function create{}(client, acc) {{", pattern.name).unwrap(); writeln!(output, "function create{}(client, acc) {{", pattern.name).unwrap();
} }
+12 -10
View File
@@ -56,11 +56,7 @@ pub fn generate_main_client(output: &mut String, endpoints: &[Endpoint]) {
) )
.unwrap(); .unwrap();
writeln!(output, " \"\"\"").unwrap(); writeln!(output, " \"\"\"").unwrap();
writeln!( writeln!(output, " return SeriesEndpoint(self, series, index)").unwrap();
output,
" return SeriesEndpoint(self, series, index)"
)
.unwrap();
writeln!(output).unwrap(); writeln!(output).unwrap();
// Generate helper methods // Generate helper methods
@@ -105,7 +101,7 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) {
.response_type .response_type
.as_deref() .as_deref()
.map(js_type_to_python) .map(js_type_to_python)
.unwrap_or_else(|| "Any".to_string()), .unwrap_or_else(|| "str".to_string()),
); );
let return_type = if endpoint.supports_csv { let return_type = if endpoint.supports_csv {
@@ -163,11 +159,17 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) {
// Build path // Build path
let path = build_path_template(&endpoint.path, &endpoint.path_params); let path = build_path_template(&endpoint.path, &endpoint.path_params);
let fetch_method = if endpoint.returns_json() {
"get_json"
} else {
"get_text"
};
if endpoint.query_params.is_empty() { if endpoint.query_params.is_empty() {
if endpoint.path_params.is_empty() { if endpoint.path_params.is_empty() {
writeln!(output, " return self.get_json('{}')", path).unwrap(); writeln!(output, " return self.{}('{}')", fetch_method, path).unwrap();
} else { } else {
writeln!(output, " return self.get_json(f'{}')", path).unwrap(); writeln!(output, " return self.{}(f'{}')", fetch_method, path).unwrap();
} }
} else { } else {
writeln!(output, " params = []").unwrap(); writeln!(output, " params = []").unwrap();
@@ -201,9 +203,9 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) {
if endpoint.supports_csv { if endpoint.supports_csv {
writeln!(output, " if format == 'csv':").unwrap(); writeln!(output, " if format == 'csv':").unwrap();
writeln!(output, " return self.get_text(path)").unwrap(); writeln!(output, " return self.get_text(path)").unwrap();
writeln!(output, " return self.get_json(path)").unwrap(); writeln!(output, " return self.{}(path)", fetch_method).unwrap();
} else { } else {
writeln!(output, " return self.get_json(path)").unwrap(); writeln!(output, " return self.{}(path)", fetch_method).unwrap();
} }
} }
@@ -684,7 +684,6 @@ pub fn generate_structural_patterns(
writeln!(output, "# Reusable structural pattern classes\n").unwrap(); writeln!(output, "# Reusable structural pattern classes\n").unwrap();
for pattern in patterns { for pattern in patterns {
// Generate class // Generate class
if pattern.is_generic { if pattern.is_generic {
writeln!(output, "class {}(Generic[T]):", pattern.name).unwrap(); writeln!(output, "class {}(Generic[T]):", pattern.name).unwrap();
+36 -12
View File
@@ -93,7 +93,7 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) {
.response_type .response_type
.as_deref() .as_deref()
.map(js_type_to_rust) .map(js_type_to_rust)
.unwrap_or_else(|| "serde_json::Value".to_string()); .unwrap_or_else(|| "String".to_string());
let return_type = if endpoint.supports_csv { let return_type = if endpoint.supports_csv {
format!("FormatResponse<{}>", base_return_type) format!("FormatResponse<{}>", base_return_type)
@@ -132,29 +132,43 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) {
.unwrap(); .unwrap();
let (path, index_arg) = build_path_template(endpoint); let (path, index_arg) = build_path_template(endpoint);
let fetch_method = if endpoint.returns_json() {
"get_json"
} else {
"get_text"
};
if endpoint.query_params.is_empty() { if endpoint.query_params.is_empty() {
writeln!( writeln!(
output, output,
" self.base.get_json(&format!(\"{}\"{}))", " self.base.{}(&format!(\"{}\"{}))",
path, index_arg fetch_method, path, index_arg
) )
.unwrap(); .unwrap();
} else { } else {
writeln!(output, " let mut query = Vec::new();").unwrap(); writeln!(output, " let mut query = Vec::new();").unwrap();
for param in &endpoint.query_params { for param in &endpoint.query_params {
if param.required { let ident = sanitize_ident(&param.name);
let is_array = param.param_type.ends_with("[]");
if is_array {
writeln!(
output,
" for v in {} {{ query.push(format!(\"{}={{}}\", v)); }}",
ident, param.name
)
.unwrap();
} else if param.required {
writeln!( writeln!(
output, output,
" query.push(format!(\"{}={{}}\", {}));", " query.push(format!(\"{}={{}}\", {}));",
param.name, param.name param.name, ident
) )
.unwrap(); .unwrap();
} else { } else {
writeln!( writeln!(
output, output,
" if let Some(v) = {} {{ query.push(format!(\"{}={{}}\", v)); }}", " if let Some(v) = {} {{ query.push(format!(\"{}={{}}\", v)); }}",
param.name, param.name ident, param.name
) )
.unwrap(); .unwrap();
} }
@@ -177,12 +191,13 @@ pub fn generate_api_methods(output: &mut String, endpoints: &[Endpoint]) {
writeln!(output, " }} else {{").unwrap(); writeln!(output, " }} else {{").unwrap();
writeln!( writeln!(
output, output,
" self.base.get_json(&path).map(FormatResponse::Json)" " self.base.{}(&path).map(FormatResponse::Json)",
fetch_method
) )
.unwrap(); .unwrap();
writeln!(output, " }}").unwrap(); writeln!(output, " }}").unwrap();
} else { } else {
writeln!(output, " self.base.get_json(&path)").unwrap(); writeln!(output, " self.base.{}(&path)", fetch_method).unwrap();
} }
} }
@@ -198,26 +213,35 @@ fn build_method_params(endpoint: &Endpoint) -> String {
let mut params = Vec::new(); let mut params = Vec::new();
for param in &endpoint.path_params { for param in &endpoint.path_params {
let rust_type = param_type_to_rust(&param.param_type); let rust_type = param_type_to_rust(&param.param_type);
params.push(format!(", {}: {}", param.name, rust_type)); params.push(format!(", {}: {}", sanitize_ident(&param.name), rust_type));
} }
for param in &endpoint.query_params { for param in &endpoint.query_params {
let rust_type = param_type_to_rust(&param.param_type); let rust_type = param_type_to_rust(&param.param_type);
let name = sanitize_ident(&param.name);
if param.required { if param.required {
params.push(format!(", {}: {}", param.name, rust_type)); params.push(format!(", {}: {}", name, rust_type));
} else { } else {
params.push(format!(", {}: Option<{}>", param.name, rust_type)); params.push(format!(", {}: Option<{}>", name, rust_type));
} }
} }
params.join("") params.join("")
} }
/// Strip characters invalid in Rust identifiers (e.g. `[]` from `txId[]`).
fn sanitize_ident(name: &str) -> String {
name.replace(['[', ']'], "")
}
/// Convert parameter type to Rust type for function signatures. /// Convert parameter type to Rust type for function signatures.
fn param_type_to_rust(param_type: &str) -> String { fn param_type_to_rust(param_type: &str) -> String {
if let Some(inner) = param_type.strip_suffix("[]") {
return format!("&[{}]", param_type_to_rust(inner));
}
match param_type { match param_type {
"string" | "*" => "&str".to_string(), "string" | "*" => "&str".to_string(),
"integer" | "number" => "i64".to_string(), "integer" | "number" => "i64".to_string(),
"boolean" => "bool".to_string(), "boolean" => "bool".to_string(),
other => other.to_string(), // Domain types like Index, SeriesName, Format other => other.to_string(),
} }
} }
+5
View File
@@ -43,6 +43,11 @@ impl Endpoint {
self.method == "GET" && !self.deprecated self.method == "GET" && !self.deprecated
} }
/// Returns true if this endpoint returns JSON (has a response_type extracted from application/json).
pub fn returns_json(&self) -> bool {
self.response_type.is_some()
}
/// Returns the operation ID or generates one from the path. /// Returns the operation ID or generates one from the path.
/// The returned string uses the raw case from the spec (typically camelCase). /// The returned string uses the raw case from the spec (typically camelCase).
pub fn operation_name(&self) -> String { pub fn operation_name(&self) -> String {
+3
View File
@@ -74,6 +74,9 @@ pub fn escape_python_keyword(name: &str) -> String {
"try", "while", "with", "yield", "try", "while", "with", "yield",
]; ];
// Strip characters invalid in identifiers (e.g. `[]` from `txId[]`)
let name = name.replace(['[', ']'], "");
// Prefix with underscore if starts with digit // Prefix with underscore if starts with digit
let name = if name.starts_with(|c: char| c.is_ascii_digit()) { let name = if name.starts_with(|c: char| c.is_ascii_digit()) {
format!("_{}", name) format!("_{}", name)
+1 -2
View File
@@ -13,7 +13,6 @@ brk_alloc = { workspace = true }
brk_computer = { workspace = true } brk_computer = { workspace = true }
brk_error = { workspace = true, features = ["tokio", "vecdb"] } brk_error = { workspace = true, features = ["tokio", "vecdb"] }
brk_indexer = { workspace = true } brk_indexer = { workspace = true }
brk_iterator = { workspace = true }
brk_logger = { workspace = true } brk_logger = { workspace = true }
brk_mempool = { workspace = true } brk_mempool = { workspace = true }
brk_query = { workspace = true } brk_query = { workspace = true }
@@ -26,7 +25,7 @@ owo-colors = { workspace = true }
tracing = { workspace = true } tracing = { workspace = true }
serde = { workspace = true } serde = { workspace = true }
tokio = { workspace = true } tokio = { workspace = true }
toml = "1.1.0" toml = "1.1.2"
vecdb = { workspace = true } vecdb = { workspace = true }
[[bin]] [[bin]]
+2 -5
View File
@@ -1,11 +1,8 @@
# BRK CLI # BRK CLI
Command-line interface for running a Bitcoin Research Kit instance. Run your own Bitcoin Research Kit instance. One binary, one command. Full sync in ~4-7h depending on hardware. ~44% disk overhead vs 250% for mempool/electrs.
## Demo [bitview.space](https://bitview.space) is the official free hosted instance.
- [bitview.space](https://bitview.space) - web interface
- [bitview.space/api](https://bitview.space/api) - API docs
## Requirements ## Requirements
+4 -7
View File
@@ -10,7 +10,6 @@ use brk_alloc::Mimalloc;
use brk_computer::Computer; use brk_computer::Computer;
use brk_error::Result; use brk_error::Result;
use brk_indexer::Indexer; use brk_indexer::Indexer;
use brk_iterator::Blocks;
use brk_mempool::Mempool; use brk_mempool::Mempool;
use brk_query::AsyncQuery; use brk_query::AsyncQuery;
use brk_reader::Reader; use brk_reader::Reader;
@@ -37,8 +36,6 @@ pub fn main() -> anyhow::Result<()> {
let reader = Reader::new(config.blocksdir(), &client); let reader = Reader::new(config.blocksdir(), &client);
let blocks = Blocks::new(&client, &reader);
let mut indexer = Indexer::forced_import(&config.brkdir())?; let mut indexer = Indexer::forced_import(&config.brkdir())?;
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
@@ -52,7 +49,7 @@ pub fn main() -> anyhow::Result<()> {
info!("Indexing {blocks_behind} blocks before starting server..."); info!("Indexing {blocks_behind} blocks before starting server...");
info!("---"); info!("---");
sleep(Duration::from_secs(10)); sleep(Duration::from_secs(10));
indexer.index(&blocks, &client, &exit)?; indexer.index(&reader, &client, &exit)?;
drop(indexer); drop(indexer);
Mimalloc::collect(); Mimalloc::collect();
indexer = Indexer::forced_import(&config.brkdir())?; indexer = Indexer::forced_import(&config.brkdir())?;
@@ -102,14 +99,14 @@ pub fn main() -> anyhow::Result<()> {
let total_start = Instant::now(); let total_start = Instant::now();
let starting_indexes = if cfg!(debug_assertions) { let starting_indexes = if cfg!(debug_assertions) {
indexer.checked_index(&blocks, &client, &exit)? indexer.checked_index(&reader, &client, &exit)?
} else { } else {
indexer.index(&blocks, &client, &exit)? indexer.index(&reader, &client, &exit)?
}; };
Mimalloc::collect(); Mimalloc::collect();
computer.compute(&indexer, starting_indexes, &reader, &exit)?; computer.compute(&indexer, starting_indexes, &exit)?;
info!("Total time: {:?}", total_start.elapsed()); info!("Total time: {:?}", total_start.elapsed());
info!("Waiting for new blocks..."); info!("Waiting for new blocks...");
+5076 -1118
View File
File diff suppressed because it is too large Load Diff
+3
View File
@@ -14,3 +14,6 @@ brk_traversable = { workspace = true }
vecdb = { workspace = true } vecdb = { workspace = true }
rayon = { workspace = true } rayon = { workspace = true }
serde = { workspace = true } serde = { workspace = true }
[package.metadata.cargo-machete]
ignored = ["vecdb"]
+3 -2
View File
@@ -75,7 +75,8 @@ impl<T> AddrGroups<T> {
} }
pub fn iter_overlapping_mut(&mut self) -> impl Iterator<Item = &mut T> { pub fn iter_overlapping_mut(&mut self) -> impl Iterator<Item = &mut T> {
self.under_amount.iter_mut().chain(self.over_amount.iter_mut()) self.under_amount
.iter_mut()
.chain(self.over_amount.iter_mut())
} }
} }
+23 -1
View File
@@ -201,7 +201,29 @@ impl<T> AgeRange<T> {
} }
pub fn from_array(arr: [T; 21]) -> Self { pub fn from_array(arr: [T; 21]) -> Self {
let [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20] = arr; let [
a0,
a1,
a2,
a3,
a4,
a5,
a6,
a7,
a8,
a9,
a10,
a11,
a12,
a13,
a14,
a15,
a16,
a17,
a18,
a19,
a20,
] = arr;
Self { Self {
under_1h: a0, under_1h: a0,
_1h_to_1d: a1, _1h_to_1d: a1,
+5 -1
View File
@@ -84,7 +84,11 @@ pub const AMOUNT_RANGE_NAMES: AmountRange<CohortName> = AmountRange {
_10sats_to_100sats: CohortName::new("10sats_to_100sats", "10-100 sats", "10-100 Sats"), _10sats_to_100sats: CohortName::new("10sats_to_100sats", "10-100 sats", "10-100 Sats"),
_100sats_to_1k_sats: CohortName::new("100sats_to_1k_sats", "100-1k sats", "100-1K Sats"), _100sats_to_1k_sats: CohortName::new("100sats_to_1k_sats", "100-1k sats", "100-1K Sats"),
_1k_sats_to_10k_sats: CohortName::new("1k_sats_to_10k_sats", "1k-10k sats", "1K-10K Sats"), _1k_sats_to_10k_sats: CohortName::new("1k_sats_to_10k_sats", "1k-10k sats", "1K-10K Sats"),
_10k_sats_to_100k_sats: CohortName::new("10k_sats_to_100k_sats", "10k-100k sats", "10K-100K Sats"), _10k_sats_to_100k_sats: CohortName::new(
"10k_sats_to_100k_sats",
"10k-100k sats",
"10K-100K Sats",
),
_100k_sats_to_1m_sats: CohortName::new("100k_sats_to_1m_sats", "100k-1M sats", "100K-1M Sats"), _100k_sats_to_1m_sats: CohortName::new("100k_sats_to_1m_sats", "100k-1M sats", "100K-1M Sats"),
_1m_sats_to_10m_sats: CohortName::new("1m_sats_to_10m_sats", "1M-10M sats", "1M-10M Sats"), _1m_sats_to_10m_sats: CohortName::new("1m_sats_to_10m_sats", "1M-10M sats", "1M-10M Sats"),
_10m_sats_to_1btc: CohortName::new("10m_sats_to_1btc", "0.1-1 BTC", "0.1-1 BTC"), _10m_sats_to_1btc: CohortName::new("10m_sats_to_1btc", "0.1-1 BTC", "0.1-1 BTC"),
+2 -2
View File
@@ -1,8 +1,8 @@
#![doc = include_str!("../README.md")] #![doc = include_str!("../README.md")]
mod addr; mod addr;
mod amount_filter;
mod age_range; mod age_range;
mod amount_filter;
mod amount_range; mod amount_range;
mod by_addr_type; mod by_addr_type;
mod by_any_addr; mod by_any_addr;
@@ -30,8 +30,8 @@ mod utxo;
pub use brk_types::{Age, Term}; pub use brk_types::{Age, Term};
pub use addr::*; pub use addr::*;
pub use amount_filter::*;
pub use age_range::*; pub use age_range::*;
pub use amount_filter::*;
pub use amount_range::*; pub use amount_range::*;
pub use by_addr_type::*; pub use by_addr_type::*;
pub use by_any_addr::*; pub use by_any_addr::*;
+1 -1
View File
@@ -153,6 +153,6 @@ impl<T> Loss<T> {
.into_iter() .into_iter()
.rev() .rev()
.enumerate() .enumerate()
.map(move |(n, threshold)| (threshold, &ranges[len - 1 - n..])) .map(move |(n, threshold)| (threshold, &ranges[len - 2 - n..]))
} }
} }
+18 -6
View File
@@ -43,19 +43,31 @@ pub const OVER_AMOUNT_NAMES: OverAmount<CohortName> = OverAmount {
pub const OVER_AMOUNT_FILTERS: OverAmount<Filter> = OverAmount { pub const OVER_AMOUNT_FILTERS: OverAmount<Filter> = OverAmount {
_1sat: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._1sat)), _1sat: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._1sat)),
_10sats: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._10sats)), _10sats: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._10sats)),
_100sats: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._100sats)), _100sats: Filter::Amount(AmountFilter::GreaterOrEqual(
_1k_sats: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._1k_sats)), OVER_AMOUNT_THRESHOLDS._100sats,
_10k_sats: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._10k_sats)), )),
_1k_sats: Filter::Amount(AmountFilter::GreaterOrEqual(
OVER_AMOUNT_THRESHOLDS._1k_sats,
)),
_10k_sats: Filter::Amount(AmountFilter::GreaterOrEqual(
OVER_AMOUNT_THRESHOLDS._10k_sats,
)),
_100k_sats: Filter::Amount(AmountFilter::GreaterOrEqual( _100k_sats: Filter::Amount(AmountFilter::GreaterOrEqual(
OVER_AMOUNT_THRESHOLDS._100k_sats, OVER_AMOUNT_THRESHOLDS._100k_sats,
)), )),
_1m_sats: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._1m_sats)), _1m_sats: Filter::Amount(AmountFilter::GreaterOrEqual(
_10m_sats: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._10m_sats)), OVER_AMOUNT_THRESHOLDS._1m_sats,
)),
_10m_sats: Filter::Amount(AmountFilter::GreaterOrEqual(
OVER_AMOUNT_THRESHOLDS._10m_sats,
)),
_1btc: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._1btc)), _1btc: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._1btc)),
_10btc: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._10btc)), _10btc: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._10btc)),
_100btc: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._100btc)), _100btc: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._100btc)),
_1k_btc: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._1k_btc)), _1k_btc: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._1k_btc)),
_10k_btc: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._10k_btc)), _10k_btc: Filter::Amount(AmountFilter::GreaterOrEqual(
OVER_AMOUNT_THRESHOLDS._10k_btc,
)),
}; };
#[derive(Default, Clone, Traversable, Serialize)] #[derive(Default, Clone, Traversable, Serialize)]
+21 -5
View File
@@ -16,10 +16,26 @@ pub const PROFIT_NAMES: Profit<CohortName> = Profit {
_70pct: CohortName::new("utxos_over_70pct_in_profit", ">=70%", "Over 70% in Profit"), _70pct: CohortName::new("utxos_over_70pct_in_profit", ">=70%", "Over 70% in Profit"),
_80pct: CohortName::new("utxos_over_80pct_in_profit", ">=80%", "Over 80% in Profit"), _80pct: CohortName::new("utxos_over_80pct_in_profit", ">=80%", "Over 80% in Profit"),
_90pct: CohortName::new("utxos_over_90pct_in_profit", ">=90%", "Over 90% in Profit"), _90pct: CohortName::new("utxos_over_90pct_in_profit", ">=90%", "Over 90% in Profit"),
_100pct: CohortName::new("utxos_over_100pct_in_profit", ">=100%", "Over 100% in Profit"), _100pct: CohortName::new(
_200pct: CohortName::new("utxos_over_200pct_in_profit", ">=200%", "Over 200% in Profit"), "utxos_over_100pct_in_profit",
_300pct: CohortName::new("utxos_over_300pct_in_profit", ">=300%", "Over 300% in Profit"), ">=100%",
_500pct: CohortName::new("utxos_over_500pct_in_profit", ">=500%", "Over 500% in Profit"), "Over 100% in Profit",
),
_200pct: CohortName::new(
"utxos_over_200pct_in_profit",
">=200%",
"Over 200% in Profit",
),
_300pct: CohortName::new(
"utxos_over_300pct_in_profit",
">=300%",
"Over 300% in Profit",
),
_500pct: CohortName::new(
"utxos_over_500pct_in_profit",
">=500%",
"Over 500% in Profit",
),
}; };
/// Number of profit thresholds. /// Number of profit thresholds.
@@ -192,6 +208,6 @@ impl<T> Profit<T> {
.into_iter() .into_iter()
.rev() .rev()
.enumerate() .enumerate()
.map(move |(n, threshold)| (threshold, &ranges[..n + 1])) .map(move |(n, threshold)| (threshold, &ranges[..n + 2]))
} }
} }
+125 -25
View File
@@ -83,31 +83,131 @@ pub fn compute_profitability_boundaries(spot: Cents) -> [Cents; PROFITABILITY_BO
/// Profitability range names (25 ranges, from most profitable to most in loss) /// Profitability range names (25 ranges, from most profitable to most in loss)
pub const PROFITABILITY_RANGE_NAMES: ProfitabilityRange<CohortName> = ProfitabilityRange { pub const PROFITABILITY_RANGE_NAMES: ProfitabilityRange<CohortName> = ProfitabilityRange {
over_1000pct_in_profit: CohortName::new("utxos_over_1000pct_in_profit", "+>1000%", "Over 1000% in Profit"), over_1000pct_in_profit: CohortName::new(
_500pct_to_1000pct_in_profit: CohortName::new("utxos_500pct_to_1000pct_in_profit", "+500-1000%", "500-1000% in Profit"), "utxos_over_1000pct_in_profit",
_300pct_to_500pct_in_profit: CohortName::new("utxos_300pct_to_500pct_in_profit", "+300-500%", "300-500% in Profit"), "+>1000%",
_200pct_to_300pct_in_profit: CohortName::new("utxos_200pct_to_300pct_in_profit", "+200-300%", "200-300% in Profit"), "Over 1000% in Profit",
_100pct_to_200pct_in_profit: CohortName::new("utxos_100pct_to_200pct_in_profit", "+100-200%", "100-200% in Profit"), ),
_90pct_to_100pct_in_profit: CohortName::new("utxos_90pct_to_100pct_in_profit", "+90-100%", "90-100% in Profit"), _500pct_to_1000pct_in_profit: CohortName::new(
_80pct_to_90pct_in_profit: CohortName::new("utxos_80pct_to_90pct_in_profit", "+80-90%", "80-90% in Profit"), "utxos_500pct_to_1000pct_in_profit",
_70pct_to_80pct_in_profit: CohortName::new("utxos_70pct_to_80pct_in_profit", "+70-80%", "70-80% in Profit"), "+500-1000%",
_60pct_to_70pct_in_profit: CohortName::new("utxos_60pct_to_70pct_in_profit", "+60-70%", "60-70% in Profit"), "500-1000% in Profit",
_50pct_to_60pct_in_profit: CohortName::new("utxos_50pct_to_60pct_in_profit", "+50-60%", "50-60% in Profit"), ),
_40pct_to_50pct_in_profit: CohortName::new("utxos_40pct_to_50pct_in_profit", "+40-50%", "40-50% in Profit"), _300pct_to_500pct_in_profit: CohortName::new(
_30pct_to_40pct_in_profit: CohortName::new("utxos_30pct_to_40pct_in_profit", "+30-40%", "30-40% in Profit"), "utxos_300pct_to_500pct_in_profit",
_20pct_to_30pct_in_profit: CohortName::new("utxos_20pct_to_30pct_in_profit", "+20-30%", "20-30% in Profit"), "+300-500%",
_10pct_to_20pct_in_profit: CohortName::new("utxos_10pct_to_20pct_in_profit", "+10-20%", "10-20% in Profit"), "300-500% in Profit",
_0pct_to_10pct_in_profit: CohortName::new("utxos_0pct_to_10pct_in_profit", "+0-10%", "0-10% in Profit"), ),
_0pct_to_10pct_in_loss: CohortName::new("utxos_0pct_to_10pct_in_loss", "-0-10%", "0-10% in Loss"), _200pct_to_300pct_in_profit: CohortName::new(
_10pct_to_20pct_in_loss: CohortName::new("utxos_10pct_to_20pct_in_loss", "-10-20%", "10-20% in Loss"), "utxos_200pct_to_300pct_in_profit",
_20pct_to_30pct_in_loss: CohortName::new("utxos_20pct_to_30pct_in_loss", "-20-30%", "20-30% in Loss"), "+200-300%",
_30pct_to_40pct_in_loss: CohortName::new("utxos_30pct_to_40pct_in_loss", "-30-40%", "30-40% in Loss"), "200-300% in Profit",
_40pct_to_50pct_in_loss: CohortName::new("utxos_40pct_to_50pct_in_loss", "-40-50%", "40-50% in Loss"), ),
_50pct_to_60pct_in_loss: CohortName::new("utxos_50pct_to_60pct_in_loss", "-50-60%", "50-60% in Loss"), _100pct_to_200pct_in_profit: CohortName::new(
_60pct_to_70pct_in_loss: CohortName::new("utxos_60pct_to_70pct_in_loss", "-60-70%", "60-70% in Loss"), "utxos_100pct_to_200pct_in_profit",
_70pct_to_80pct_in_loss: CohortName::new("utxos_70pct_to_80pct_in_loss", "-70-80%", "70-80% in Loss"), "+100-200%",
_80pct_to_90pct_in_loss: CohortName::new("utxos_80pct_to_90pct_in_loss", "-80-90%", "80-90% in Loss"), "100-200% in Profit",
_90pct_to_100pct_in_loss: CohortName::new("utxos_90pct_to_100pct_in_loss", "-90-100%", "90-100% in Loss"), ),
_90pct_to_100pct_in_profit: CohortName::new(
"utxos_90pct_to_100pct_in_profit",
"+90-100%",
"90-100% in Profit",
),
_80pct_to_90pct_in_profit: CohortName::new(
"utxos_80pct_to_90pct_in_profit",
"+80-90%",
"80-90% in Profit",
),
_70pct_to_80pct_in_profit: CohortName::new(
"utxos_70pct_to_80pct_in_profit",
"+70-80%",
"70-80% in Profit",
),
_60pct_to_70pct_in_profit: CohortName::new(
"utxos_60pct_to_70pct_in_profit",
"+60-70%",
"60-70% in Profit",
),
_50pct_to_60pct_in_profit: CohortName::new(
"utxos_50pct_to_60pct_in_profit",
"+50-60%",
"50-60% in Profit",
),
_40pct_to_50pct_in_profit: CohortName::new(
"utxos_40pct_to_50pct_in_profit",
"+40-50%",
"40-50% in Profit",
),
_30pct_to_40pct_in_profit: CohortName::new(
"utxos_30pct_to_40pct_in_profit",
"+30-40%",
"30-40% in Profit",
),
_20pct_to_30pct_in_profit: CohortName::new(
"utxos_20pct_to_30pct_in_profit",
"+20-30%",
"20-30% in Profit",
),
_10pct_to_20pct_in_profit: CohortName::new(
"utxos_10pct_to_20pct_in_profit",
"+10-20%",
"10-20% in Profit",
),
_0pct_to_10pct_in_profit: CohortName::new(
"utxos_0pct_to_10pct_in_profit",
"+0-10%",
"0-10% in Profit",
),
_0pct_to_10pct_in_loss: CohortName::new(
"utxos_0pct_to_10pct_in_loss",
"-0-10%",
"0-10% in Loss",
),
_10pct_to_20pct_in_loss: CohortName::new(
"utxos_10pct_to_20pct_in_loss",
"-10-20%",
"10-20% in Loss",
),
_20pct_to_30pct_in_loss: CohortName::new(
"utxos_20pct_to_30pct_in_loss",
"-20-30%",
"20-30% in Loss",
),
_30pct_to_40pct_in_loss: CohortName::new(
"utxos_30pct_to_40pct_in_loss",
"-30-40%",
"30-40% in Loss",
),
_40pct_to_50pct_in_loss: CohortName::new(
"utxos_40pct_to_50pct_in_loss",
"-40-50%",
"40-50% in Loss",
),
_50pct_to_60pct_in_loss: CohortName::new(
"utxos_50pct_to_60pct_in_loss",
"-50-60%",
"50-60% in Loss",
),
_60pct_to_70pct_in_loss: CohortName::new(
"utxos_60pct_to_70pct_in_loss",
"-60-70%",
"60-70% in Loss",
),
_70pct_to_80pct_in_loss: CohortName::new(
"utxos_70pct_to_80pct_in_loss",
"-70-80%",
"70-80% in Loss",
),
_80pct_to_90pct_in_loss: CohortName::new(
"utxos_80pct_to_90pct_in_loss",
"-80-90%",
"80-90% in Loss",
),
_90pct_to_100pct_in_loss: CohortName::new(
"utxos_90pct_to_100pct_in_loss",
"-90-100%",
"90-100% in Loss",
),
}; };
impl ProfitabilityRange<CohortName> { impl ProfitabilityRange<CohortName> {
+2 -2
View File
@@ -2,8 +2,8 @@ use brk_traversable::Traversable;
use rayon::prelude::*; use rayon::prelude::*;
use crate::{ use crate::{
AgeRange, AmountRange, ByEpoch, OverAmount, UnderAmount, UnderAge, OverAge, AgeRange, AmountRange, ByEpoch, ByTerm, Class, Filter, OverAge, OverAmount, SpendableType,
Class, SpendableType, ByTerm, Filter, UnderAge, UnderAmount,
}; };
#[derive(Default, Clone, Traversable)] #[derive(Default, Clone, Traversable)]
+1 -3
View File
@@ -14,11 +14,8 @@ brk_error = { workspace = true, features = ["vecdb"] }
brk_cohort = { workspace = true } brk_cohort = { workspace = true }
brk_indexer = { workspace = true } brk_indexer = { workspace = true }
brk_oracle = { workspace = true } brk_oracle = { workspace = true }
brk_iterator = { workspace = true }
brk_logger = { workspace = true } brk_logger = { workspace = true }
brk_reader = { workspace = true }
brk_rpc = { workspace = true, features = ["corepc"] } brk_rpc = { workspace = true, features = ["corepc"] }
brk_store = { workspace = true }
brk_traversable = { workspace = true } brk_traversable = { workspace = true }
brk_types = { workspace = true } brk_types = { workspace = true }
derive_more = { workspace = true } derive_more = { workspace = true }
@@ -33,6 +30,7 @@ smallvec = { workspace = true }
vecdb = { workspace = true } vecdb = { workspace = true }
[dev-dependencies] [dev-dependencies]
brk_reader = { workspace = true }
brk_alloc = { workspace = true } brk_alloc = { workspace = true }
brk_bencher = { workspace = true } brk_bencher = { workspace = true }
color-eyre = { workspace = true } color-eyre = { workspace = true }
+3 -6
View File
@@ -8,7 +8,6 @@ use std::{
use brk_alloc::Mimalloc; use brk_alloc::Mimalloc;
use brk_computer::Computer; use brk_computer::Computer;
use brk_indexer::Indexer; use brk_indexer::Indexer;
use brk_iterator::Blocks;
use brk_reader::Reader; use brk_reader::Reader;
use brk_rpc::{Auth, Client}; use brk_rpc::{Auth, Client};
use vecdb::Exit; use vecdb::Exit;
@@ -31,8 +30,6 @@ pub fn main() -> color_eyre::Result<()> {
let reader = Reader::new(bitcoin_dir.join("blocks"), &client); let reader = Reader::new(bitcoin_dir.join("blocks"), &client);
let blocks = Blocks::new(&client, &reader);
let mut indexer = Indexer::forced_import(&outputs_dir)?; let mut indexer = Indexer::forced_import(&outputs_dir)?;
let exit = Exit::new(); let exit = Exit::new();
@@ -42,7 +39,7 @@ pub fn main() -> color_eyre::Result<()> {
let chain_height = client.get_last_height()?; let chain_height = client.get_last_height()?;
let indexed_height = indexer.vecs.starting_height(); let indexed_height = indexer.vecs.starting_height();
if u32::from(chain_height).saturating_sub(u32::from(indexed_height)) > 1000 { if u32::from(chain_height).saturating_sub(u32::from(indexed_height)) > 1000 {
indexer.checked_index(&blocks, &client, &exit)?; indexer.checked_index(&reader, &client, &exit)?;
drop(indexer); drop(indexer);
Mimalloc::collect(); Mimalloc::collect();
indexer = Indexer::forced_import(&outputs_dir)?; indexer = Indexer::forced_import(&outputs_dir)?;
@@ -52,11 +49,11 @@ pub fn main() -> color_eyre::Result<()> {
loop { loop {
let i = Instant::now(); let i = Instant::now();
let starting_indexes = indexer.checked_index(&blocks, &client, &exit)?; let starting_indexes = indexer.checked_index(&reader, &client, &exit)?;
Mimalloc::collect(); Mimalloc::collect();
computer.compute(&indexer, starting_indexes, &reader, &exit)?; computer.compute(&indexer, starting_indexes, &exit)?;
dbg!(i.elapsed()); dbg!(i.elapsed());
sleep(Duration::from_secs(10)); sleep(Duration::from_secs(10));
} }
@@ -5,7 +5,6 @@ use brk_bencher::Bencher;
use brk_computer::Computer; use brk_computer::Computer;
use brk_error::Result; use brk_error::Result;
use brk_indexer::Indexer; use brk_indexer::Indexer;
use brk_iterator::Blocks;
use brk_reader::Reader; use brk_reader::Reader;
use brk_rpc::{Auth, Client}; use brk_rpc::{Auth, Client};
use tracing::{debug, info}; use tracing::{debug, info};
@@ -28,8 +27,6 @@ pub fn main() -> Result<()> {
let reader = Reader::new(bitcoin_dir.join("blocks"), &client); let reader = Reader::new(bitcoin_dir.join("blocks"), &client);
let blocks = Blocks::new(&client, &reader);
let mut indexer = Indexer::forced_import(&outputs_dir)?; let mut indexer = Indexer::forced_import(&outputs_dir)?;
let mut computer = Computer::forced_import(&outputs_benches_dir, &indexer)?; let mut computer = Computer::forced_import(&outputs_benches_dir, &indexer)?;
@@ -47,13 +44,13 @@ pub fn main() -> Result<()> {
}); });
let i = Instant::now(); let i = Instant::now();
let starting_indexes = indexer.index(&blocks, &client, &exit)?; let starting_indexes = indexer.index(&reader, &client, &exit)?;
info!("Done in {:?}", i.elapsed()); info!("Done in {:?}", i.elapsed());
Mimalloc::collect(); Mimalloc::collect();
let i = Instant::now(); let i = Instant::now();
computer.compute(&indexer, starting_indexes, &reader, &exit)?; computer.compute(&indexer, starting_indexes, &exit)?;
info!("Done in {:?}", i.elapsed()); info!("Done in {:?}", i.elapsed());
// We want to benchmark the drop too // We want to benchmark the drop too
+3 -6
View File
@@ -9,7 +9,6 @@ use brk_alloc::Mimalloc;
use brk_bencher::Bencher; use brk_bencher::Bencher;
use brk_computer::Computer; use brk_computer::Computer;
use brk_indexer::Indexer; use brk_indexer::Indexer;
use brk_iterator::Blocks;
use brk_reader::Reader; use brk_reader::Reader;
use brk_rpc::{Auth, Client}; use brk_rpc::{Auth, Client};
use tracing::{debug, info}; use tracing::{debug, info};
@@ -45,15 +44,13 @@ pub fn main() -> color_eyre::Result<()> {
let reader = Reader::new(bitcoin_dir.join("blocks"), &client); let reader = Reader::new(bitcoin_dir.join("blocks"), &client);
let blocks = Blocks::new(&client, &reader);
let mut indexer = Indexer::forced_import(&outputs_dir)?; let mut indexer = Indexer::forced_import(&outputs_dir)?;
// Pre-run indexer if too far behind, then drop and reimport to reduce memory // Pre-run indexer if too far behind, then drop and reimport to reduce memory
let chain_height = client.get_last_height()?; let chain_height = client.get_last_height()?;
let indexed_height = indexer.vecs.starting_height(); let indexed_height = indexer.vecs.starting_height();
if chain_height.saturating_sub(*indexed_height) > 1000 { if chain_height.saturating_sub(*indexed_height) > 1000 {
indexer.index(&blocks, &client, &exit)?; indexer.index(&reader, &client, &exit)?;
drop(indexer); drop(indexer);
Mimalloc::collect(); Mimalloc::collect();
indexer = Indexer::forced_import(&outputs_dir)?; indexer = Indexer::forced_import(&outputs_dir)?;
@@ -63,13 +60,13 @@ pub fn main() -> color_eyre::Result<()> {
loop { loop {
let i = Instant::now(); let i = Instant::now();
let starting_indexes = indexer.index(&blocks, &client, &exit)?; let starting_indexes = indexer.index(&reader, &client, &exit)?;
info!("Done in {:?}", i.elapsed()); info!("Done in {:?}", i.elapsed());
Mimalloc::collect(); Mimalloc::collect();
let i = Instant::now(); let i = Instant::now();
computer.compute(&indexer, starting_indexes, &reader, &exit)?; computer.compute(&indexer, starting_indexes, &exit)?;
info!("Done in {:?}", i.elapsed()); info!("Done in {:?}", i.elapsed());
sleep(Duration::from_secs(60)); sleep(Duration::from_secs(60));
+2 -3
View File
@@ -38,8 +38,7 @@ impl Vecs {
let r1 = s.spawn(|| count.compute(indexer, starting_indexes, exit)); let r1 = s.spawn(|| count.compute(indexer, starting_indexes, exit));
let r2 = s.spawn(|| interval.compute(indexer, starting_indexes, exit)); let r2 = s.spawn(|| interval.compute(indexer, starting_indexes, exit));
let r3 = s.spawn(|| weight.compute(indexer, starting_indexes, exit)); let r3 = s.spawn(|| weight.compute(indexer, starting_indexes, exit));
let r4 = let r4 = s.spawn(|| difficulty.compute(indexer, indexes, starting_indexes, exit));
s.spawn(|| difficulty.compute(indexer, indexes, starting_indexes, exit));
let r5 = s.spawn(|| halving.compute(indexes, starting_indexes, exit)); let r5 = s.spawn(|| halving.compute(indexes, starting_indexes, exit));
size.compute(indexer, &*lookback, starting_indexes, exit)?; size.compute(indexer, &*lookback, starting_indexes, exit)?;
r1.join().unwrap()?; r1.join().unwrap()?;
@@ -53,7 +52,7 @@ impl Vecs {
let exit = exit.clone(); let exit = exit.clone();
self.db.run_bg(move |db| { self.db.run_bg(move |db| {
let _lock = exit.lock(); let _lock = exit.lock();
db.compact() db.compact_deferred_default()
}); });
Ok(()) Ok(())
} }
+22 -6
View File
@@ -6,8 +6,8 @@ use super::Vecs;
use crate::{ use crate::{
indexes, indexes,
internal::{ internal::{
BlockCountTarget24h, BlockCountTarget1w, BlockCountTarget1m, BlockCountTarget1y, BlockCountTarget1m, BlockCountTarget1w, BlockCountTarget1y, BlockCountTarget24h,
CachedWindowStarts, PerBlockCumulativeRolling, ConstantVecs, Windows, CachedWindowStarts, ConstantVecs, PerBlockCumulativeRolling, Windows,
}, },
}; };
@@ -20,10 +20,26 @@ impl Vecs {
) -> Result<Self> { ) -> Result<Self> {
Ok(Self { Ok(Self {
target: Windows { target: Windows {
_24h: ConstantVecs::new::<BlockCountTarget24h>("block_count_target_24h", version, indexes), _24h: ConstantVecs::new::<BlockCountTarget24h>(
_1w: ConstantVecs::new::<BlockCountTarget1w>("block_count_target_1w", version, indexes), "block_count_target_24h",
_1m: ConstantVecs::new::<BlockCountTarget1m>("block_count_target_1m", version, indexes), version,
_1y: ConstantVecs::new::<BlockCountTarget1y>("block_count_target_1y", version, indexes), indexes,
),
_1w: ConstantVecs::new::<BlockCountTarget1w>(
"block_count_target_1w",
version,
indexes,
),
_1m: ConstantVecs::new::<BlockCountTarget1m>(
"block_count_target_1m",
version,
indexes,
),
_1y: ConstantVecs::new::<BlockCountTarget1y>(
"block_count_target_1y",
version,
indexes,
),
}, },
total: PerBlockCumulativeRolling::forced_import( total: PerBlockCumulativeRolling::forced_import(
db, db,
+1 -1
View File
@@ -2,7 +2,7 @@ use brk_traversable::Traversable;
use brk_types::{StoredU32, StoredU64}; use brk_types::{StoredU32, StoredU64};
use vecdb::{Rw, StorageMode}; use vecdb::{Rw, StorageMode};
use crate::internal::{PerBlockCumulativeRolling, ConstantVecs, Windows}; use crate::internal::{ConstantVecs, PerBlockCumulativeRolling, Windows};
#[derive(Traversable)] #[derive(Traversable)]
pub struct Vecs<M: StorageMode = Rw> { pub struct Vecs<M: StorageMode = Rw> {
@@ -27,12 +27,8 @@ impl Vecs {
indexes, indexes,
); );
let blocks_to_retarget = PerBlock::forced_import( let blocks_to_retarget =
db, PerBlock::forced_import(db, "blocks_to_retarget", version + v2, indexes)?;
"blocks_to_retarget",
version + v2,
indexes,
)?;
let days_to_retarget = LazyPerBlock::from_computed::<BlocksToDaysF32>( let days_to_retarget = LazyPerBlock::from_computed::<BlocksToDaysF32>(
"days_to_retarget", "days_to_retarget",
@@ -2,7 +2,7 @@ use brk_traversable::Traversable;
use brk_types::{BasisPointsSigned32, Epoch, StoredF32, StoredF64, StoredU32}; use brk_types::{BasisPointsSigned32, Epoch, StoredF32, StoredF64, StoredU32};
use vecdb::{Rw, StorageMode}; use vecdb::{Rw, StorageMode};
use crate::internal::{LazyPerBlock, PerBlock, Resolutions, PercentPerBlock}; use crate::internal::{LazyPerBlock, PerBlock, PercentPerBlock, Resolutions};
#[derive(Traversable)] #[derive(Traversable)]
pub struct Vecs<M: StorageMode = Rw> { pub struct Vecs<M: StorageMode = Rw> {
pub value: Resolutions<StoredF64>, pub value: Resolutions<StoredF64>,
@@ -16,9 +16,8 @@ impl Vecs {
) -> Result<Self> { ) -> Result<Self> {
let v2 = Version::TWO; let v2 = Version::TWO;
let blocks_to_halving = PerBlock::forced_import( let blocks_to_halving =
db, "blocks_to_halving", version + v2, indexes, PerBlock::forced_import(db, "blocks_to_halving", version + v2, indexes)?;
)?;
let days_to_halving = LazyPerBlock::from_computed::<BlocksToDaysF32>( let days_to_halving = LazyPerBlock::from_computed::<BlocksToDaysF32>(
"days_to_halving", "days_to_halving",
+1 -2
View File
@@ -10,8 +10,7 @@ use crate::{
}; };
use super::{ use super::{
CountVecs, DifficultyVecs, HalvingVecs, IntervalVecs, LookbackVecs, SizeVecs, Vecs, CountVecs, DifficultyVecs, HalvingVecs, IntervalVecs, LookbackVecs, SizeVecs, Vecs, WeightVecs,
WeightVecs,
}; };
impl Vecs { impl Vecs {
@@ -13,27 +13,26 @@ impl Vecs {
exit: &Exit, exit: &Exit,
) -> Result<()> { ) -> Result<()> {
let mut prev_timestamp = None; let mut prev_timestamp = None;
self.0 self.0.compute(starting_indexes.height, exit, |vec| {
.compute(starting_indexes.height, exit, |vec| { vec.compute_transform(
vec.compute_transform( starting_indexes.height,
starting_indexes.height, &indexer.vecs.blocks.timestamp,
&indexer.vecs.blocks.timestamp, |(h, timestamp, ..)| {
|(h, timestamp, ..)| { let interval = if let Some(prev_h) = h.decremented() {
let interval = if let Some(prev_h) = h.decremented() { let prev = prev_timestamp.unwrap_or_else(|| {
let prev = prev_timestamp.unwrap_or_else(|| { indexer.vecs.blocks.timestamp.collect_one(prev_h).unwrap()
indexer.vecs.blocks.timestamp.collect_one(prev_h).unwrap() });
}); timestamp.checked_sub(prev).unwrap_or(Timestamp::ZERO)
timestamp.checked_sub(prev).unwrap_or(Timestamp::ZERO) } else {
} else { Timestamp::ZERO
Timestamp::ZERO };
}; prev_timestamp = Some(timestamp);
prev_timestamp = Some(timestamp); (h, interval)
(h, interval) },
}, exit,
exit, )?;
)?; Ok(())
Ok(()) })?;
})?;
Ok(()) Ok(())
} }
@@ -3,7 +3,10 @@ use brk_types::Version;
use vecdb::Database; use vecdb::Database;
use super::Vecs; use super::Vecs;
use crate::{indexes, internal::{CachedWindowStarts, PerBlockRollingAverage}}; use crate::{
indexes,
internal::{CachedWindowStarts, PerBlockRollingAverage},
};
impl Vecs { impl Vecs {
pub(crate) fn forced_import( pub(crate) fn forced_import(
+72 -43
View File
@@ -1,11 +1,14 @@
use brk_error::Result; use brk_error::Result;
use brk_traversable::Traversable; use brk_traversable::Traversable;
use brk_types::{Height, Indexes, Timestamp, Version}; use brk_types::{Height, Indexes, Timestamp, Version};
use vecdb::{AnyVec, CachedVec, Cursor, Database, EagerVec, Exit, ImportableVec, PcoVec, ReadableVec, Rw, StorageMode, VecIndex}; use vecdb::{
AnyVec, CachedVec, Cursor, Database, EagerVec, Exit, ImportableVec, PcoVec, ReadableVec, Rw,
StorageMode, VecIndex,
};
use crate::{ use crate::{
indexes, indexes,
internal::{CachedWindowStarts, Windows, WindowStarts}, internal::{CachedWindowStarts, WindowStarts, Windows},
}; };
#[derive(Traversable)] #[derive(Traversable)]
@@ -112,10 +115,49 @@ impl Vecs {
Ok(Self { Ok(Self {
cached_window_starts, cached_window_starts,
_1h, _24h, _3d, _1w, _8d, _9d, _12d, _13d, _2w, _21d, _26d, _1h,
_1m, _34d, _55d, _2m, _9w, _12w, _89d, _3m, _14w, _111d, _144d, _24h,
_6m, _26w, _200d, _9m, _350d, _12m, _1y, _14m, _2y, _26m, _3y, _3d,
_200w, _4y, _5y, _6y, _8y, _9y, _10y, _12y, _14y, _26y, _1w,
_8d,
_9d,
_12d,
_13d,
_2w,
_21d,
_26d,
_1m,
_34d,
_55d,
_2m,
_9w,
_12w,
_89d,
_3m,
_14w,
_111d,
_144d,
_6m,
_26w,
_200d,
_9m,
_350d,
_12m,
_1y,
_14m,
_2y,
_26m,
_3y,
_200w,
_4y,
_5y,
_6y,
_8y,
_9y,
_10y,
_12y,
_14y,
_26y,
}) })
} }
@@ -128,7 +170,6 @@ impl Vecs {
} }
} }
pub fn start_vec(&self, days: usize) -> &EagerVec<PcoVec<Height, Height>> { pub fn start_vec(&self, days: usize) -> &EagerVec<PcoVec<Height, Height>> {
match days { match days {
1 => &self._24h, 1 => &self._24h,
@@ -183,9 +224,7 @@ impl Vecs {
starting_indexes: &Indexes, starting_indexes: &Indexes,
exit: &Exit, exit: &Exit,
) -> Result<()> { ) -> Result<()> {
self.compute_rolling_start_hours(indexes, starting_indexes, exit, 1, |s| { self.compute_rolling_start_hours(indexes, starting_indexes, exit, 1, |s| &mut s._1h)?;
&mut s._1h
})?;
self.compute_rolling_start(indexes, starting_indexes, exit, 1, |s| &mut s._24h)?; self.compute_rolling_start(indexes, starting_indexes, exit, 1, |s| &mut s._24h)?;
self.compute_rolling_start(indexes, starting_indexes, exit, 3, |s| &mut s._3d)?; self.compute_rolling_start(indexes, starting_indexes, exit, 3, |s| &mut s._3d)?;
self.compute_rolling_start(indexes, starting_indexes, exit, 7, |s| &mut s._1w)?; self.compute_rolling_start(indexes, starting_indexes, exit, 7, |s| &mut s._1w)?;
@@ -205,47 +244,29 @@ impl Vecs {
self.compute_rolling_start(indexes, starting_indexes, exit, 89, |s| &mut s._89d)?; self.compute_rolling_start(indexes, starting_indexes, exit, 89, |s| &mut s._89d)?;
self.compute_rolling_start(indexes, starting_indexes, exit, 90, |s| &mut s._3m)?; self.compute_rolling_start(indexes, starting_indexes, exit, 90, |s| &mut s._3m)?;
self.compute_rolling_start(indexes, starting_indexes, exit, 98, |s| &mut s._14w)?; self.compute_rolling_start(indexes, starting_indexes, exit, 98, |s| &mut s._14w)?;
self.compute_rolling_start(indexes, starting_indexes, exit, 111, |s| { self.compute_rolling_start(indexes, starting_indexes, exit, 111, |s| &mut s._111d)?;
&mut s._111d self.compute_rolling_start(indexes, starting_indexes, exit, 144, |s| &mut s._144d)?;
})?;
self.compute_rolling_start(indexes, starting_indexes, exit, 144, |s| {
&mut s._144d
})?;
self.compute_rolling_start(indexes, starting_indexes, exit, 180, |s| &mut s._6m)?; self.compute_rolling_start(indexes, starting_indexes, exit, 180, |s| &mut s._6m)?;
self.compute_rolling_start(indexes, starting_indexes, exit, 182, |s| &mut s._26w)?; self.compute_rolling_start(indexes, starting_indexes, exit, 182, |s| &mut s._26w)?;
self.compute_rolling_start(indexes, starting_indexes, exit, 200, |s| { self.compute_rolling_start(indexes, starting_indexes, exit, 200, |s| &mut s._200d)?;
&mut s._200d
})?;
self.compute_rolling_start(indexes, starting_indexes, exit, 270, |s| &mut s._9m)?; self.compute_rolling_start(indexes, starting_indexes, exit, 270, |s| &mut s._9m)?;
self.compute_rolling_start(indexes, starting_indexes, exit, 350, |s| { self.compute_rolling_start(indexes, starting_indexes, exit, 350, |s| &mut s._350d)?;
&mut s._350d
})?;
self.compute_rolling_start(indexes, starting_indexes, exit, 360, |s| &mut s._12m)?; self.compute_rolling_start(indexes, starting_indexes, exit, 360, |s| &mut s._12m)?;
self.compute_rolling_start(indexes, starting_indexes, exit, 365, |s| &mut s._1y)?; self.compute_rolling_start(indexes, starting_indexes, exit, 365, |s| &mut s._1y)?;
self.compute_rolling_start(indexes, starting_indexes, exit, 420, |s| &mut s._14m)?; self.compute_rolling_start(indexes, starting_indexes, exit, 420, |s| &mut s._14m)?;
self.compute_rolling_start(indexes, starting_indexes, exit, 730, |s| &mut s._2y)?; self.compute_rolling_start(indexes, starting_indexes, exit, 730, |s| &mut s._2y)?;
self.compute_rolling_start(indexes, starting_indexes, exit, 780, |s| &mut s._26m)?; self.compute_rolling_start(indexes, starting_indexes, exit, 780, |s| &mut s._26m)?;
self.compute_rolling_start(indexes, starting_indexes, exit, 1095, |s| &mut s._3y)?; self.compute_rolling_start(indexes, starting_indexes, exit, 1095, |s| &mut s._3y)?;
self.compute_rolling_start(indexes, starting_indexes, exit, 1400, |s| { self.compute_rolling_start(indexes, starting_indexes, exit, 1400, |s| &mut s._200w)?;
&mut s._200w
})?;
self.compute_rolling_start(indexes, starting_indexes, exit, 1460, |s| &mut s._4y)?; self.compute_rolling_start(indexes, starting_indexes, exit, 1460, |s| &mut s._4y)?;
self.compute_rolling_start(indexes, starting_indexes, exit, 1825, |s| &mut s._5y)?; self.compute_rolling_start(indexes, starting_indexes, exit, 1825, |s| &mut s._5y)?;
self.compute_rolling_start(indexes, starting_indexes, exit, 2190, |s| &mut s._6y)?; self.compute_rolling_start(indexes, starting_indexes, exit, 2190, |s| &mut s._6y)?;
self.compute_rolling_start(indexes, starting_indexes, exit, 2920, |s| &mut s._8y)?; self.compute_rolling_start(indexes, starting_indexes, exit, 2920, |s| &mut s._8y)?;
self.compute_rolling_start(indexes, starting_indexes, exit, 3285, |s| &mut s._9y)?; self.compute_rolling_start(indexes, starting_indexes, exit, 3285, |s| &mut s._9y)?;
self.compute_rolling_start(indexes, starting_indexes, exit, 3650, |s| { self.compute_rolling_start(indexes, starting_indexes, exit, 3650, |s| &mut s._10y)?;
&mut s._10y self.compute_rolling_start(indexes, starting_indexes, exit, 4380, |s| &mut s._12y)?;
})?; self.compute_rolling_start(indexes, starting_indexes, exit, 5110, |s| &mut s._14y)?;
self.compute_rolling_start(indexes, starting_indexes, exit, 4380, |s| { self.compute_rolling_start(indexes, starting_indexes, exit, 9490, |s| &mut s._26y)?;
&mut s._12y
})?;
self.compute_rolling_start(indexes, starting_indexes, exit, 5110, |s| {
&mut s._14y
})?;
self.compute_rolling_start(indexes, starting_indexes, exit, 9490, |s| {
&mut s._26y
})?;
Ok(()) Ok(())
} }
@@ -261,9 +282,13 @@ impl Vecs {
where where
F: FnOnce(&mut Self) -> &mut EagerVec<PcoVec<Height, Height>>, F: FnOnce(&mut Self) -> &mut EagerVec<PcoVec<Height, Height>>,
{ {
self.compute_rolling_start_inner(indexes, starting_indexes, exit, get_field, |t, prev_ts| { self.compute_rolling_start_inner(
t.difference_in_days_between(prev_ts) >= days indexes,
}) starting_indexes,
exit,
get_field,
|t, prev_ts| t.difference_in_days_between(prev_ts) >= days,
)
} }
fn compute_rolling_start_hours<F>( fn compute_rolling_start_hours<F>(
@@ -277,9 +302,13 @@ impl Vecs {
where where
F: FnOnce(&mut Self) -> &mut EagerVec<PcoVec<Height, Height>>, F: FnOnce(&mut Self) -> &mut EagerVec<PcoVec<Height, Height>>,
{ {
self.compute_rolling_start_inner(indexes, starting_indexes, exit, get_field, |t, prev_ts| { self.compute_rolling_start_inner(
t.difference_in_hours_between(prev_ts) >= hours indexes,
}) starting_indexes,
exit,
get_field,
|t, prev_ts| t.difference_in_hours_between(prev_ts) >= hours,
)
} }
fn compute_rolling_start_inner<F, D>( fn compute_rolling_start_inner<F, D>(
@@ -28,10 +28,18 @@ impl Vecs {
Ok(Self { Ok(Self {
coinblocks_created: PerBlockCumulativeRolling::forced_import( coinblocks_created: PerBlockCumulativeRolling::forced_import(
db, "coinblocks_created", version, indexes, cached_starts, db,
"coinblocks_created",
version,
indexes,
cached_starts,
)?, )?,
coinblocks_stored: PerBlockCumulativeRolling::forced_import( coinblocks_stored: PerBlockCumulativeRolling::forced_import(
db, "coinblocks_stored", version, indexes, cached_starts, db,
"coinblocks_stored",
version,
indexes,
cached_starts,
)?, )?,
liveliness, liveliness,
vaultedness, vaultedness,
+1 -1
View File
@@ -85,7 +85,7 @@ impl Vecs {
let exit = exit.clone(); let exit = exit.clone();
self.db.run_bg(move |db| { self.db.run_bg(move |db| {
let _lock = exit.lock(); let _lock = exit.lock();
db.compact() db.compact_deferred_default()
}); });
Ok(()) Ok(())
} }
@@ -22,11 +22,8 @@ impl Vecs {
let circulating_supply = &all_metrics.supply.total.btc.height; let circulating_supply = &all_metrics.supply.total.btc.height;
let realized_price = &all_metrics.realized.price.cents.height; let realized_price = &all_metrics.realized.price.cents.height;
self.vaulted.compute_all( self.vaulted
prices, .compute_all(prices, starting_indexes, exit, |v| {
starting_indexes,
exit,
|v| {
Ok(v.compute_transform2( Ok(v.compute_transform2(
starting_indexes.height, starting_indexes.height,
realized_price, realized_price,
@@ -36,14 +33,10 @@ impl Vecs {
}, },
exit, exit,
)?) )?)
}, })?;
)?;
self.active.compute_all( self.active
prices, .compute_all(prices, starting_indexes, exit, |v| {
starting_indexes,
exit,
|v| {
Ok(v.compute_transform2( Ok(v.compute_transform2(
starting_indexes.height, starting_indexes.height,
realized_price, realized_price,
@@ -53,14 +46,10 @@ impl Vecs {
}, },
exit, exit,
)?) )?)
}, })?;
)?;
self.true_market_mean.compute_all( self.true_market_mean
prices, .compute_all(prices, starting_indexes, exit, |v| {
starting_indexes,
exit,
|v| {
Ok(v.compute_transform2( Ok(v.compute_transform2(
starting_indexes.height, starting_indexes.height,
&cap.investor.cents.height, &cap.investor.cents.height,
@@ -70,14 +59,10 @@ impl Vecs {
}, },
exit, exit,
)?) )?)
}, })?;
)?;
self.cointime.compute_all( self.cointime
prices, .compute_all(prices, starting_indexes, exit, |v| {
starting_indexes,
exit,
|v| {
Ok(v.compute_transform2( Ok(v.compute_transform2(
starting_indexes.height, starting_indexes.height,
&cap.cointime.cents.height, &cap.cointime.cents.height,
@@ -87,8 +72,7 @@ impl Vecs {
}, },
exit, exit,
)?) )?)
}, })?;
)?;
Ok(()) Ok(())
} }
@@ -3,10 +3,7 @@ use brk_types::Version;
use vecdb::Database; use vecdb::Database;
use super::Vecs; use super::Vecs;
use crate::{ use crate::{indexes, internal::PriceWithRatioExtendedPerBlock};
indexes,
internal::PriceWithRatioExtendedPerBlock,
};
impl Vecs { impl Vecs {
pub(crate) fn forced_import( pub(crate) fn forced_import(
@@ -23,7 +23,7 @@ impl Vecs {
self.hodl_bank.compute_cumulative_transformed_binary( self.hodl_bank.compute_cumulative_transformed_binary(
starting_indexes.height, starting_indexes.height,
&prices.spot.usd.height, &prices.cached_spot_usd,
&self.vocdd_median_1y, &self.vocdd_median_1y,
|price, median| StoredF64::from(f64::from(price) - f64::from(median)), |price, median| StoredF64::from(f64::from(price) - f64::from(median)),
exit, exit,
@@ -31,7 +31,7 @@ impl Vecs {
self.value.height.compute_divide( self.value.height.compute_divide(
starting_indexes.height, starting_indexes.height,
&prices.spot.usd.height, &prices.cached_spot_usd,
&self.hodl_bank, &self.hodl_bank,
exit, exit,
)?; )?;
@@ -38,7 +38,8 @@ impl Vecs {
exit, exit,
)?; )?;
self.vaulted.compute(prices, starting_indexes.height, exit)?; self.vaulted
.compute(prices, starting_indexes.height, exit)?;
self.active.compute(prices, starting_indexes.height, exit)?; self.active.compute(prices, starting_indexes.height, exit)?;
Ok(()) Ok(())
@@ -12,12 +12,7 @@ impl Vecs {
indexes: &indexes::Vecs, indexes: &indexes::Vecs,
) -> Result<Self> { ) -> Result<Self> {
Ok(Self { Ok(Self {
vaulted: AmountPerBlock::forced_import( vaulted: AmountPerBlock::forced_import(db, "vaulted_supply", version, indexes)?,
db,
"vaulted_supply",
version,
indexes,
)?,
active: AmountPerBlock::forced_import(db, "active_supply", version, indexes)?, active: AmountPerBlock::forced_import(db, "active_supply", version, indexes)?,
}) })
} }
@@ -24,59 +24,56 @@ impl Vecs {
.compute(starting_indexes.height, exit, |vec| { .compute(starting_indexes.height, exit, |vec| {
vec.compute_multiply( vec.compute_multiply(
starting_indexes.height, starting_indexes.height,
&prices.spot.usd.height, &prices.cached_spot_usd,
&coinblocks_destroyed.block, &coinblocks_destroyed.block,
exit, exit,
)?; )?;
Ok(()) Ok(())
})?; })?;
self.created self.created.compute(starting_indexes.height, exit, |vec| {
.compute(starting_indexes.height, exit, |vec| { vec.compute_multiply(
vec.compute_multiply( starting_indexes.height,
starting_indexes.height, &prices.cached_spot_usd,
&prices.spot.usd.height, &activity.coinblocks_created.block,
&activity.coinblocks_created.block, exit,
exit, )?;
)?; Ok(())
Ok(()) })?;
})?;
self.stored self.stored.compute(starting_indexes.height, exit, |vec| {
.compute(starting_indexes.height, exit, |vec| { vec.compute_multiply(
vec.compute_multiply( starting_indexes.height,
starting_indexes.height, &prices.cached_spot_usd,
&prices.spot.usd.height, &activity.coinblocks_stored.block,
&activity.coinblocks_stored.block, exit,
exit, )?;
)?; Ok(())
Ok(()) })?;
})?;
// VOCDD: Value of Coin Days Destroyed = price × (CDD / circulating_supply) // VOCDD: Value of Coin Days Destroyed = price × (CDD / circulating_supply)
// Supply-adjusted to account for growing supply over time // Supply-adjusted to account for growing supply over time
// This is a key input for Reserve Risk / HODL Bank calculation // This is a key input for Reserve Risk / HODL Bank calculation
self.vocdd self.vocdd.compute(starting_indexes.height, exit, |vec| {
.compute(starting_indexes.height, exit, |vec| { vec.compute_transform3(
vec.compute_transform3( starting_indexes.height,
starting_indexes.height, &prices.cached_spot_usd,
&prices.spot.usd.height, &coindays_destroyed.block,
&coindays_destroyed.block, circulating_supply,
circulating_supply, |(i, price, cdd, supply, _): (_, Dollars, StoredF64, Bitcoin, _)| {
|(i, price, cdd, supply, _): (_, Dollars, StoredF64, Bitcoin, _)| { let supply_f64 = f64::from(supply);
let supply_f64 = f64::from(supply); if supply_f64 == 0.0 {
if supply_f64 == 0.0 { (i, StoredF64::from(0.0))
(i, StoredF64::from(0.0)) } else {
} else { // VOCDD = price × (CDD / supply)
// VOCDD = price × (CDD / supply) let vocdd = f64::from(price) * f64::from(cdd) / supply_f64;
let vocdd = f64::from(price) * f64::from(cdd) / supply_f64; (i, StoredF64::from(vocdd))
(i, StoredF64::from(vocdd)) }
} },
}, exit,
exit, )?;
)?; Ok(())
Ok(()) })?;
})?;
Ok(()) Ok(())
} }
@@ -148,11 +148,7 @@ impl ActivityCountVecs {
self.both.block.push(counts.both.into()); self.both.block.push(counts.both.into());
} }
pub(crate) fn compute_rest( pub(crate) fn compute_rest(&mut self, max_from: Height, exit: &Exit) -> Result<()> {
&mut self,
max_from: Height,
exit: &Exit,
) -> Result<()> {
self.reactivated.compute_rest(max_from, exit)?; self.reactivated.compute_rest(max_from, exit)?;
self.sending.compute_rest(max_from, exit)?; self.sending.compute_rest(max_from, exit)?;
self.receiving.compute_rest(max_from, exit)?; self.receiving.compute_rest(max_from, exit)?;
@@ -180,8 +176,8 @@ impl AddrTypeToActivityCountVecs {
indexes: &indexes::Vecs, indexes: &indexes::Vecs,
cached_starts: &CachedWindowStarts, cached_starts: &CachedWindowStarts,
) -> Result<Self> { ) -> Result<Self> {
Ok(Self::from( Ok(Self::from(ByAddrType::<ActivityCountVecs>::new_with_name(
ByAddrType::<ActivityCountVecs>::new_with_name(|type_name| { |type_name| {
ActivityCountVecs::forced_import( ActivityCountVecs::forced_import(
db, db,
&format!("{type_name}_{name}"), &format!("{type_name}_{name}"),
@@ -189,8 +185,8 @@ impl AddrTypeToActivityCountVecs {
indexes, indexes,
cached_starts, cached_starts,
) )
})?, },
)) )?))
} }
pub(crate) fn min_stateful_len(&self) -> usize { pub(crate) fn min_stateful_len(&self) -> usize {
@@ -221,11 +217,7 @@ impl AddrTypeToActivityCountVecs {
Ok(()) Ok(())
} }
pub(crate) fn compute_rest( pub(crate) fn compute_rest(&mut self, max_from: Height, exit: &Exit) -> Result<()> {
&mut self,
max_from: Height,
exit: &Exit,
) -> Result<()> {
for type_vecs in self.0.values_mut() { for type_vecs in self.0.values_mut() {
type_vecs.compute_rest(max_from, exit)?; type_vecs.compute_rest(max_from, exit)?;
} }
@@ -259,7 +251,11 @@ impl AddrActivityVecs {
Ok(Self { Ok(Self {
all: ActivityCountVecs::forced_import(db, name, version, indexes, cached_starts)?, all: ActivityCountVecs::forced_import(db, name, version, indexes, cached_starts)?,
by_addr_type: AddrTypeToActivityCountVecs::forced_import( by_addr_type: AddrTypeToActivityCountVecs::forced_import(
db, name, version, indexes, cached_starts, db,
name,
version,
indexes,
cached_starts,
)?, )?,
}) })
} }
@@ -284,11 +280,7 @@ impl AddrActivityVecs {
Ok(()) Ok(())
} }
pub(crate) fn compute_rest( pub(crate) fn compute_rest(&mut self, max_from: Height, exit: &Exit) -> Result<()> {
&mut self,
max_from: Height,
exit: &Exit,
) -> Result<()> {
self.all.compute_rest(max_from, exit)?; self.all.compute_rest(max_from, exit)?;
self.by_addr_type.compute_rest(max_from, exit)?; self.by_addr_type.compute_rest(max_from, exit)?;
Ok(()) Ok(())
@@ -12,9 +12,7 @@ use vecdb::{
use crate::{indexes, internal::PerBlock}; use crate::{indexes, internal::PerBlock};
#[derive(Deref, DerefMut, Traversable)] #[derive(Deref, DerefMut, Traversable)]
pub struct AddrCountVecs<M: StorageMode = Rw>( pub struct AddrCountVecs<M: StorageMode = Rw>(#[traversable(flatten)] pub PerBlock<StoredU64, M>);
#[traversable(flatten)] pub PerBlock<StoredU64, M>,
);
impl AddrCountVecs { impl AddrCountVecs {
pub(crate) fn forced_import( pub(crate) fn forced_import(
@@ -23,9 +21,7 @@ impl AddrCountVecs {
version: Version, version: Version,
indexes: &indexes::Vecs, indexes: &indexes::Vecs,
) -> Result<Self> { ) -> Result<Self> {
Ok(Self(PerBlock::forced_import( Ok(Self(PerBlock::forced_import(db, name, version, indexes)?))
db, name, version, indexes,
)?))
} }
} }
@@ -57,42 +53,17 @@ impl From<(&AddrTypeToAddrCountVecs, Height)> for AddrTypeToAddrCount {
.collect_one(prev_height) .collect_one(prev_height)
.unwrap() .unwrap()
.into(), .into(),
p2pkh: groups p2pkh: groups.p2pkh.height.collect_one(prev_height).unwrap().into(),
.p2pkh p2sh: groups.p2sh.height.collect_one(prev_height).unwrap().into(),
.height
.collect_one(prev_height)
.unwrap()
.into(),
p2sh: groups
.p2sh
.height
.collect_one(prev_height)
.unwrap()
.into(),
p2wpkh: groups p2wpkh: groups
.p2wpkh .p2wpkh
.height .height
.collect_one(prev_height) .collect_one(prev_height)
.unwrap() .unwrap()
.into(), .into(),
p2wsh: groups p2wsh: groups.p2wsh.height.collect_one(prev_height).unwrap().into(),
.p2wsh p2tr: groups.p2tr.height.collect_one(prev_height).unwrap().into(),
.height p2a: groups.p2a.height.collect_one(prev_height).unwrap().into(),
.collect_one(prev_height)
.unwrap()
.into(),
p2tr: groups
.p2tr
.height
.collect_one(prev_height)
.unwrap()
.into(),
p2a: groups
.p2a
.height
.collect_one(prev_height)
.unwrap()
.into(),
}) })
} else { } else {
Default::default() Default::default()
@@ -177,7 +148,10 @@ impl AddrCountsVecs {
} }
pub(crate) fn min_stateful_len(&self) -> usize { pub(crate) fn min_stateful_len(&self) -> usize {
self.all.height.len().min(self.by_addr_type.min_stateful_len()) self.all
.height
.len()
.min(self.by_addr_type.min_stateful_len())
} }
pub(crate) fn par_iter_height_mut( pub(crate) fn par_iter_height_mut(
@@ -199,11 +173,7 @@ impl AddrCountsVecs {
self.by_addr_type.push_height(addr_counts); self.by_addr_type.push_height(addr_counts);
} }
pub(crate) fn compute_rest( pub(crate) fn compute_rest(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()> {
&mut self,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
let sources = self.by_addr_type.by_height(); let sources = self.by_addr_type.by_height();
self.all self.all
.height .height
@@ -1,8 +1,6 @@
use brk_error::Result; use brk_error::Result;
use brk_traversable::Traversable; use brk_traversable::Traversable;
use brk_types::{ use brk_types::{EmptyAddrData, EmptyAddrIndex, FundedAddrData, FundedAddrIndex, Height};
EmptyAddrData, EmptyAddrIndex, FundedAddrData, FundedAddrIndex, Height,
};
use rayon::prelude::*; use rayon::prelude::*;
use vecdb::{AnyStoredVec, BytesVec, Rw, Stamp, StorageMode, WritableVec}; use vecdb::{AnyStoredVec, BytesVec, Rw, Stamp, StorageMode, WritableVec};
@@ -45,9 +45,6 @@ impl DeltaVecs {
) )
}); });
Self { Self { all, by_addr_type }
all,
by_addr_type,
}
} }
} }
@@ -5,8 +5,8 @@ use brk_error::{Error, Result};
use brk_traversable::Traversable; use brk_traversable::Traversable;
use brk_types::{ use brk_types::{
AnyAddrIndex, Height, OutputType, P2AAddrIndex, P2PK33AddrIndex, P2PK65AddrIndex, AnyAddrIndex, Height, OutputType, P2AAddrIndex, P2PK33AddrIndex, P2PK65AddrIndex,
P2PKHAddrIndex, P2SHAddrIndex, P2TRAddrIndex, P2WPKHAddrIndex, P2WSHAddrIndex, P2PKHAddrIndex, P2SHAddrIndex, P2TRAddrIndex, P2WPKHAddrIndex, P2WSHAddrIndex, TypeIndex,
TypeIndex, Version, Version,
}; };
use rayon::prelude::*; use rayon::prelude::*;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
@@ -44,10 +44,7 @@ impl NewAddrCountVecs {
) )
})?; })?;
Ok(Self { Ok(Self { all, by_addr_type })
all,
by_addr_type,
})
} }
pub(crate) fn compute( pub(crate) fn compute(
@@ -24,20 +24,11 @@ impl TotalAddrCountVecs {
) -> Result<Self> { ) -> Result<Self> {
let all = PerBlock::forced_import(db, "total_addr_count", version, indexes)?; let all = PerBlock::forced_import(db, "total_addr_count", version, indexes)?;
let by_addr_type: ByAddrType<PerBlock<StoredU64>> = let by_addr_type: ByAddrType<PerBlock<StoredU64>> = ByAddrType::new_with_name(|name| {
ByAddrType::new_with_name(|name| { PerBlock::forced_import(db, &format!("{name}_total_addr_count"), version, indexes)
PerBlock::forced_import( })?;
db,
&format!("{name}_total_addr_count"),
version,
indexes,
)
})?;
Ok(Self { Ok(Self { all, by_addr_type })
all,
by_addr_type,
})
} }
/// Eagerly compute total = addr_count + empty_addr_count. /// Eagerly compute total = addr_count + empty_addr_count.
+1 -3
View File
@@ -103,9 +103,7 @@ pub(crate) fn load_uncached_addr_data(
// Check if this is a new address (type_index >= first for this height) // Check if this is a new address (type_index >= first for this height)
let first = *first_addr_indexes.get(addr_type).unwrap(); let first = *first_addr_indexes.get(addr_type).unwrap();
if first <= type_index { if first <= type_index {
return Ok(Some(WithAddrDataSource::New( return Ok(Some(WithAddrDataSource::New(FundedAddrData::default())));
FundedAddrData::default(),
)));
} }
// Skip if already in cache // Skip if already in cache
+1 -4
View File
@@ -26,10 +26,7 @@ impl<'a> AddrLookup<'a> {
&mut self, &mut self,
output_type: OutputType, output_type: OutputType,
type_index: TypeIndex, type_index: TypeIndex,
) -> ( ) -> (&mut WithAddrDataSource<FundedAddrData>, TrackingStatus) {
&mut WithAddrDataSource<FundedAddrData>,
TrackingStatus,
) {
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
let map = self.funded.get_mut(output_type).unwrap(); let map = self.funded.get_mut(output_type).unwrap();
@@ -1,7 +1,7 @@
use brk_error::Result; use brk_error::Result;
use brk_types::{ use brk_types::{
AnyAddrIndex, EmptyAddrData, EmptyAddrIndex, FundedAddrData, FundedAddrIndex, AnyAddrIndex, EmptyAddrData, EmptyAddrIndex, FundedAddrData, FundedAddrIndex, OutputType,
OutputType, TypeIndex, TypeIndex,
}; };
use vecdb::AnyVec; use vecdb::AnyVec;
@@ -26,7 +26,11 @@ pub(crate) fn process_received(
empty_addr_count: &mut ByAddrType<u64>, empty_addr_count: &mut ByAddrType<u64>,
activity_counts: &mut AddrTypeToActivityCounts, activity_counts: &mut AddrTypeToActivityCounts,
) { ) {
let max_type_len = received_data.iter().map(|(_, v)| v.len()).max().unwrap_or(0); let max_type_len = received_data
.iter()
.map(|(_, v)| v.len())
.max()
.unwrap_or(0);
let mut aggregated: FxHashMap<TypeIndex, AggregatedReceive> = let mut aggregated: FxHashMap<TypeIndex, AggregatedReceive> =
FxHashMap::with_capacity_and_hasher(max_type_len, Default::default()); FxHashMap::with_capacity_and_hasher(max_type_len, Default::default());
@@ -41,10 +41,7 @@ pub(crate) fn update_tx_counts(
.get_mut(&type_index) .get_mut(&type_index)
{ {
addr_data.tx_count += tx_count; addr_data.tx_count += tx_count;
} else if let Some(addr_data) = empty_cache } else if let Some(addr_data) = empty_cache.get_mut(addr_type).unwrap().get_mut(&type_index)
.get_mut(addr_type)
.unwrap()
.get_mut(&type_index)
{ {
addr_data.tx_count += tx_count; addr_data.tx_count += tx_count;
} }
@@ -90,9 +90,7 @@ pub(crate) fn process_inputs(
}; };
let items: Vec<_> = if input_count < 128 { let items: Vec<_> = if input_count < 128 {
(0..input_count) (0..input_count).map(map_fn).collect::<Result<Vec<_>>>()?
.map(map_fn)
.collect::<Result<Vec<_>>>()?
} else { } else {
(0..input_count) (0..input_count)
.into_par_iter() .into_par_iter()
@@ -109,10 +107,9 @@ pub(crate) fn process_inputs(
Default::default(), Default::default(),
); );
let mut sent_data = HeightToAddrTypeToVec::with_capacity(estimated_unique_heights); let mut sent_data = HeightToAddrTypeToVec::with_capacity(estimated_unique_heights);
let mut addr_data = let mut addr_data = AddrTypeToTypeIndexMap::<WithAddrDataSource<FundedAddrData>>::with_capacity(
AddrTypeToTypeIndexMap::<WithAddrDataSource<FundedAddrData>>::with_capacity( estimated_per_type,
estimated_per_type, );
);
let mut tx_index_vecs = let mut tx_index_vecs =
AddrTypeToTypeIndexMap::<SmallVec<[TxIndex; 4]>>::with_capacity(estimated_per_type); AddrTypeToTypeIndexMap::<SmallVec<[TxIndex; 4]>>::with_capacity(estimated_per_type);
@@ -5,9 +5,7 @@ use rayon::prelude::*;
use smallvec::SmallVec; use smallvec::SmallVec;
use crate::distribution::{ use crate::distribution::{
addr::{ addr::{AddrTypeToTypeIndexMap, AddrTypeToVec, AddrsDataVecs, AnyAddrIndexesVecs},
AddrTypeToTypeIndexMap, AddrTypeToVec, AddrsDataVecs, AnyAddrIndexesVecs,
},
compute::{TxOutData, VecsReaders}, compute::{TxOutData, VecsReaders},
state::Transacted, state::Transacted,
}; };
@@ -79,9 +77,7 @@ pub(crate) fn process_outputs(
}; };
let items: Vec<_> = if output_count < 128 { let items: Vec<_> = if output_count < 128 {
(0..output_count) (0..output_count).map(map_fn).collect::<Result<Vec<_>>>()?
.map(map_fn)
.collect::<Result<Vec<_>>>()?
} else { } else {
(0..output_count) (0..output_count)
.into_par_iter() .into_par_iter()
@@ -93,10 +89,9 @@ pub(crate) fn process_outputs(
let estimated_per_type = (output_count / 8).max(8); let estimated_per_type = (output_count / 8).max(8);
let mut transacted = Transacted::default(); let mut transacted = Transacted::default();
let mut received_data = AddrTypeToVec::with_capacity(estimated_per_type); let mut received_data = AddrTypeToVec::with_capacity(estimated_per_type);
let mut addr_data = let mut addr_data = AddrTypeToTypeIndexMap::<WithAddrDataSource<FundedAddrData>>::with_capacity(
AddrTypeToTypeIndexMap::<WithAddrDataSource<FundedAddrData>>::with_capacity( estimated_per_type,
estimated_per_type, );
);
let mut tx_index_vecs = let mut tx_index_vecs =
AddrTypeToTypeIndexMap::<SmallVec<[TxIndex; 4]>>::with_capacity(estimated_per_type); AddrTypeToTypeIndexMap::<SmallVec<[TxIndex; 4]>>::with_capacity(estimated_per_type);
@@ -1,8 +1,6 @@
use std::path::Path; use std::path::Path;
use brk_cohort::{ use brk_cohort::{AddrGroups, AmountRange, Filter, Filtered, OverAmount, UnderAmount};
AddrGroups, AmountRange, OverAmount, UnderAmount, Filter, Filtered,
};
use brk_error::Result; use brk_error::Result;
use brk_traversable::Traversable; use brk_traversable::Traversable;
use brk_types::{Height, Indexes, StoredU64, Version}; use brk_types::{Height, Indexes, StoredU64, Version};
@@ -161,9 +161,7 @@ impl DynCohortVecs for AddrCohortVecs {
} }
if let Some(state) = self.state.as_ref() { if let Some(state) = self.state.as_ref() {
self.addr_count self.addr_count.height.push(state.addr_count.into());
.height
.push(state.addr_count.into());
self.metrics.supply.push_state(&state.inner); self.metrics.supply.push_state(&state.inner);
self.metrics.outputs.push_state(&state.inner); self.metrics.outputs.push_state(&state.inner);
self.metrics.activity.push_state(&state.inner); self.metrics.activity.push_state(&state.inner);
@@ -1,4 +1,4 @@
use brk_types::{CostBasisSnapshot, Cents, Height, Timestamp}; use brk_types::{Cents, CostBasisSnapshot, Height, Timestamp};
use vecdb::Rw; use vecdb::Rw;
use crate::distribution::state::Transacted; use crate::distribution::state::Transacted;
@@ -34,10 +34,16 @@ impl UTXOCohorts<Rw> {
.unwrap() .unwrap()
.receive_utxo_snapshot(&supply_state, &snapshot); .receive_utxo_snapshot(&supply_state, &snapshot);
if let Some(v) = self.epoch.mut_vec_from_height(height) { if let Some(v) = self.epoch.mut_vec_from_height(height) {
v.state.as_mut().unwrap().receive_utxo_snapshot(&supply_state, &snapshot); v.state
.as_mut()
.unwrap()
.receive_utxo_snapshot(&supply_state, &snapshot);
} }
if let Some(v) = self.class.mut_vec_from_timestamp(timestamp) { if let Some(v) = self.class.mut_vec_from_timestamp(timestamp) {
v.state.as_mut().unwrap().receive_utxo_snapshot(&supply_state, &snapshot); v.state
.as_mut()
.unwrap()
.receive_utxo_snapshot(&supply_state, &snapshot);
} }
// Update output type cohorts (skip types with no outputs this block) // Update output type cohorts (skip types with no outputs this block)
@@ -64,10 +64,16 @@ impl UTXOCohorts<Rw> {
.unwrap() .unwrap()
.send_utxo_precomputed(&sent.spendable_supply, &pre); .send_utxo_precomputed(&sent.spendable_supply, &pre);
if let Some(v) = self.epoch.mut_vec_from_height(receive_height) { if let Some(v) = self.epoch.mut_vec_from_height(receive_height) {
v.state.as_mut().unwrap().send_utxo_precomputed(&sent.spendable_supply, &pre); v.state
.as_mut()
.unwrap()
.send_utxo_precomputed(&sent.spendable_supply, &pre);
} }
if let Some(v) = self.class.mut_vec_from_timestamp(block_state.timestamp) { if let Some(v) = self.class.mut_vec_from_timestamp(block_state.timestamp) {
v.state.as_mut().unwrap().send_utxo_precomputed(&sent.spendable_supply, &pre); v.state
.as_mut()
.unwrap()
.send_utxo_precomputed(&sent.spendable_supply, &pre);
} }
} else if sent.spendable_supply.utxo_count > 0 { } else if sent.spendable_supply.utxo_count > 0 {
// Zero-value UTXOs: just subtract supply // Zero-value UTXOs: just subtract supply
@@ -67,9 +67,7 @@ impl UTXOCohorts<Rw> {
idx idx
} else { } else {
let mut idx = cached[boundary_idx]; let mut idx = cached[boundary_idx];
while idx < chain_state.len() while idx < chain_state.len() && *chain_state[idx].timestamp <= lower_timestamp {
&& *chain_state[idx].timestamp <= lower_timestamp
{
idx += 1; idx += 1;
} }
cached[boundary_idx] = idx; cached[boundary_idx] = idx;
@@ -84,8 +82,7 @@ impl UTXOCohorts<Rw> {
// Move supply from younger cohort to older cohort // Move supply from younger cohort to older cohort
for block_state in &chain_state[start_idx..end_idx] { for block_state in &chain_state[start_idx..end_idx] {
let snapshot = let snapshot = CostBasisSnapshot::from_utxo(block_state.price, &block_state.supply);
CostBasisSnapshot::from_utxo(block_state.price, &block_state.supply);
if let Some(state) = age_cohorts[boundary_idx].as_mut() { if let Some(state) = age_cohorts[boundary_idx].as_mut() {
state.decrement_snapshot(&snapshot); state.decrement_snapshot(&snapshot);
} }
@@ -3,7 +3,10 @@ use brk_error::Result;
use brk_types::{Cents, Height, Indexes, Version}; use brk_types::{Cents, Height, Indexes, Version};
use vecdb::{Exit, ReadableVec}; use vecdb::{Exit, ReadableVec};
use crate::{distribution::{cohorts::traits::DynCohortVecs, metrics::CoreCohortMetrics}, prices}; use crate::{
distribution::{cohorts::traits::DynCohortVecs, metrics::CoreCohortMetrics},
prices,
};
use super::UTXOCohortVecs; use super::UTXOCohortVecs;
@@ -45,12 +48,8 @@ impl DynCohortVecs for UTXOCohortVecs<CoreCohortMetrics> {
if let Some(state) = self.state.as_mut() { if let Some(state) = self.state.as_mut() {
state.apply_pending(); state.apply_pending();
let unrealized_state = state.compute_unrealized_state(height_price); let unrealized_state = state.compute_unrealized_state(height_price);
self.metrics self.metrics.unrealized.push_state(&unrealized_state);
.unrealized self.metrics.supply.push_profitability(&unrealized_state);
.push_state(&unrealized_state);
self.metrics
.supply
.push_profitability(&unrealized_state);
} }
} }
@@ -3,7 +3,9 @@ use brk_error::Result;
use brk_types::{Cents, Height, Indexes, Version}; use brk_types::{Cents, Height, Indexes, Version};
use vecdb::{Exit, ReadableVec}; use vecdb::{Exit, ReadableVec};
use crate::{distribution::cohorts::traits::DynCohortVecs, distribution::metrics::TypeCohortMetrics, prices}; use crate::{
distribution::cohorts::traits::DynCohortVecs, distribution::metrics::TypeCohortMetrics, prices,
};
use super::UTXOCohortVecs; use super::UTXOCohortVecs;
@@ -45,12 +47,8 @@ impl DynCohortVecs for UTXOCohortVecs<TypeCohortMetrics> {
if let Some(state) = self.state.as_mut() { if let Some(state) = self.state.as_mut() {
state.apply_pending(); state.apply_pending();
let unrealized_state = state.compute_unrealized_state(height_price); let unrealized_state = state.compute_unrealized_state(height_price);
self.metrics self.metrics.unrealized.push_state(&unrealized_state);
.unrealized self.metrics.supply.push_profitability(&unrealized_state);
.push_state(&unrealized_state);
self.metrics
.supply
.push_profitability(&unrealized_state);
} }
} }
@@ -7,7 +7,7 @@ use brk_types::{
use rayon::prelude::*; use rayon::prelude::*;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use tracing::{debug, info}; use tracing::{debug, info};
use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, VecIndex, WritableVec}; use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, VecIndex, WritableVec, unlikely};
use crate::{ use crate::{
distribution::{ distribution::{
@@ -144,42 +144,50 @@ pub(crate) fn process_blocks(
let first_p2a_vec = indexer let first_p2a_vec = indexer
.vecs .vecs
.addrs .addrs
.p2a.first_index .p2a
.first_index
.collect_range_at(start_usize, end_usize); .collect_range_at(start_usize, end_usize);
let first_p2pk33_vec = indexer let first_p2pk33_vec = indexer
.vecs .vecs
.addrs .addrs
.p2pk33.first_index .p2pk33
.first_index
.collect_range_at(start_usize, end_usize); .collect_range_at(start_usize, end_usize);
let first_p2pk65_vec = indexer let first_p2pk65_vec = indexer
.vecs .vecs
.addrs .addrs
.p2pk65.first_index .p2pk65
.first_index
.collect_range_at(start_usize, end_usize); .collect_range_at(start_usize, end_usize);
let first_p2pkh_vec = indexer let first_p2pkh_vec = indexer
.vecs .vecs
.addrs .addrs
.p2pkh.first_index .p2pkh
.first_index
.collect_range_at(start_usize, end_usize); .collect_range_at(start_usize, end_usize);
let first_p2sh_vec = indexer let first_p2sh_vec = indexer
.vecs .vecs
.addrs .addrs
.p2sh.first_index .p2sh
.first_index
.collect_range_at(start_usize, end_usize); .collect_range_at(start_usize, end_usize);
let first_p2tr_vec = indexer let first_p2tr_vec = indexer
.vecs .vecs
.addrs .addrs
.p2tr.first_index .p2tr
.first_index
.collect_range_at(start_usize, end_usize); .collect_range_at(start_usize, end_usize);
let first_p2wpkh_vec = indexer let first_p2wpkh_vec = indexer
.vecs .vecs
.addrs .addrs
.p2wpkh.first_index .p2wpkh
.first_index
.collect_range_at(start_usize, end_usize); .collect_range_at(start_usize, end_usize);
let first_p2wsh_vec = indexer let first_p2wsh_vec = indexer
.vecs .vecs
.addrs .addrs
.p2wsh.first_index .p2wsh
.first_index
.collect_range_at(start_usize, end_usize); .collect_range_at(start_usize, end_usize);
// Track running totals - recover from previous height if resuming // Track running totals - recover from previous height if resuming
@@ -187,10 +195,8 @@ pub(crate) fn process_blocks(
let (mut addr_counts, mut empty_addr_counts) = if starting_height > Height::ZERO { let (mut addr_counts, mut empty_addr_counts) = if starting_height > Height::ZERO {
let addr_counts = let addr_counts =
AddrTypeToAddrCount::from((&vecs.addrs.funded.by_addr_type, starting_height)); AddrTypeToAddrCount::from((&vecs.addrs.funded.by_addr_type, starting_height));
let empty_addr_counts = AddrTypeToAddrCount::from(( let empty_addr_counts =
&vecs.addrs.empty.by_addr_type, AddrTypeToAddrCount::from((&vecs.addrs.empty.by_addr_type, starting_height));
starting_height,
));
(addr_counts, empty_addr_counts) (addr_counts, empty_addr_counts)
} else { } else {
( (
@@ -237,7 +243,11 @@ pub(crate) fn process_blocks(
for height in starting_height.to_usize()..=last_height.to_usize() { for height in starting_height.to_usize()..=last_height.to_usize() {
let height = Height::from(height); let height = Height::from(height);
info!("Processing chain at {}...", height); if unlikely(height.is_multiple_of(100)) {
info!("Processing chain at {}...", height);
} else {
debug!("Processing chain at {}...", height);
}
// Get block metadata from pre-collected vecs // Get block metadata from pre-collected vecs
let offset = height.to_usize() - start_usize; let offset = height.to_usize() - start_usize;
@@ -274,12 +284,18 @@ pub(crate) fn process_blocks(
// processing closures so outputs and inputs collection overlap each other // processing closures so outputs and inputs collection overlap each other
// and tick-tock, instead of running sequentially before the join. // and tick-tock, instead of running sequentially before the join.
let (matured, oi_result) = rayon::join( let (matured, oi_result) = rayon::join(
|| vecs.utxo_cohorts.tick_tock_next_block(chain_state, timestamp), || {
vecs.utxo_cohorts
.tick_tock_next_block(chain_state, timestamp)
},
|| -> Result<_> { || -> Result<_> {
let (outputs_result, inputs_result) = rayon::join( let (outputs_result, inputs_result) = rayon::join(
|| { || {
let txout_index_to_tx_index = txout_to_tx_index_buf let txout_index_to_tx_index = txout_to_tx_index_buf.build(
.build(first_tx_index, tx_count, tx_index_to_output_count); first_tx_index,
tx_count,
tx_index_to_output_count,
);
let txout_data_vec = let txout_data_vec =
txout_iters.collect_block_outputs(first_txout_index, output_count); txout_iters.collect_block_outputs(first_txout_index, output_count);
process_outputs( process_outputs(
@@ -294,14 +310,21 @@ pub(crate) fn process_blocks(
}, },
|| -> Result<_> { || -> Result<_> {
if input_count > 1 { if input_count > 1 {
let txin_index_to_tx_index = txin_to_tx_index_buf let txin_index_to_tx_index = txin_to_tx_index_buf.build(
.build(first_tx_index, tx_count, tx_index_to_input_count); first_tx_index,
let (input_values, input_prev_heights, input_output_types, input_type_indexes) = tx_count,
txin_iters.collect_block_inputs( tx_index_to_input_count,
first_txin_index + 1, );
input_count - 1, let (
height, input_values,
); input_prev_heights,
input_output_types,
input_type_indexes,
) = txin_iters.collect_block_inputs(
first_txin_index + 1,
input_count - 1,
height,
);
process_inputs( process_inputs(
input_count - 1, input_count - 1,
&txin_index_to_tx_index[1..], &txin_index_to_tx_index[1..],
@@ -380,9 +403,9 @@ pub(crate) fn process_blocks(
blocks_old as u128 * u64::from(sent.spendable_supply.value) as u128 blocks_old as u128 * u64::from(sent.spendable_supply.value) as u128
}) })
.sum(); .sum();
vecs.coinblocks_destroyed.block.push( vecs.coinblocks_destroyed.block.push(StoredF64::from(
StoredF64::from(total_satblocks as f64 / Sats::ONE_BTC_U128 as f64), total_satblocks as f64 / Sats::ONE_BTC_U128 as f64,
); ));
} }
// Record maturation (sats crossing age boundaries) // Record maturation (sats crossing age boundaries)
@@ -451,9 +474,11 @@ pub(crate) fn process_blocks(
vecs.utxo_cohorts.update_fenwick_from_pending(); vecs.utxo_cohorts.update_fenwick_from_pending();
// Push to height-indexed vectors // Push to height-indexed vectors
vecs.addrs.funded vecs.addrs
.funded
.push_height(addr_counts.sum(), &addr_counts); .push_height(addr_counts.sum(), &addr_counts);
vecs.addrs.empty vecs.addrs
.empty
.push_height(empty_addr_counts.sum(), &empty_addr_counts); .push_height(empty_addr_counts.sum(), &empty_addr_counts);
vecs.addrs.activity.push_height(&activity_counts); vecs.addrs.activity.push_height(&activity_counts);
@@ -467,11 +492,8 @@ pub(crate) fn process_blocks(
block_price, block_price,
); );
vecs.utxo_cohorts.push_aggregate_percentiles( vecs.utxo_cohorts
block_price, .push_aggregate_percentiles(block_price, date_opt, &vecs.states_path)?;
date_opt,
&vecs.states_path,
)?;
// Periodic checkpoint flush // Periodic checkpoint flush
if height != last_height if height != last_height
@@ -534,20 +556,16 @@ fn push_cohort_states(
// Phase 1: push + unrealized (no reset yet — states still needed for aggregation) // Phase 1: push + unrealized (no reset yet — states still needed for aggregation)
rayon::join( rayon::join(
|| { || {
utxo_cohorts utxo_cohorts.par_iter_separate_mut().for_each(|v| {
.par_iter_separate_mut() v.push_state(height);
.for_each(|v| { v.push_unrealized_state(height_price);
v.push_state(height); })
v.push_unrealized_state(height_price);
})
}, },
|| { || {
addr_cohorts addr_cohorts.par_iter_separate_mut().for_each(|v| {
.par_iter_separate_mut() v.push_state(height);
.for_each(|v| { v.push_unrealized_state(height_price);
v.push_state(height); })
v.push_unrealized_state(height_price);
})
}, },
); );
@@ -116,11 +116,10 @@ impl<'a> TxInReaders<'a> {
current_height: Height, current_height: Height,
) -> (&[Sats], &[Height], &[OutputType], &[TypeIndex]) { ) -> (&[Sats], &[Height], &[OutputType], &[TypeIndex]) {
let end = first_txin_index + input_count; let end = first_txin_index + input_count;
self.txins.spent.value.collect_range_into_at( self.txins
first_txin_index, .spent
end, .value
&mut self.values_buf, .collect_range_into_at(first_txin_index, end, &mut self.values_buf);
);
self.indexer.vecs.inputs.outpoint.collect_range_into_at( self.indexer.vecs.inputs.outpoint.collect_range_into_at(
first_txin_index, first_txin_index,
end, end,
@@ -138,8 +137,8 @@ impl<'a> TxInReaders<'a> {
); );
self.prev_heights_buf.clear(); self.prev_heights_buf.clear();
self.prev_heights_buf.extend( self.prev_heights_buf
self.outpoints_buf.iter().map(|outpoint| { .extend(self.outpoints_buf.iter().map(|outpoint| {
if outpoint.is_coinbase() { if outpoint.is_coinbase() {
current_height current_height
} else { } else {
@@ -147,8 +146,7 @@ impl<'a> TxInReaders<'a> {
.get(outpoint.tx_index()) .get(outpoint.tx_index())
.unwrap_or(current_height) .unwrap_or(current_height)
} }
}), }));
);
( (
&self.values_buf, &self.values_buf,
@@ -166,10 +164,7 @@ pub struct VecsReaders {
} }
impl VecsReaders { impl VecsReaders {
pub(crate) fn new( pub(crate) fn new(any_addr_indexes: &AnyAddrIndexesVecs, addrs_data: &AddrsDataVecs) -> Self {
any_addr_indexes: &AnyAddrIndexesVecs,
addrs_data: &AddrsDataVecs,
) -> Self {
Self { Self {
addr_type_index_to_any_addr_index: ByAddrType { addr_type_index_to_any_addr_index: ByAddrType {
p2a: any_addr_indexes.p2a.create_reader(), p2a: any_addr_indexes.p2a.create_reader(),
@@ -185,10 +185,7 @@ fn rollback_states(
heights.insert(chain_height); heights.insert(chain_height);
let Ok(stamps) = addr_indexes_rollbacks else { let Ok(stamps) = addr_indexes_rollbacks else {
warn!( warn!("addr_indexes rollback failed: {:?}", addr_indexes_rollbacks);
"addr_indexes rollback failed: {:?}",
addr_indexes_rollbacks
);
return Height::ZERO; return Height::ZERO;
}; };
for (i, s) in stamps.iter().enumerate() { for (i, s) in stamps.iter().enumerate() {
@@ -5,7 +5,10 @@ use derive_more::{Deref, DerefMut};
use vecdb::{AnyStoredVec, AnyVec, Exit, Rw, StorageMode, WritableVec}; use vecdb::{AnyStoredVec, AnyVec, Exit, Rw, StorageMode, WritableVec};
use crate::{ use crate::{
distribution::{metrics::ImportConfig, state::{CohortState, CostBasisOps, RealizedOps}}, distribution::{
metrics::ImportConfig,
state::{CohortState, CostBasisOps, RealizedOps},
},
internal::{AmountPerBlockCumulativeRolling, PerBlockCumulativeRolling}, internal::{AmountPerBlockCumulativeRolling, PerBlockCumulativeRolling},
prices, prices,
}; };
@@ -46,19 +49,18 @@ impl ActivityCore {
} }
#[inline(always)] #[inline(always)]
pub(crate) fn push_state( pub(crate) fn push_state(&mut self, state: &CohortState<impl RealizedOps, impl CostBasisOps>) {
&mut self,
state: &CohortState<impl RealizedOps, impl CostBasisOps>,
) {
self.minimal.push_state(state); self.minimal.push_state(state);
self.coindays_destroyed.block.push( self.coindays_destroyed
StoredF64::from(Bitcoin::from(state.satdays_destroyed)), .block
); .push(StoredF64::from(Bitcoin::from(state.satdays_destroyed)));
self.transfer_volume_in_profit self.transfer_volume_in_profit
.block.sats .block
.sats
.push(state.realized.sent_in_profit()); .push(state.realized.sent_in_profit());
self.transfer_volume_in_loss self.transfer_volume_in_loss
.block.sats .block
.sats
.push(state.realized.sent_in_loss()); .push(state.realized.sent_in_loss());
} }
@@ -7,7 +7,10 @@ use vecdb::{AnyStoredVec, Exit, ReadableCloneableVec, Rw, StorageMode};
use crate::internal::{Identity, LazyPerBlock, PerBlock, Windows}; use crate::internal::{Identity, LazyPerBlock, PerBlock, Windows};
use crate::{ use crate::{
distribution::{metrics::ImportConfig, state::{CohortState, CostBasisOps, RealizedOps}}, distribution::{
metrics::ImportConfig,
state::{CohortState, CostBasisOps, RealizedOps},
},
prices, prices,
}; };
@@ -33,7 +36,12 @@ impl ActivityFull {
let coinyears_destroyed = LazyPerBlock::from_height_source::<Identity<StoredF64>>( let coinyears_destroyed = LazyPerBlock::from_height_source::<Identity<StoredF64>>(
&cfg.name("coinyears_destroyed"), &cfg.name("coinyears_destroyed"),
cfg.version + v1, cfg.version + v1,
inner.coindays_destroyed.sum._1y.height.read_only_boxed_clone(), inner
.coindays_destroyed
.sum
._1y
.height
.read_only_boxed_clone(),
cfg.indexes, cfg.indexes,
); );
@@ -89,7 +97,8 @@ impl ActivityFull {
starting_indexes: &Indexes, starting_indexes: &Indexes,
exit: &Exit, exit: &Exit,
) -> Result<()> { ) -> Result<()> {
self.inner.compute_rest_part1(prices, starting_indexes, exit)?; self.inner
.compute_rest_part1(prices, starting_indexes, exit)?;
for ((dormancy, cdd_sum), tv_sum) in self for ((dormancy, cdd_sum), tv_sum) in self
.dormancy .dormancy
@@ -4,7 +4,10 @@ use brk_types::{Indexes, Version};
use vecdb::{AnyStoredVec, AnyVec, Exit, Rw, StorageMode, WritableVec}; use vecdb::{AnyStoredVec, AnyVec, Exit, Rw, StorageMode, WritableVec};
use crate::{ use crate::{
distribution::{metrics::ImportConfig, state::{CohortState, CostBasisOps, RealizedOps}}, distribution::{
metrics::ImportConfig,
state::{CohortState, CostBasisOps, RealizedOps},
},
internal::AmountPerBlockCumulativeRolling, internal::AmountPerBlockCumulativeRolling,
prices, prices,
}; };
@@ -23,16 +26,11 @@ impl ActivityMinimal {
} }
pub(crate) fn min_len(&self) -> usize { pub(crate) fn min_len(&self) -> usize {
self.transfer_volume self.transfer_volume.block.sats.len()
.block.sats
.len()
} }
#[inline(always)] #[inline(always)]
pub(crate) fn push_state( pub(crate) fn push_state(&mut self, state: &CohortState<impl RealizedOps, impl CostBasisOps>) {
&mut self,
state: &CohortState<impl RealizedOps, impl CostBasisOps>,
) {
self.transfer_volume.block.sats.push(state.sent); self.transfer_volume.block.sats.push(state.sent);
} }
@@ -19,10 +19,7 @@ pub trait ActivityLike: Send + Sync {
fn as_core(&self) -> &ActivityCore; fn as_core(&self) -> &ActivityCore;
fn as_core_mut(&mut self) -> &mut ActivityCore; fn as_core_mut(&mut self) -> &mut ActivityCore;
fn min_len(&self) -> usize; fn min_len(&self) -> usize;
fn push_state<R: RealizedOps>( fn push_state<R: RealizedOps>(&mut self, state: &CohortState<R, impl CostBasisOps>);
&mut self,
state: &CohortState<R, impl CostBasisOps>,
);
fn validate_computed_versions(&mut self, base_version: Version) -> Result<()>; fn validate_computed_versions(&mut self, base_version: Version) -> Result<()>;
fn compute_from_stateful( fn compute_from_stateful(
&mut self, &mut self,
@@ -39,37 +36,69 @@ pub trait ActivityLike: Send + Sync {
} }
impl ActivityLike for ActivityCore { impl ActivityLike for ActivityCore {
fn as_core(&self) -> &ActivityCore { self } fn as_core(&self) -> &ActivityCore {
fn as_core_mut(&mut self) -> &mut ActivityCore { self } self
fn min_len(&self) -> usize { self.min_len() } }
fn as_core_mut(&mut self) -> &mut ActivityCore {
self
}
fn min_len(&self) -> usize {
self.min_len()
}
fn push_state<R: RealizedOps>(&mut self, state: &CohortState<R, impl CostBasisOps>) { fn push_state<R: RealizedOps>(&mut self, state: &CohortState<R, impl CostBasisOps>) {
self.push_state(state); self.push_state(state);
} }
fn validate_computed_versions(&mut self, base_version: Version) -> Result<()> { fn validate_computed_versions(&mut self, base_version: Version) -> Result<()> {
self.validate_computed_versions(base_version) self.validate_computed_versions(base_version)
} }
fn compute_from_stateful(&mut self, starting_indexes: &Indexes, others: &[&ActivityCore], exit: &Exit) -> Result<()> { fn compute_from_stateful(
&mut self,
starting_indexes: &Indexes,
others: &[&ActivityCore],
exit: &Exit,
) -> Result<()> {
self.compute_from_stateful(starting_indexes, others, exit) self.compute_from_stateful(starting_indexes, others, exit)
} }
fn compute_rest_part1(&mut self, prices: &prices::Vecs, starting_indexes: &Indexes, exit: &Exit) -> Result<()> { fn compute_rest_part1(
&mut self,
prices: &prices::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.compute_rest_part1(prices, starting_indexes, exit) self.compute_rest_part1(prices, starting_indexes, exit)
} }
} }
impl ActivityLike for ActivityFull { impl ActivityLike for ActivityFull {
fn as_core(&self) -> &ActivityCore { &self.inner } fn as_core(&self) -> &ActivityCore {
fn as_core_mut(&mut self) -> &mut ActivityCore { &mut self.inner } &self.inner
fn min_len(&self) -> usize { self.full_min_len() } }
fn as_core_mut(&mut self) -> &mut ActivityCore {
&mut self.inner
}
fn min_len(&self) -> usize {
self.full_min_len()
}
fn push_state<R: RealizedOps>(&mut self, state: &CohortState<R, impl CostBasisOps>) { fn push_state<R: RealizedOps>(&mut self, state: &CohortState<R, impl CostBasisOps>) {
self.full_push_state(state); self.full_push_state(state);
} }
fn validate_computed_versions(&mut self, base_version: Version) -> Result<()> { fn validate_computed_versions(&mut self, base_version: Version) -> Result<()> {
self.inner.validate_computed_versions(base_version) self.inner.validate_computed_versions(base_version)
} }
fn compute_from_stateful(&mut self, starting_indexes: &Indexes, others: &[&ActivityCore], exit: &Exit) -> Result<()> { fn compute_from_stateful(
&mut self,
starting_indexes: &Indexes,
others: &[&ActivityCore],
exit: &Exit,
) -> Result<()> {
self.compute_from_stateful(starting_indexes, others, exit) self.compute_from_stateful(starting_indexes, others, exit)
} }
fn compute_rest_part1(&mut self, prices: &prices::Vecs, starting_indexes: &Indexes, exit: &Exit) -> Result<()> { fn compute_rest_part1(
&mut self,
prices: &prices::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.compute_rest_part1(prices, starting_indexes, exit) self.compute_rest_part1(prices, starting_indexes, exit)
} }
} }
@@ -1,9 +1,7 @@
use brk_cohort::Filter; use brk_cohort::Filter;
use brk_error::Result; use brk_error::Result;
use brk_traversable::Traversable; use brk_traversable::Traversable;
use brk_types::{ use brk_types::{Cents, Dollars, Height, Indexes, Version};
Cents, Dollars, Height, Indexes, Version,
};
use vecdb::AnyStoredVec; use vecdb::AnyStoredVec;
use vecdb::{Exit, ReadOnlyClone, ReadableVec, Rw, StorageMode}; use vecdb::{Exit, ReadOnlyClone, ReadableVec, Rw, StorageMode};
@@ -121,7 +119,7 @@ impl AllCohortMetrics {
self.unrealized.compute( self.unrealized.compute(
starting_indexes.height, starting_indexes.height,
&prices.spot.cents.height, &prices.cached_spot_cents,
&self.realized.price.cents.height, &self.realized.price.cents.height,
exit, exit,
)?; )?;
@@ -136,15 +134,12 @@ impl AllCohortMetrics {
)?; )?;
let all_utxo_count = self.outputs.unspent_count.height.read_only_clone(); let all_utxo_count = self.outputs.unspent_count.height.read_only_clone();
self.outputs.compute_part2( self.outputs
starting_indexes.height, .compute_part2(starting_indexes.height, &all_utxo_count, exit)?;
&all_utxo_count,
exit,
)?;
self.cost_basis.compute_prices( self.cost_basis.compute_prices(
starting_indexes, starting_indexes,
&prices.spot.cents.height, &prices.cached_spot_cents,
&self.unrealized.invested_capital.in_profit.cents.height, &self.unrealized.invested_capital.in_profit.cents.height,
&self.unrealized.invested_capital.in_loss.cents.height, &self.unrealized.invested_capital.in_loss.cents.height,
&self.supply.in_profit.sats.height, &self.supply.in_profit.sats.height,
@@ -154,11 +149,8 @@ impl AllCohortMetrics {
exit, exit,
)?; )?;
self.unrealized.compute_sentiment( self.unrealized
starting_indexes, .compute_sentiment(starting_indexes, &prices.cached_spot_cents, exit)?;
&prices.spot.cents.height,
exit,
)?;
self.relative.compute( self.relative.compute(
starting_indexes.height, starting_indexes.height,
@@ -82,21 +82,17 @@ impl BasicCohortMetrics {
self.unrealized.compute( self.unrealized.compute(
starting_indexes.height, starting_indexes.height,
&prices.spot.cents.height, &prices.cached_spot_cents,
&self.realized.price.cents.height, &self.realized.price.cents.height,
exit, exit,
)?; )?;
self.relative.compute( self.relative
starting_indexes.height, .compute(starting_indexes.height, &self.supply, all_supply_sats, exit)?;
&self.supply,
all_supply_sats,
exit,
)?;
self.outputs.compute_part2(starting_indexes.height, all_utxo_count, exit)?; self.outputs
.compute_part2(starting_indexes.height, all_utxo_count, exit)?;
Ok(()) Ok(())
} }
} }
@@ -92,7 +92,10 @@ impl CoreCohortMetrics {
)?; )?;
self.unrealized.compute_from_stateful( self.unrealized.compute_from_stateful(
starting_indexes, starting_indexes,
&others.iter().map(|v| v.unrealized_core()).collect::<Vec<_>>(), &others
.iter()
.map(|v| v.unrealized_core())
.collect::<Vec<_>>(),
exit, exit,
)?; )?;
@@ -105,16 +108,14 @@ impl CoreCohortMetrics {
starting_indexes: &Indexes, starting_indexes: &Indexes,
exit: &Exit, exit: &Exit,
) -> Result<()> { ) -> Result<()> {
self.supply self.supply.compute(prices, starting_indexes.height, exit)?;
.compute(prices, starting_indexes.height, exit)?;
self.outputs.compute_rest(starting_indexes.height, exit)?; self.outputs.compute_rest(starting_indexes.height, exit)?;
self.activity self.activity
.compute_rest_part1(prices, starting_indexes, exit)?; .compute_rest_part1(prices, starting_indexes, exit)?;
self.realized self.realized.compute_rest_part1(starting_indexes, exit)?;
.compute_rest_part1(starting_indexes, exit)?;
self.unrealized.compute_rest(starting_indexes, exit)?; self.unrealized.compute_rest(starting_indexes, exit)?;
@@ -139,19 +140,16 @@ impl CoreCohortMetrics {
self.unrealized.compute( self.unrealized.compute(
starting_indexes.height, starting_indexes.height,
&prices.spot.cents.height, &prices.cached_spot_cents,
&self.realized.price.cents.height, &self.realized.price.cents.height,
exit, exit,
)?; )?;
self.relative.compute( self.relative
starting_indexes.height, .compute(starting_indexes.height, &self.supply, all_supply_sats, exit)?;
&self.supply,
all_supply_sats,
exit,
)?;
self.outputs.compute_part2(starting_indexes.height, all_utxo_count, exit)?; self.outputs
.compute_part2(starting_indexes.height, all_utxo_count, exit)?;
Ok(()) Ok(())
} }
@@ -108,14 +108,14 @@ impl ExtendedCohortMetrics {
self.unrealized.compute( self.unrealized.compute(
starting_indexes.height, starting_indexes.height,
&prices.spot.cents.height, &prices.cached_spot_cents,
&self.realized.price.cents.height, &self.realized.price.cents.height,
exit, exit,
)?; )?;
self.cost_basis.compute_prices( self.cost_basis.compute_prices(
starting_indexes, starting_indexes,
&prices.spot.cents.height, &prices.cached_spot_cents,
&self.unrealized.invested_capital.in_profit.cents.height, &self.unrealized.invested_capital.in_profit.cents.height,
&self.unrealized.invested_capital.in_loss.cents.height, &self.unrealized.invested_capital.in_loss.cents.height,
&self.supply.in_profit.sats.height, &self.supply.in_profit.sats.height,
@@ -126,7 +126,7 @@ impl ExtendedCohortMetrics {
)?; )?;
self.unrealized self.unrealized
.compute_sentiment(starting_indexes, &prices.spot.cents.height, exit)?; .compute_sentiment(starting_indexes, &prices.cached_spot_cents, exit)?;
self.relative.compute( self.relative.compute(
starting_indexes.height, starting_indexes.height,
@@ -104,8 +104,7 @@ impl MinimalCohortMetrics {
self.outputs.compute_rest(starting_indexes.height, exit)?; self.outputs.compute_rest(starting_indexes.height, exit)?;
self.activity self.activity
.compute_rest_part1(prices, starting_indexes, exit)?; .compute_rest_part1(prices, starting_indexes, exit)?;
self.realized self.realized.compute_rest_part1(starting_indexes, exit)?;
.compute_rest_part1(starting_indexes, exit)?;
Ok(()) Ok(())
} }
@@ -125,12 +124,13 @@ impl MinimalCohortMetrics {
self.unrealized.compute( self.unrealized.compute(
starting_indexes.height, starting_indexes.height,
&prices.spot.cents.height, &prices.cached_spot_cents,
&self.realized.price.cents.height, &self.realized.price.cents.height,
exit, exit,
)?; )?;
self.outputs.compute_part2(starting_indexes.height, all_utxo_count, exit)?; self.outputs
.compute_part2(starting_indexes.height, all_utxo_count, exit)?;
Ok(()) Ok(())
} }
@@ -66,8 +66,7 @@ impl TypeCohortMetrics {
self.outputs.compute_rest(starting_indexes.height, exit)?; self.outputs.compute_rest(starting_indexes.height, exit)?;
self.activity self.activity
.compute_rest_part1(prices, starting_indexes, exit)?; .compute_rest_part1(prices, starting_indexes, exit)?;
self.realized self.realized.compute_rest_part1(starting_indexes, exit)?;
.compute_rest_part1(starting_indexes, exit)?;
Ok(()) Ok(())
} }
@@ -87,12 +86,13 @@ impl TypeCohortMetrics {
self.unrealized.compute( self.unrealized.compute(
starting_indexes.height, starting_indexes.height,
&prices.spot.cents.height, &prices.cached_spot_cents,
&self.realized.price.cents.height, &self.realized.price.cents.height,
exit, exit,
)?; )?;
self.outputs.compute_part2(starting_indexes.height, all_utxo_count, exit)?; self.outputs
.compute_part2(starting_indexes.height, all_utxo_count, exit)?;
Ok(()) Ok(())
} }
@@ -4,9 +4,7 @@ use brk_types::CentsSquaredSats;
use brk_types::{BasisPoints16, Cents, Height, Indexes, Sats, Version}; use brk_types::{BasisPoints16, Cents, Height, Indexes, Sats, Version};
use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, Rw, StorageMode, WritableVec}; use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, Rw, StorageMode, WritableVec};
use crate::internal::{ use crate::internal::{PERCENTILES_LEN, PerBlock, PercentPerBlock, PercentilesVecs, Price};
PERCENTILES_LEN, PerBlock, PercentPerBlock, PercentilesVecs, Price,
};
use super::ImportConfig; use super::ImportConfig;
@@ -33,12 +31,32 @@ impl CostBasis {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> { pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
Ok(Self { Ok(Self {
in_profit: CostBasisSide { in_profit: CostBasisSide {
per_coin: Price::forced_import(cfg.db, &cfg.name("cost_basis_in_profit_per_coin"), cfg.version + Version::ONE, cfg.indexes)?, per_coin: Price::forced_import(
per_dollar: Price::forced_import(cfg.db, &cfg.name("cost_basis_in_profit_per_dollar"), cfg.version + Version::ONE, cfg.indexes)?, cfg.db,
&cfg.name("cost_basis_in_profit_per_coin"),
cfg.version + Version::ONE,
cfg.indexes,
)?,
per_dollar: Price::forced_import(
cfg.db,
&cfg.name("cost_basis_in_profit_per_dollar"),
cfg.version + Version::ONE,
cfg.indexes,
)?,
}, },
in_loss: CostBasisSide { in_loss: CostBasisSide {
per_coin: Price::forced_import(cfg.db, &cfg.name("cost_basis_in_loss_per_coin"), cfg.version + Version::ONE, cfg.indexes)?, per_coin: Price::forced_import(
per_dollar: Price::forced_import(cfg.db, &cfg.name("cost_basis_in_loss_per_dollar"), cfg.version + Version::ONE, cfg.indexes)?, cfg.db,
&cfg.name("cost_basis_in_loss_per_coin"),
cfg.version + Version::ONE,
cfg.indexes,
)?,
per_dollar: Price::forced_import(
cfg.db,
&cfg.name("cost_basis_in_loss_per_dollar"),
cfg.version + Version::ONE,
cfg.indexes,
)?,
}, },
min: cfg.import("cost_basis_min", Version::ZERO)?, min: cfg.import("cost_basis_min", Version::ZERO)?,
max: cfg.import("cost_basis_max", Version::ZERO)?, max: cfg.import("cost_basis_max", Version::ZERO)?,
@@ -51,7 +51,12 @@ macro_rules! impl_cohort_accessors {
fn unrealized_mut(&mut self) -> &mut Self::UnrealizedVecs { fn unrealized_mut(&mut self) -> &mut Self::UnrealizedVecs {
&mut self.unrealized &mut self.unrealized
} }
fn supply_and_unrealized_mut(&mut self) -> (&$crate::distribution::metrics::SupplyCore, &mut Self::UnrealizedVecs) { fn supply_and_unrealized_mut(
&mut self,
) -> (
&$crate::distribution::metrics::SupplyCore,
&mut Self::UnrealizedVecs,
) {
(&*self.supply, &mut self.unrealized) (&*self.supply, &mut self.unrealized)
} }
}; };
@@ -94,7 +99,12 @@ macro_rules! impl_cohort_accessors_inner {
fn unrealized_mut(&mut self) -> &mut Self::UnrealizedVecs { fn unrealized_mut(&mut self) -> &mut Self::UnrealizedVecs {
&mut self.inner.unrealized &mut self.inner.unrealized
} }
fn supply_and_unrealized_mut(&mut self) -> (&$crate::distribution::metrics::SupplyCore, &mut Self::UnrealizedVecs) { fn supply_and_unrealized_mut(
&mut self,
) -> (
&$crate::distribution::metrics::SupplyCore,
&mut Self::UnrealizedVecs,
) {
(&*self.inner.supply, &mut self.inner.unrealized) (&*self.inner.supply, &mut self.inner.unrealized)
} }
}; };
@@ -125,8 +135,7 @@ pub use realized::{
pub use relative::{RelativeForAll, RelativeToAll, RelativeWithExtended}; pub use relative::{RelativeForAll, RelativeToAll, RelativeWithExtended};
pub use supply::{SupplyBase, SupplyCore}; pub use supply::{SupplyBase, SupplyCore};
pub use unrealized::{ pub use unrealized::{
UnrealizedBasic, UnrealizedCore, UnrealizedFull, UnrealizedLike, UnrealizedBasic, UnrealizedCore, UnrealizedFull, UnrealizedLike, UnrealizedMinimal,
UnrealizedMinimal,
}; };
use brk_cohort::Filter; use brk_cohort::Filter;
@@ -250,10 +259,7 @@ pub trait CohortMetricsBase:
.min(self.unrealized().min_stateful_len()) .min(self.unrealized().min_stateful_len())
} }
fn push_state( fn push_state(&mut self, state: &CohortState<RealizedState, CostBasisData<WithCapital>>) {
&mut self,
state: &CohortState<RealizedState, CostBasisData<WithCapital>>,
) {
self.supply_mut().push_state(state); self.supply_mut().push_state(state);
self.outputs_mut().push_state(state); self.outputs_mut().push_state(state);
self.activity_mut().push_state(state); self.activity_mut().push_state(state);
@@ -6,7 +6,9 @@ use vecdb::{AnyStoredVec, AnyVec, Database, Exit, Rw, StorageMode, WritableVec};
use crate::{ use crate::{
indexes, indexes,
internal::{AmountPerBlock, AmountPerBlockWithDeltas, CachedWindowStarts, PerBlock, RatioPerBlock}, internal::{
AmountPerBlock, AmountPerBlockWithDeltas, CachedWindowStarts, PerBlock, RatioPerBlock,
},
prices, prices,
}; };
@@ -124,7 +126,7 @@ impl ProfitabilityBucket {
self.unrealized_pnl.all.height.compute_transform3( self.unrealized_pnl.all.height.compute_transform3(
max_from, max_from,
&prices.spot.cents.height, &prices.cached_spot_cents,
&self.realized_cap.all.height, &self.realized_cap.all.height,
&self.supply.all.sats.height, &self.supply.all.sats.height,
|(i, spot, cap, supply, ..)| { |(i, spot, cap, supply, ..)| {
@@ -137,7 +139,7 @@ impl ProfitabilityBucket {
)?; )?;
self.unrealized_pnl.sth.height.compute_transform3( self.unrealized_pnl.sth.height.compute_transform3(
max_from, max_from,
&prices.spot.cents.height, &prices.cached_spot_cents,
&self.realized_cap.sth.height, &self.realized_cap.sth.height,
&self.supply.sth.sats.height, &self.supply.sth.sats.height,
|(i, spot, cap, supply, ..)| { |(i, spot, cap, supply, ..)| {
@@ -151,7 +153,7 @@ impl ProfitabilityBucket {
self.nupl.bps.height.compute_transform3( self.nupl.bps.height.compute_transform3(
max_from, max_from,
&prices.spot.cents.height, &prices.cached_spot_cents,
&self.realized_cap.all.height, &self.realized_cap.all.height,
&self.supply.all.sats.height, &self.supply.all.sats.height,
|(i, spot, cap_dollars, supply_sats, ..)| { |(i, spot, cap_dollars, supply_sats, ..)| {
@@ -183,22 +185,34 @@ impl ProfitabilityBucket {
self.supply.all.sats.height.compute_sum_of_others( self.supply.all.sats.height.compute_sum_of_others(
max_from, max_from,
&sources.iter().map(|s| &s.supply.all.sats.height).collect::<Vec<_>>(), &sources
.iter()
.map(|s| &s.supply.all.sats.height)
.collect::<Vec<_>>(),
exit, exit,
)?; )?;
self.supply.sth.sats.height.compute_sum_of_others( self.supply.sth.sats.height.compute_sum_of_others(
max_from, max_from,
&sources.iter().map(|s| &s.supply.sth.sats.height).collect::<Vec<_>>(), &sources
.iter()
.map(|s| &s.supply.sth.sats.height)
.collect::<Vec<_>>(),
exit, exit,
)?; )?;
self.realized_cap.all.height.compute_sum_of_others( self.realized_cap.all.height.compute_sum_of_others(
max_from, max_from,
&sources.iter().map(|s| &s.realized_cap.all.height).collect::<Vec<_>>(), &sources
.iter()
.map(|s| &s.realized_cap.all.height)
.collect::<Vec<_>>(),
exit, exit,
)?; )?;
self.realized_cap.sth.height.compute_sum_of_others( self.realized_cap.sth.height.compute_sum_of_others(
max_from, max_from,
&sources.iter().map(|s| &s.realized_cap.sth.height).collect::<Vec<_>>(), &sources
.iter()
.map(|s| &s.realized_cap.sth.height)
.collect::<Vec<_>>(),
exit, exit,
)?; )?;
@@ -259,7 +273,7 @@ impl ProfitabilityMetrics {
ProfitabilityBucket::forced_import(db, name, version, indexes, cached_starts) ProfitabilityBucket::forced_import(db, name, version, indexes, cached_starts)
})?; })?;
let aggregate_version = version + Version::ONE; let aggregate_version = version + Version::TWO;
let profit = Profit::try_new(|name| { let profit = Profit::try_new(|name| {
ProfitabilityBucket::forced_import(db, name, aggregate_version, indexes, cached_starts) ProfitabilityBucket::forced_import(db, name, aggregate_version, indexes, cached_starts)
@@ -1,6 +1,8 @@
use brk_error::Result; use brk_error::Result;
use brk_traversable::Traversable; use brk_traversable::Traversable;
use brk_types::{BasisPointsSigned32, Bitcoin, Cents, CentsSigned, Dollars, Height, Indexes, StoredF64, Version}; use brk_types::{
BasisPointsSigned32, Bitcoin, Cents, CentsSigned, Dollars, Height, Indexes, StoredF64, Version,
};
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
use vecdb::{ use vecdb::{
AnyStoredVec, Exit, LazyVecFrom1, ReadableCloneableVec, ReadableVec, Rw, StorageMode, AnyStoredVec, Exit, LazyVecFrom1, ReadableCloneableVec, ReadableVec, Rw, StorageMode,
@@ -42,7 +44,8 @@ pub struct RealizedCore<M: StorageMode = Rw> {
#[traversable(wrap = "loss", rename = "negative")] #[traversable(wrap = "loss", rename = "negative")]
pub neg_loss: NegRealizedLoss, pub neg_loss: NegRealizedLoss,
pub net_pnl: FiatPerBlockCumulativeWithSumsAndDeltas<CentsSigned, CentsSigned, BasisPointsSigned32, M>, pub net_pnl:
FiatPerBlockCumulativeWithSumsAndDeltas<CentsSigned, CentsSigned, BasisPointsSigned32, M>,
pub sopr: RealizedSoprCore<M>, pub sopr: RealizedSoprCore<M>,
} }
@@ -107,7 +110,10 @@ impl RealizedCore {
#[inline(always)] #[inline(always)]
pub(crate) fn push_state(&mut self, state: &CohortState<impl RealizedOps, impl CostBasisOps>) { pub(crate) fn push_state(&mut self, state: &CohortState<impl RealizedOps, impl CostBasisOps>) {
self.minimal.push_state(state); self.minimal.push_state(state);
self.sopr.value_destroyed.block.push(state.realized.value_destroyed()); self.sopr
.value_destroyed
.block
.push(state.realized.value_destroyed());
} }
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> { pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
@@ -135,8 +141,7 @@ impl RealizedCore {
starting_indexes: &Indexes, starting_indexes: &Indexes,
exit: &Exit, exit: &Exit,
) -> Result<()> { ) -> Result<()> {
self.minimal self.minimal.compute_rest_part1(starting_indexes, exit)?;
.compute_rest_part1(starting_indexes, exit)?;
self.sopr self.sopr
.value_destroyed .value_destroyed
@@ -169,8 +174,7 @@ impl RealizedCore {
self.minimal self.minimal
.compute_rest_part2(prices, starting_indexes, height_to_supply, exit)?; .compute_rest_part2(prices, starting_indexes, height_to_supply, exit)?;
self.net_pnl self.net_pnl.compute_rest(starting_indexes.height, exit)?;
.compute_rest(starting_indexes.height, exit)?;
self.sopr self.sopr
.ratio .ratio
@@ -178,7 +178,8 @@ impl RealizedFull {
.push(state.realized.investor_cap_raw()); .push(state.realized.investor_cap_raw());
self.peak_regret self.peak_regret
.value .value
.block.cents .block
.cents
.push(state.realized.peak_regret()); .push(state.realized.peak_regret());
} }
@@ -218,10 +219,7 @@ impl RealizedFull {
}; };
self.investor.price.cents.height.push(investor_price); self.investor.price.cents.height.push(investor_price);
self.peak_regret self.peak_regret.value.block.cents.push(accum.peak_regret());
.value
.block.cents
.push(accum.peak_regret());
} }
pub(crate) fn compute_rest_part1( pub(crate) fn compute_rest_part1(
@@ -1,18 +1,16 @@
use brk_error::Result; use brk_error::Result;
use brk_traversable::Traversable; use brk_traversable::Traversable;
use brk_types::{ use brk_types::{
BasisPoints32, BasisPointsSigned32, Bitcoin, Cents, CentsSigned, Height, Indexes, Sats, StoredF32, BasisPoints32, BasisPointsSigned32, Bitcoin, Cents, CentsSigned, Height, Indexes, Sats,
Version, StoredF32, Version,
};
use vecdb::{
AnyStoredVec, AnyVec, Exit, ReadableVec, Rw, StorageMode, WritableVec,
}; };
use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, Rw, StorageMode, WritableVec};
use crate::{ use crate::{
distribution::state::{CohortState, CostBasisOps, RealizedOps}, distribution::state::{CohortState, CostBasisOps, RealizedOps},
internal::{ internal::{
FiatPerBlockCumulativeWithSums, FiatPerBlockCumulativeWithSums, FiatPerBlockWithDeltas, Identity, LazyPerBlock,
FiatPerBlockWithDeltas, Identity, LazyPerBlock, PriceWithRatioPerBlock, PriceWithRatioPerBlock,
}, },
prices, prices,
}; };
@@ -111,23 +109,24 @@ impl RealizedMinimal {
exit: &Exit, exit: &Exit,
) -> Result<()> { ) -> Result<()> {
let cap = &self.cap.cents.height; let cap = &self.cap.cents.height;
self.price.compute_all(prices, starting_indexes, exit, |v| { self.price
Ok(v.compute_transform2( .compute_all(prices, starting_indexes, exit, |v| {
starting_indexes.height, Ok(v.compute_transform2(
cap, starting_indexes.height,
height_to_supply, cap,
|(i, cap_cents, supply, ..)| { height_to_supply,
let cap = cap_cents.as_u128(); |(i, cap_cents, supply, ..)| {
let supply_sats = Sats::from(supply).as_u128(); let cap = cap_cents.as_u128();
if supply_sats == 0 { let supply_sats = Sats::from(supply).as_u128();
(i, Cents::ZERO) if supply_sats == 0 {
} else { (i, Cents::ZERO)
(i, Cents::from(cap * Sats::ONE_BTC_U128 / supply_sats)) } else {
} (i, Cents::from(cap * Sats::ONE_BTC_U128 / supply_sats))
}, }
exit, },
)?) exit,
})?; )?)
})?;
Ok(()) Ok(())
} }
@@ -3,8 +3,8 @@ mod core;
mod full; mod full;
mod minimal; mod minimal;
pub use adjusted::AdjustedSopr;
pub use self::core::RealizedCore; pub use self::core::RealizedCore;
pub use adjusted::AdjustedSopr;
pub use full::{RealizedFull, RealizedFullAccum}; pub use full::{RealizedFull, RealizedFullAccum};
pub use minimal::RealizedMinimal; pub use minimal::RealizedMinimal;
@@ -12,7 +12,7 @@ use brk_error::Result;
use brk_types::Indexes; use brk_types::Indexes;
use vecdb::Exit; use vecdb::Exit;
use crate::distribution::state::{WithCapital, CohortState, CostBasisData, RealizedState}; use crate::distribution::state::{CohortState, CostBasisData, RealizedState, WithCapital};
pub trait RealizedLike: Send + Sync { pub trait RealizedLike: Send + Sync {
fn as_core(&self) -> &RealizedCore; fn as_core(&self) -> &RealizedCore;
@@ -29,9 +29,15 @@ pub trait RealizedLike: Send + Sync {
} }
impl RealizedLike for RealizedCore { impl RealizedLike for RealizedCore {
fn as_core(&self) -> &RealizedCore { self } fn as_core(&self) -> &RealizedCore {
fn as_core_mut(&mut self) -> &mut RealizedCore { self } self
fn min_stateful_len(&self) -> usize { self.min_stateful_len() } }
fn as_core_mut(&mut self) -> &mut RealizedCore {
self
}
fn min_stateful_len(&self) -> usize {
self.min_stateful_len()
}
#[inline(always)] #[inline(always)]
fn push_state(&mut self, state: &CohortState<RealizedState, CostBasisData<WithCapital>>) { fn push_state(&mut self, state: &CohortState<RealizedState, CostBasisData<WithCapital>>) {
self.push_state(state) self.push_state(state)
@@ -39,15 +45,26 @@ impl RealizedLike for RealizedCore {
fn compute_rest_part1(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()> { fn compute_rest_part1(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()> {
self.compute_rest_part1(starting_indexes, exit) self.compute_rest_part1(starting_indexes, exit)
} }
fn compute_from_stateful(&mut self, starting_indexes: &Indexes, others: &[&RealizedCore], exit: &Exit) -> Result<()> { fn compute_from_stateful(
&mut self,
starting_indexes: &Indexes,
others: &[&RealizedCore],
exit: &Exit,
) -> Result<()> {
self.compute_from_stateful(starting_indexes, others, exit) self.compute_from_stateful(starting_indexes, others, exit)
} }
} }
impl RealizedLike for RealizedFull { impl RealizedLike for RealizedFull {
fn as_core(&self) -> &RealizedCore { &self.core } fn as_core(&self) -> &RealizedCore {
fn as_core_mut(&mut self) -> &mut RealizedCore { &mut self.core } &self.core
fn min_stateful_len(&self) -> usize { self.min_stateful_len() } }
fn as_core_mut(&mut self) -> &mut RealizedCore {
&mut self.core
}
fn min_stateful_len(&self) -> usize {
self.min_stateful_len()
}
#[inline(always)] #[inline(always)]
fn push_state(&mut self, state: &CohortState<RealizedState, CostBasisData<WithCapital>>) { fn push_state(&mut self, state: &CohortState<RealizedState, CostBasisData<WithCapital>>) {
self.push_state(state) self.push_state(state)
@@ -55,7 +72,12 @@ impl RealizedLike for RealizedFull {
fn compute_rest_part1(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()> { fn compute_rest_part1(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()> {
self.compute_rest_part1(starting_indexes, exit) self.compute_rest_part1(starting_indexes, exit)
} }
fn compute_from_stateful(&mut self, starting_indexes: &Indexes, others: &[&RealizedCore], exit: &Exit) -> Result<()> { fn compute_from_stateful(
&mut self,
starting_indexes: &Indexes,
others: &[&RealizedCore],
exit: &Exit,
) -> Result<()> {
self.compute_from_stateful(starting_indexes, others, exit) self.compute_from_stateful(starting_indexes, others, exit)
} }
} }
@@ -23,8 +23,7 @@ impl RelativeExtendedOwnMarketCap {
let v2 = Version::new(2); let v2 = Version::new(2);
Ok(Self { Ok(Self {
unrealized_profit_to_own_mcap: cfg unrealized_profit_to_own_mcap: cfg.import("unrealized_profit_to_own_mcap", v2)?,
.import("unrealized_profit_to_own_mcap", v2)?,
unrealized_loss_to_own_mcap: cfg unrealized_loss_to_own_mcap: cfg
.import("unrealized_loss_to_own_mcap", Version::new(3))?, .import("unrealized_loss_to_own_mcap", Version::new(3))?,
net_unrealized_pnl_to_own_mcap: cfg net_unrealized_pnl_to_own_mcap: cfg
@@ -16,7 +16,6 @@ pub struct RelativeExtendedOwnPnl<M: StorageMode = Rw> {
pub unrealized_loss_to_own_gross_pnl: PercentPerBlock<BasisPoints16, M>, pub unrealized_loss_to_own_gross_pnl: PercentPerBlock<BasisPoints16, M>,
#[traversable(wrap = "unrealized/net_pnl", rename = "to_own_gross_pnl")] #[traversable(wrap = "unrealized/net_pnl", rename = "to_own_gross_pnl")]
pub net_unrealized_pnl_to_own_gross_pnl: PercentPerBlock<BasisPointsSigned32, M>, pub net_unrealized_pnl_to_own_gross_pnl: PercentPerBlock<BasisPointsSigned32, M>,
} }
impl RelativeExtendedOwnPnl { impl RelativeExtendedOwnPnl {
@@ -26,8 +25,7 @@ impl RelativeExtendedOwnPnl {
Ok(Self { Ok(Self {
unrealized_profit_to_own_gross_pnl: cfg unrealized_profit_to_own_gross_pnl: cfg
.import("unrealized_profit_to_own_gross_pnl", v1)?, .import("unrealized_profit_to_own_gross_pnl", v1)?,
unrealized_loss_to_own_gross_pnl: cfg unrealized_loss_to_own_gross_pnl: cfg.import("unrealized_loss_to_own_gross_pnl", v1)?,
.import("unrealized_loss_to_own_gross_pnl", v1)?,
net_unrealized_pnl_to_own_gross_pnl: cfg net_unrealized_pnl_to_own_gross_pnl: cfg
.import("net_unrealized_pnl_to_own_gross_pnl", Version::new(3))?, .import("net_unrealized_pnl_to_own_gross_pnl", Version::new(3))?,
}) })
@@ -6,7 +6,7 @@ use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::distribution::metrics::{ImportConfig, SupplyCore, UnrealizedFull}; use crate::distribution::metrics::{ImportConfig, SupplyCore, UnrealizedFull};
use super::{RelativeFull, RelativeExtendedOwnPnl}; use super::{RelativeExtendedOwnPnl, RelativeFull};
/// Relative metrics for the "all" cohort (base + own_pnl, NO rel_to_all). /// Relative metrics for the "all" cohort (base + own_pnl, NO rel_to_all).
#[derive(Deref, DerefMut, Traversable)] #[derive(Deref, DerefMut, Traversable)]
@@ -35,15 +35,14 @@ impl RelativeForAll {
market_cap: &impl ReadableVec<Height, Dollars>, market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit, exit: &Exit,
) -> Result<()> { ) -> Result<()> {
self.base.compute( self.base
.compute(max_from, supply, &unrealized.inner.basic, market_cap, exit)?;
self.extended_own_pnl.compute(
max_from, max_from,
supply, &unrealized.inner,
&unrealized.inner.basic, &unrealized.gross_pnl.usd.height,
market_cap,
exit, exit,
)?; )?;
self.extended_own_pnl
.compute(max_from, &unrealized.inner, &unrealized.gross_pnl.usd.height, exit)?;
Ok(()) Ok(())
} }
} }
@@ -28,13 +28,10 @@ impl RelativeFull {
let v2 = Version::new(2); let v2 = Version::new(2);
Ok(Self { Ok(Self {
supply_in_profit_to_own: cfg supply_in_profit_to_own: cfg.import("supply_in_profit_to_own", v1)?,
.import("supply_in_profit_to_own", v1)?,
supply_in_loss_to_own: cfg.import("supply_in_loss_to_own", v1)?, supply_in_loss_to_own: cfg.import("supply_in_loss_to_own", v1)?,
unrealized_profit_to_mcap: cfg unrealized_profit_to_mcap: cfg.import("unrealized_profit_to_mcap", v2)?,
.import("unrealized_profit_to_mcap", v2)?, unrealized_loss_to_mcap: cfg.import("unrealized_loss_to_mcap", v2)?,
unrealized_loss_to_mcap: cfg
.import("unrealized_loss_to_mcap", v2)?,
}) })
} }
@@ -21,8 +21,7 @@ pub struct RelativeToAll<M: StorageMode = Rw> {
impl RelativeToAll { impl RelativeToAll {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> { pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
Ok(Self { Ok(Self {
supply_to_circulating: cfg supply_to_circulating: cfg.import("supply_to_circulating", Version::ONE)?,
.import("supply_to_circulating", Version::ONE)?,
supply_in_profit_to_circulating: cfg supply_in_profit_to_circulating: cfg
.import("supply_in_profit_to_circulating", Version::ONE)?, .import("supply_in_profit_to_circulating", Version::ONE)?,
supply_in_loss_to_circulating: cfg supply_in_loss_to_circulating: cfg
@@ -6,7 +6,7 @@ use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::distribution::metrics::{ImportConfig, SupplyCore, UnrealizedFull}; use crate::distribution::metrics::{ImportConfig, SupplyCore, UnrealizedFull};
use super::{RelativeFull, RelativeExtendedOwnMarketCap, RelativeExtendedOwnPnl, RelativeToAll}; use super::{RelativeExtendedOwnMarketCap, RelativeExtendedOwnPnl, RelativeFull, RelativeToAll};
/// Full extended relative metrics (base + rel_to_all + own_market_cap + own_pnl). /// Full extended relative metrics (base + rel_to_all + own_market_cap + own_pnl).
/// Used by: sth, lth cohorts. /// Used by: sth, lth cohorts.
@@ -45,23 +45,18 @@ impl RelativeWithExtended {
own_market_cap: &impl ReadableVec<Height, Dollars>, own_market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit, exit: &Exit,
) -> Result<()> { ) -> Result<()> {
self.base.compute( self.base
max_from, .compute(max_from, supply, &unrealized.inner.basic, market_cap, exit)?;
supply, self.rel_to_all
&unrealized.inner.basic, .compute(max_from, supply, all_supply_sats, exit)?;
market_cap,
exit,
)?;
self.rel_to_all.compute(
max_from,
supply,
all_supply_sats,
exit,
)?;
self.extended_own_market_cap self.extended_own_market_cap
.compute(max_from, &unrealized.inner, own_market_cap, exit)?; .compute(max_from, &unrealized.inner, own_market_cap, exit)?;
self.extended_own_pnl self.extended_own_pnl.compute(
.compute(max_from, &unrealized.inner, &unrealized.gross_pnl.usd.height, exit)?; max_from,
&unrealized.inner,
&unrealized.gross_pnl.usd.height,
exit,
)?;
Ok(()) Ok(())
} }
} }
@@ -3,12 +3,13 @@ use brk_traversable::Traversable;
use brk_types::{BasisPointsSigned32, Height, Indexes, Sats, SatsSigned, Version}; use brk_types::{BasisPointsSigned32, Height, Indexes, Sats, SatsSigned, Version};
use vecdb::{AnyStoredVec, AnyVec, Exit, Rw, StorageMode, WritableVec}; use vecdb::{AnyStoredVec, AnyVec, Exit, Rw, StorageMode, WritableVec};
use crate::{distribution::state::{CohortState, CostBasisOps, RealizedOps}, prices}; use crate::{
distribution::state::{CohortState, CostBasisOps, RealizedOps},
use crate::internal::{ prices,
AmountPerBlock, LazyRollingDeltasFromHeight,
}; };
use crate::internal::{AmountPerBlock, LazyRollingDeltasFromHeight};
use crate::distribution::metrics::ImportConfig; use crate::distribution::metrics::ImportConfig;
/// Base supply metrics: total supply only (2 stored vecs). /// Base supply metrics: total supply only (2 stored vecs).
@@ -1,5 +1,5 @@
mod base; mod base;
mod core; mod core;
pub use base::SupplyBase;
pub use self::core::SupplyCore; pub use self::core::SupplyCore;
pub use base::SupplyBase;
@@ -54,14 +54,8 @@ impl UnrealizedBasic {
#[inline(always)] #[inline(always)]
pub(crate) fn push_state(&mut self, state: &UnrealizedState) { pub(crate) fn push_state(&mut self, state: &UnrealizedState) {
self.profit self.profit.cents.height.push(state.unrealized_profit);
.cents self.loss.cents.height.push(state.unrealized_loss);
.height
.push(state.unrealized_profit);
self.loss
.cents
.height
.push(state.unrealized_loss);
} }
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> { pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
@@ -5,10 +5,7 @@ use derive_more::{Deref, DerefMut};
use vecdb::{AnyStoredVec, Exit, Rw, StorageMode}; use vecdb::{AnyStoredVec, Exit, Rw, StorageMode};
use crate::{ use crate::{
distribution::{ distribution::{metrics::ImportConfig, state::UnrealizedState},
metrics::ImportConfig,
state::UnrealizedState,
},
internal::{CentsSubtractToCentsSigned, FiatPerBlock}, internal::{CentsSubtractToCentsSigned, FiatPerBlock},
}; };
@@ -60,11 +57,7 @@ impl UnrealizedCore {
Ok(()) Ok(())
} }
pub(crate) fn compute_rest( pub(crate) fn compute_rest(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()> {
&mut self,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.net_pnl self.net_pnl
.cents .cents
.height .height

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