Compare commits

...

40 Commits

Author SHA1 Message Date
nym21 cae16227fd release: v0.3.1 2026-06-01 19:19:13 +02:00
nym21 dc2ca0ca27 docs: update generated docs 2026-06-01 19:18:42 +02:00
nym21 d161462137 deps: bumped 2026-06-01 18:10:24 +02:00
nym21 be20633945 heatmaps: part 23 2026-06-01 18:03:41 +02:00
nym21 2bbc535b58 heatmaps: part 22 2026-06-01 17:54:42 +02:00
nym21 88c38e74f9 heatmaps: part 21 2026-06-01 14:25:21 +02:00
nym21 a61b76a4a5 heatmaps: part 20 2026-06-01 13:31:00 +02:00
nym21 46b888337c heatmaps: part 19 2026-06-01 13:20:34 +02:00
nym21 4b49a04186 heatmaps: part 18 2026-06-01 13:03:45 +02:00
nym21 15b0cd2445 heatmaps: part 17 2026-06-01 13:03:39 +02:00
nym21 76720434d7 heatmaps: part 16 2026-06-01 12:19:32 +02:00
nym21 200cd1011e heatmaps: part 15 2026-06-01 12:04:44 +02:00
nym21 cb9f277d49 heatmaps: part 14 2026-06-01 12:01:24 +02:00
nym21 102933b406 heatmaps: part 13 2026-06-01 11:17:00 +02:00
nym21 e64ffac8d1 heatmaps: part 12 2026-06-01 10:56:58 +02:00
nym21 a94d31dfdf heatmaps: part 12 2026-06-01 10:30:44 +02:00
nym21 087a3b6fd6 heatmaps: part 11 2026-06-01 01:04:14 +02:00
nym21 7181d59966 heatmaps: part 10 2026-06-01 00:38:12 +02:00
nym21 3b7734a61a heatmaps: part 9 2026-05-31 23:35:19 +02:00
nym21 7860c5a8bd heatmaps: part 8 2026-05-31 18:57:23 +02:00
nym21 5df399d2f7 heatmaps: part 7 2026-05-31 12:05:48 +02:00
nym21 b2345db279 heatmaps: part 6 2026-05-31 01:38:50 +02:00
nym21 7e2fc8b455 heatmaps: part 5 2026-05-30 15:43:59 +02:00
nym21 c1ff095e4b heatmaps: part 5 2026-05-30 13:16:22 +02:00
nym21 cc8fde59e8 heatmaps: part 4 2026-05-30 11:36:49 +02:00
nym21 e43b53b429 heatmaps: part 3 2026-05-30 11:36:46 +02:00
nym21 6938204a24 heatmaps: part 2 2026-05-29 23:17:39 +02:00
nym21 52883bbdba heatmaps: part 1 2026-05-28 21:58:54 +02:00
nym21 100495fdba deps: bumped 2026-05-27 19:41:37 +02:00
nym21 0ad5be6974 global: snap 2026-05-26 15:33:22 +02:00
nym21 66037c862f global: added support for oracle histograms 2026-05-25 16:44:09 +02:00
nym21 ee20175cbf oracle: cleanup + split lib.rs 2026-05-24 18:40:35 +02:00
nym21 7ad0adf659 oracle: start at 340k 2026-05-24 11:34:57 +02:00
nym21 6219d2301d oracle: snap pre 340k patch 2026-05-24 00:07:25 +02:00
nym21 0aaffc6c43 oracle: doc fixes 2026-05-23 12:18:34 +02:00
nym21 9c74881c5d oracle: snapshot + start at 508k 2026-05-23 00:45:37 +02:00
nym21 bf8de73541 oracle: cleanup 2026-05-22 11:02:56 +02:00
nym21 56e8103178 clients: bump versions 2026-05-22 11:02:12 +02:00
nym21 773c0d090b website: cleanup & fixes 2026-05-22 11:01:34 +02:00
nym21 d6f4c0ac19 changelog: updated 2026-05-22 11:01:07 +02:00
702 changed files with 10383 additions and 296848 deletions
-15
View File
@@ -1,15 +0,0 @@
name: Check outdated dependencies
on:
schedule:
- cron: "0 9 * * 1"
workflow_dispatch:
jobs:
outdated:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cargo install cargo-outdated
- run: cargo outdated --exit-code 1 --depth 1
Generated
+107 -112
View File
@@ -103,9 +103,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "autocfg"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
[[package]]
name = "axum"
@@ -176,11 +176,10 @@ dependencies = [
[[package]]
name = "base58ck"
version = "0.1.0"
version = "0.1.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f"
checksum = "ec5dc7e09f7bb15f0062da7c03086d6b71a2c84e0af4fccbbc7d8c6559847816"
dependencies = [
"bitcoin-internals",
"bitcoin_hashes",
]
@@ -222,20 +221,19 @@ dependencies = [
"quote",
"regex",
"rustc-hash",
"shlex",
"shlex 1.3.0",
"syn",
]
[[package]]
name = "bitcoin"
version = "0.32.9"
version = "0.32.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cf93e61f2dbc3e3c41234ca26a65e2c0b0975c52e0f069ab9893ebbede584d3"
checksum = "39581299241111285f3268ba75ddf372746fd041620918b145c1af9d75e91b6c"
dependencies = [
"base58ck",
"base64 0.21.7",
"bech32",
"bitcoin-internals",
"bitcoin-io",
"bitcoin-units",
"bitcoin_hashes",
@@ -245,36 +243,26 @@ dependencies = [
"serde",
]
[[package]]
name = "bitcoin-internals"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2"
dependencies = [
"serde",
]
[[package]]
name = "bitcoin-io"
version = "0.1.4"
version = "0.1.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953"
checksum = "11301df0b06f22dea7bb1916403fdd88a371031e495c49b8f96931b28189e175"
[[package]]
name = "bitcoin-units"
version = "0.1.3"
version = "0.1.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "346568ebaab2918487cea76dd55dae13c27bb618cdb737c952e69eb2017c4118"
checksum = "57bad157b78d0d1b22c4cbb6a35a566211fc4d14866a37f2c780652b50f3b845"
dependencies = [
"bitcoin-internals",
"serde",
]
[[package]]
name = "bitcoin_hashes"
version = "0.14.1"
version = "0.14.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b"
checksum = "0c9901a56e133a1fc86eeb1113e2591f45f4682451ca893bff494d2f88918e3f"
dependencies = [
"bitcoin-io",
"hex-conservative",
@@ -295,7 +283,7 @@ checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
[[package]]
name = "blk"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"bitcoin",
"brk_error",
@@ -308,7 +296,7 @@ dependencies = [
[[package]]
name = "brk"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"brk_bencher",
"brk_bindgen",
@@ -333,7 +321,7 @@ dependencies = [
[[package]]
name = "brk_alloc"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"libmimalloc-sys",
"mimalloc",
@@ -341,7 +329,7 @@ dependencies = [
[[package]]
name = "brk_bencher"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"brk_error",
"brk_logger",
@@ -351,14 +339,14 @@ dependencies = [
[[package]]
name = "brk_bencher_visualizer"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"plotters",
]
[[package]]
name = "brk_bindgen"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"brk_cohort",
"brk_query",
@@ -371,7 +359,7 @@ dependencies = [
[[package]]
name = "brk_cli"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"anyhow",
"brk_alloc",
@@ -396,7 +384,7 @@ dependencies = [
[[package]]
name = "brk_client"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"brk_cohort",
"brk_types",
@@ -407,7 +395,7 @@ dependencies = [
[[package]]
name = "brk_cohort"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"brk_error",
"brk_traversable",
@@ -419,7 +407,7 @@ dependencies = [
[[package]]
name = "brk_computer"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"bitcoin",
"brk_alloc",
@@ -448,7 +436,7 @@ dependencies = [
[[package]]
name = "brk_error"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"bitcoin",
"fjall",
@@ -464,7 +452,7 @@ dependencies = [
[[package]]
name = "brk_fetcher"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"brk_error",
"brk_logger",
@@ -476,7 +464,7 @@ dependencies = [
[[package]]
name = "brk_indexer"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"bitcoin",
"brk_alloc",
@@ -502,7 +490,7 @@ dependencies = [
[[package]]
name = "brk_iterator"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"bitcoin",
"brk_error",
@@ -513,7 +501,7 @@ dependencies = [
[[package]]
name = "brk_logger"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"jiff",
"owo-colors",
@@ -524,7 +512,7 @@ dependencies = [
[[package]]
name = "brk_mempool"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"bitcoin",
"brk_error",
@@ -540,7 +528,7 @@ dependencies = [
[[package]]
name = "brk_oracle"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"brk_indexer",
"brk_types",
@@ -550,7 +538,7 @@ dependencies = [
[[package]]
name = "brk_query"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"bitcoin",
"brk_computer",
@@ -575,7 +563,7 @@ dependencies = [
[[package]]
name = "brk_reader"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"bitcoin",
"brk_error",
@@ -591,7 +579,7 @@ dependencies = [
[[package]]
name = "brk_rpc"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"bitcoin",
"brk_error",
@@ -608,7 +596,7 @@ dependencies = [
[[package]]
name = "brk_server"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"aide",
"axum",
@@ -618,6 +606,7 @@ dependencies = [
"brk_indexer",
"brk_logger",
"brk_mempool",
"brk_oracle",
"brk_query",
"brk_reader",
"brk_rpc",
@@ -640,7 +629,7 @@ dependencies = [
[[package]]
name = "brk_store"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"brk_error",
"brk_types",
@@ -651,7 +640,7 @@ dependencies = [
[[package]]
name = "brk_traversable"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"brk_traversable_derive",
"brk_types",
@@ -664,7 +653,7 @@ dependencies = [
[[package]]
name = "brk_traversable_derive"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"proc-macro2",
"quote",
@@ -673,7 +662,7 @@ dependencies = [
[[package]]
name = "brk_types"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"bitcoin",
"brk_error",
@@ -696,7 +685,7 @@ dependencies = [
[[package]]
name = "brk_website"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"axum",
"brk_logger",
@@ -711,9 +700,9 @@ dependencies = [
[[package]]
name = "brotli"
version = "8.0.2"
version = "8.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560"
checksum = "8119e4516436f5708bbc474a9d395bf12f1b5395e93a92a56e647ac3388c8610"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
@@ -722,9 +711,9 @@ dependencies = [
[[package]]
name = "brotli-decompressor"
version = "5.0.0"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03"
checksum = "5962523e1b92ce1b5e793d9169b9943eece10d39f62550bc04bb605d75b94924"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
@@ -732,9 +721,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.20.2"
version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[package]]
name = "bytemuck"
@@ -768,14 +757,14 @@ checksum = "1c53ba0f290bfc610084c05582d9c5d421662128fc69f4bf236707af6fd321b9"
[[package]]
name = "cc"
version = "1.2.62"
version = "1.2.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98"
checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f"
dependencies = [
"find-msvc-tools",
"jobserver",
"libc",
"shlex",
"shlex 2.0.1",
]
[[package]]
@@ -968,9 +957,9 @@ dependencies = [
[[package]]
name = "corepc-types"
version = "0.13.0"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b96c7869aa8234d10a41cbe3a1697bcb3a2482c48d9eb3541b3a4014a81afdad"
checksum = "f095534efdb8f2f43d48b9c3e9f35aefdf29ec6a5f1895064f575a67bc2a8dfe"
dependencies = [
"bitcoin",
"serde",
@@ -1133,9 +1122,9 @@ dependencies = [
[[package]]
name = "displaydoc"
version = "0.2.5"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f"
dependencies = [
"proc-macro2",
"quote",
@@ -1186,9 +1175,9 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
[[package]]
name = "either"
version = "1.15.0"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
[[package]]
name = "enum_dispatch"
@@ -1533,9 +1522,9 @@ checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd"
[[package]]
name = "http"
version = "1.4.0"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
checksum = "8be7462df143984c4598a256ef469b251d7d7f9e271135073e78fc535414f3d0"
dependencies = [
"bytes",
"itoa",
@@ -1578,9 +1567,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "hyper"
version = "1.9.0"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca"
checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498"
dependencies = [
"atomic-waker",
"bytes",
@@ -1849,23 +1838,23 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "jiff"
version = "0.2.24"
version = "0.2.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f00b5dbd620d61dfdcb6007c9c1f6054ebd75319f163d886a9055cec1155073d"
checksum = "4603d3033e49e2b0e31229fcab20a5d40089c607d975cd9c80551dc69eed9102"
dependencies = [
"jiff-static",
"log",
"portable-atomic",
"portable-atomic-util",
"serde_core",
"windows-sys 0.61.2",
"windows-link",
]
[[package]]
name = "jiff-static"
version = "0.2.24"
version = "0.2.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e000de030ff8022ea1da3f466fbb0f3a809f5e51ed31f6dd931c35181ad8e6d7"
checksum = "782d32378dddf207193ac91cefb848ad41abb58195c95168e1291227a0832b47"
dependencies = [
"proc-macro2",
"quote",
@@ -1890,9 +1879,9 @@ checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07"
[[package]]
name = "js-sys"
version = "0.3.98"
version = "0.3.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08"
checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11"
dependencies = [
"cfg-if",
"futures-util",
@@ -1947,9 +1936,9 @@ dependencies = [
[[package]]
name = "libmimalloc-sys"
version = "0.1.47"
version = "0.1.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d1eacfa31c33ec25e873c136ba5669f00f9866d0688bea7be4d3f7e43067df6"
checksum = "6a45a52f43e1c16f667ccfe4dd8c85b7f7c204fd5e3bf46c5b0db9a5c3c0b8e9"
dependencies = [
"cc",
"cty",
@@ -1968,9 +1957,9 @@ dependencies = [
[[package]]
name = "libredox"
version = "0.1.16"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c"
checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3"
dependencies = [
"libc",
]
@@ -2004,9 +1993,9 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.29"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5"
[[package]]
name = "lsm-tree"
@@ -2047,9 +2036,9 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
[[package]]
name = "memchr"
version = "2.8.0"
version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8"
[[package]]
name = "memmap2"
@@ -2062,9 +2051,9 @@ dependencies = [
[[package]]
name = "mimalloc"
version = "0.1.50"
version = "0.1.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3627c4272df786b9260cabaa46aec1d59c93ede723d4c3ef646c503816b0640"
checksum = "2d4139bb28d14ad1facf21d5eb8825051b326e172d216b39f6d31df53cc97862"
dependencies = [
"libmimalloc-sys",
]
@@ -2093,9 +2082,9 @@ dependencies = [
[[package]]
name = "mio"
version = "1.2.0"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda"
dependencies = [
"libc",
"wasi",
@@ -2104,7 +2093,7 @@ dependencies = [
[[package]]
name = "mmpl"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"brk_error",
"brk_mempool",
@@ -2127,9 +2116,9 @@ dependencies = [
[[package]]
name = "num-conv"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967"
checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
[[package]]
name = "num-traits"
@@ -2767,9 +2756,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.149"
version = "1.0.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
dependencies = [
"indexmap",
"itoa",
@@ -2850,6 +2839,12 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "shlex"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
[[package]]
name = "simd-adler32"
version = "0.3.9"
@@ -2870,9 +2865,9 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "socket2"
version = "0.6.3"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51"
dependencies = [
"libc",
"windows-sys 0.61.2",
@@ -3260,9 +3255,9 @@ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "unicode-segmentation"
version = "1.13.2"
version = "1.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c"
checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
[[package]]
name = "unicode-xid"
@@ -3420,9 +3415,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790"
checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409"
dependencies = [
"cfg-if",
"once_cell",
@@ -3433,9 +3428,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578"
checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -3443,9 +3438,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2"
checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e"
dependencies = [
"bumpalo",
"proc-macro2",
@@ -3456,9 +3451,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.121"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441"
checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437"
dependencies = [
"unicode-ident",
]
@@ -3499,9 +3494,9 @@ dependencies = [
[[package]]
name = "web-sys"
version = "0.3.98"
version = "0.3.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa"
checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -3851,18 +3846,18 @@ dependencies = [
[[package]]
name = "zerocopy"
version = "0.8.48"
version = "0.8.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.48"
version = "0.8.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639"
dependencies = [
"proc-macro2",
"quote",
+28 -28
View File
@@ -4,7 +4,7 @@ members = ["crates/*"]
package.description = "The Bitcoin Research Kit is a suite of tools designed to extract, compute and display data stored on a Bitcoin Core node"
package.license = "MIT"
package.edition = "2024"
package.version = "0.3.0"
package.version = "0.3.1"
package.homepage = "https://bitcoinresearchkit.org"
package.repository = "https://github.com/bitcoinresearchkit/brk"
package.readme = "README.md"
@@ -35,38 +35,38 @@ debug = true
[workspace.dependencies]
aide = { version = "0.16.0-alpha.4", features = ["axum-json", "axum-query"] }
axum = { version = "0.8.9", default-features = false, features = ["http1", "json", "query", "tokio", "tracing"] }
bitcoin = { version = "0.32.9", features = ["serde"] }
brk_alloc = { version = "0.3.0", path = "crates/brk_alloc" }
brk_bencher = { version = "0.3.0", path = "crates/brk_bencher" }
brk_bindgen = { version = "0.3.0", path = "crates/brk_bindgen" }
brk_cli = { version = "0.3.0", path = "crates/brk_cli" }
brk_client = { version = "0.3.0", path = "crates/brk_client" }
brk_cohort = { version = "0.3.0", path = "crates/brk_cohort" }
brk_computer = { version = "0.3.0", path = "crates/brk_computer" }
brk_error = { version = "0.3.0", path = "crates/brk_error" }
brk_fetcher = { version = "0.3.0", path = "crates/brk_fetcher" }
brk_indexer = { version = "0.3.0", path = "crates/brk_indexer" }
brk_iterator = { version = "0.3.0", path = "crates/brk_iterator" }
brk_logger = { version = "0.3.0", path = "crates/brk_logger" }
brk_mempool = { version = "0.3.0", path = "crates/brk_mempool" }
brk_oracle = { version = "0.3.0", path = "crates/brk_oracle" }
brk_query = { version = "0.3.0", path = "crates/brk_query", features = ["tokio"] }
brk_reader = { version = "0.3.0", path = "crates/brk_reader" }
brk_rpc = { version = "0.3.0", path = "crates/brk_rpc" }
brk_server = { version = "0.3.0", path = "crates/brk_server" }
brk_store = { version = "0.3.0", path = "crates/brk_store" }
brk_traversable = { version = "0.3.0", path = "crates/brk_traversable", features = ["pco", "derive"] }
brk_traversable_derive = { version = "0.3.0", path = "crates/brk_traversable_derive" }
brk_types = { version = "0.3.0", path = "crates/brk_types" }
brk_website = { version = "0.3.0", path = "crates/brk_website" }
bitcoin = { version = "0.32.100", features = ["serde"] }
brk_alloc = { version = "0.3.1", path = "crates/brk_alloc" }
brk_bencher = { version = "0.3.1", path = "crates/brk_bencher" }
brk_bindgen = { version = "0.3.1", path = "crates/brk_bindgen" }
brk_cli = { version = "0.3.1", path = "crates/brk_cli" }
brk_client = { version = "0.3.1", path = "crates/brk_client" }
brk_cohort = { version = "0.3.1", path = "crates/brk_cohort" }
brk_computer = { version = "0.3.1", path = "crates/brk_computer" }
brk_error = { version = "0.3.1", path = "crates/brk_error" }
brk_fetcher = { version = "0.3.1", path = "crates/brk_fetcher" }
brk_indexer = { version = "0.3.1", path = "crates/brk_indexer" }
brk_iterator = { version = "0.3.1", path = "crates/brk_iterator" }
brk_logger = { version = "0.3.1", path = "crates/brk_logger" }
brk_mempool = { version = "0.3.1", path = "crates/brk_mempool" }
brk_oracle = { version = "0.3.1", path = "crates/brk_oracle" }
brk_query = { version = "0.3.1", path = "crates/brk_query", features = ["tokio"] }
brk_reader = { version = "0.3.1", path = "crates/brk_reader" }
brk_rpc = { version = "0.3.1", path = "crates/brk_rpc" }
brk_server = { version = "0.3.1", path = "crates/brk_server" }
brk_store = { version = "0.3.1", path = "crates/brk_store" }
brk_traversable = { version = "0.3.1", path = "crates/brk_traversable", features = ["pco", "derive"] }
brk_traversable_derive = { version = "0.3.1", path = "crates/brk_traversable_derive" }
brk_types = { version = "0.3.1", path = "crates/brk_types" }
brk_website = { version = "0.3.1", path = "crates/brk_website" }
byteview = "0.10.1"
color-eyre = "0.6.5"
corepc-jsonrpc = { package = "jsonrpc", version = "0.19.0", features = ["simple_http"], default-features = false }
corepc-types = { version = "0.13.0", features = ["std"], default-features = false }
corepc-types = { version = "0.14.0", features = ["std"], default-features = false }
derive_more = { version = "2.1.1", features = ["deref", "deref_mut"] }
fjall = "3.1.4"
indexmap = { version = "2.14.0", features = ["serde"] }
jiff = { version = "0.2.24", features = ["perf-inline", "tz-system"], default-features = false }
jiff = { version = "0.2.28", features = ["perf-inline", "tz-system"], default-features = false }
owo-colors = "4.3.0"
parking_lot = "0.12.5"
pco = "1.0.2"
@@ -76,7 +76,7 @@ schemars = { version = "1.2.1", features = ["indexmap2"] }
serde = "1.0.228"
serde_bytes = "0.11.19"
serde_derive = "1.0.228"
serde_json = { version = "1.0.149", features = ["float_roundtrip", "preserve_order"] }
serde_json = { version = "1.0.150", features = ["float_roundtrip", "preserve_order"] }
smallvec = "1.15.1"
tokio = { version = "1.52.3", features = ["rt-multi-thread"] }
tower-http = { version = "0.6.11", features = ["catch-panic", "compression-br", "compression-gzip", "compression-zstd", "cors", "normalize-path", "timeout", "trace"] }
+2 -2
View File
@@ -8,5 +8,5 @@ homepage.workspace = true
repository.workspace = true
[dependencies]
libmimalloc-sys = { version = "0.1.47", features = ["extended"] }
mimalloc = { version = "0.1.50" }
libmimalloc-sys = { version = "0.1.49", features = ["extended"] }
mimalloc = { version = "0.1.52" }
@@ -51,7 +51,7 @@ fn generate_get_method(output: &mut String, endpoint: &Endpoint) {
}
writeln!(
output,
" * @param {{{{ signal?: AbortSignal, onValue?: (value: {}) => void }}}} [options]",
" * @param {{{{ signal?: AbortSignal, onValue?: (value: {}) => void, cache?: boolean }}}} [options]",
return_type
)
.unwrap();
@@ -60,22 +60,22 @@ fn generate_get_method(output: &mut String, endpoint: &Endpoint) {
let params = build_method_params(endpoint);
let params_with_opts = if params.is_empty() {
"{ signal, onValue } = {}".to_string()
"{ signal, onValue, cache } = {}".to_string()
} else {
format!("{}, {{ signal, onValue }} = {{}}", params)
format!("{}, {{ signal, onValue, cache }} = {{}}", params)
};
writeln!(output, " async {}({}) {{", method_name, params_with_opts).unwrap();
let path = build_path_template(&endpoint.path, &endpoint.path_params);
let fetch_call: String = if endpoint.returns_binary() {
"this.getBytes(path, { signal, onValue })".to_string()
"this.getBytes(path, { signal, onValue, cache })".to_string()
} else if endpoint.returns_json() {
"this.getJson(path, { signal, onValue })".to_string()
"this.getJson(path, { signal, onValue, cache })".to_string()
} else if endpoint.response_kind.text_is_numeric() {
"Number(await this.getText(path, { signal, onValue: onValue ? (v) => onValue(Number(v)) : undefined }))".to_string()
"Number(await this.getText(path, { signal, cache, onValue: onValue ? (v) => onValue(Number(v)) : undefined }))".to_string()
} else {
"this.getText(path, { signal, onValue })".to_string()
"this.getText(path, { signal, onValue, cache })".to_string()
};
write_path_assignment(output, endpoint, &path);
@@ -83,7 +83,7 @@ fn generate_get_method(output: &mut String, endpoint: &Endpoint) {
if endpoint.supports_csv {
writeln!(
output,
" if (format === 'csv') return this.getText(path, {{ signal, onValue }});"
" if (format === 'csv') return this.getText(path, {{ signal, onValue, cache }});"
)
.unwrap();
}
@@ -448,14 +448,17 @@ class BrkClientBase {{
/**
* @param {{string}} path
* @param {{{{ signal?: AbortSignal }}}} [options]
* @param {{{{ signal?: AbortSignal, cache?: boolean }}}} [options]
* @returns {{Promise<Response>}}
*/
async get(path, {{ signal }} = {{}}) {{
async get(path, {{ signal, cache = true }} = {{}}) {{
const url = `${{this.baseUrl}}${{path}}`;
const signals = [AbortSignal.timeout(this.timeout)];
if (signal) signals.push(signal);
const res = await fetch(url, {{ signal: AbortSignal.any(signals) }});
/** @type {{RequestInit}} */
const init = {{ signal: AbortSignal.any(signals) }};
if (!cache) init.cache = 'no-store';
const res = await fetch(url, init);
if (!res.ok) throw new BrkError(`HTTP ${{res.status}}: ${{url}}`, res.status);
return res;
}}
@@ -475,14 +478,21 @@ class BrkClientBase {{
* @template T
* @param {{string}} path
* @param {{(res: Response) => Promise<T>}} parse - Response body reader
* @param {{{{ onValue?: (value: T) => void, signal?: AbortSignal }}}} [options]
* @param {{{{ onValue?: (value: T) => void, signal?: AbortSignal, cache?: boolean }}}} [options]
* @returns {{Promise<T>}}
*/
async _getCached(path, parse, {{ onValue, signal }} = {{}}) {{
async _getCached(path, parse, {{ onValue, signal, cache = true }} = {{}}) {{
if (!cache) {{
const res = await this.get(path, {{ signal, cache }});
const value = await parse(res);
if (onValue) onValue(value);
return value;
}}
const url = `${{this.baseUrl}}${{path}}`;
/** @type {{_MemEntry<T> | undefined}} */
const memHit = this._memGet(url);
const browserCache = this._browserCache ?? await this._browserCachePromise;
const browserCache = this._browserCache;
// L1 fast path: deliver from memCache, revalidate via network.
// ETag match → zero parse, zero clone, zero cache write, no second onValue fire.
@@ -497,8 +507,8 @@ class BrkClientBase {{
this._memSet(url, netEtag, value);
if (onValue) onValue(value);
if (cloned && browserCache) {{
const cache = browserCache;
_runIdle(() => cache.put(url, cloned));
const cacheStore = browserCache;
_runIdle(() => cacheStore.put(url, cloned));
}}
return value;
}} catch {{
@@ -531,8 +541,8 @@ class BrkClientBase {{
this._memSet(url, netEtag, value);
if (onValue) onValue(value);
if (cloned && browserCache) {{
const cache = browserCache;
_runIdle(() => cache.put(url, cloned));
const cacheStore = browserCache;
_runIdle(() => cacheStore.put(url, cloned));
}}
return value;
}} catch (e) {{
@@ -546,7 +556,7 @@ class BrkClientBase {{
* Make a GET request expecting a JSON response. Cached and supports `onValue`.
* @template T
* @param {{string}} path
* @param {{{{ onValue?: (value: T) => void, signal?: AbortSignal }}}} [options]
* @param {{{{ onValue?: (value: T) => void, signal?: AbortSignal, cache?: boolean }}}} [options]
* @returns {{Promise<T>}}
*/
getJson(path, options) {{
@@ -557,7 +567,7 @@ class BrkClientBase {{
* Make a GET request expecting a text response (text/plain, text/csv, ...).
* Cached and supports `onValue`, same as `getJson`.
* @param {{string}} path
* @param {{{{ onValue?: (value: string) => void, signal?: AbortSignal }}}} [options]
* @param {{{{ onValue?: (value: string) => void, signal?: AbortSignal, cache?: boolean }}}} [options]
* @returns {{Promise<string>}}
*/
getText(path, options) {{
@@ -568,7 +578,7 @@ class BrkClientBase {{
* Make a GET request expecting binary data (application/octet-stream).
* Cached and supports `onValue`, same as `getJson`.
* @param {{string}} path
* @param {{{{ onValue?: (value: Uint8Array) => void, signal?: AbortSignal }}}} [options]
* @param {{{{ onValue?: (value: Uint8Array) => void, signal?: AbortSignal, cache?: boolean }}}} [options]
* @returns {{Promise<Uint8Array>}}
*/
getBytes(path, options) {{
+46 -1
View File
@@ -8953,7 +8953,7 @@ pub struct BrkClient {
impl BrkClient {
/// Client version.
pub const VERSION: &'static str = "v0.3.0-beta.11";
pub const VERSION: &'static str = "v0.3.0";
/// Create a new client with the given base URL.
pub fn new(base_url: impl Into<String>) -> Self {
@@ -9856,6 +9856,51 @@ impl BrkClient {
self.base.get_json(&format!("/api/mempool/price"))
}
/// Live BTC/USD price
///
/// Current BTC/USD price in dollars. Same value as `/api/mempool/price`. Confirmed per-height history is available at `/api/vecs/height-to-price`.
///
/// Endpoint: `GET /api/oracle/price`
pub fn get_oracle_price(&self) -> Result<Dollars> {
self.base.get_json(&format!("/api/oracle/price"))
}
/// Live payment output histogram
///
/// Live smoothed histogram of oracle-eligible payment outputs, binned by output value on the oracle log scale. It combines the committed oracle window with the forming mempool block. A flat array of log-scale bins.
///
/// Endpoint: `GET /api/oracle/histogram/payments/live`
pub fn get_oracle_histogram_payments_live(&self) -> Result<Vec<i64>> {
self.base.get_json(&format!("/api/oracle/histogram/payments/live"))
}
/// Payment output histogram at height or day
///
/// Smoothed histogram of oracle-eligible payment outputs for a confirmed point. A block height (`840000`) gives that block's oracle payment histogram; a calendar date (`YYYY-MM-DD`) gives the average of that day's per-block payment histograms. A flat array of log-scale bins.
///
/// Endpoint: `GET /api/oracle/histogram/payments/{point}`
pub fn get_oracle_histogram_payments(&self, point: &str) -> Result<Vec<i64>> {
self.base.get_json(&format!("/api/oracle/histogram/payments/{point}"))
}
/// Live output value histogram
///
/// Live unfiltered output value histogram for the forming mempool block. Every live output is binned by value on the oracle log scale; no oracle payment filters are applied. A flat array of log-scale bins, all zero when no mempool is configured.
///
/// Endpoint: `GET /api/oracle/histogram/outputs/live`
pub fn get_oracle_histogram_outputs_live(&self) -> Result<Vec<i64>> {
self.base.get_json(&format!("/api/oracle/histogram/outputs/live"))
}
/// Output value histogram at height or day
///
/// Unfiltered output value histogram for a confirmed point. A block height (`840000`) gives every output in that block, coinbase included, binned by value on the oracle log scale; a calendar date (`YYYY-MM-DD`) sums every block that day. A flat array of log-scale bins.
///
/// Endpoint: `GET /api/oracle/histogram/outputs/{point}`
pub fn get_oracle_histogram_outputs(&self, point: &str) -> Result<Vec<i64>> {
self.base.get_json(&format!("/api/oracle/histogram/outputs/{point}"))
}
/// Txid by index
///
/// Retrieve the transaction ID (txid) at a given global transaction index. Returns the txid as plain text.
@@ -24,51 +24,60 @@ pub struct RecoveredState {
/// Returns Height::ZERO if any validation fails (triggers fresh start).
pub(crate) fn recover_state(
height: Height,
chain_state_rollback: vecdb::Result<Stamp>,
chain_state_rollback: Option<vecdb::Result<Stamp>>,
any_addr_indexes: &mut AnyAddrIndexesVecs,
addrs_data: &mut AddrsDataVecs,
utxo_cohorts: &mut UTXOCohorts,
addr_cohorts: &mut AddrCohorts,
) -> Result<RecoveredState> {
let stamp = Stamp::from(height);
// `None`: clean resume, already at the checkpoint, nothing to undo.
// `Some`: reorg, undo state past the resume point.
let consistent_height = match chain_state_rollback {
None => height,
Some(chain_state_rollback) => {
let stamp = Stamp::from(height);
// Rollback address state vectors
let addr_indexes_rollback = any_addr_indexes.rollback_before(stamp);
let addr_data_rollback = addrs_data.rollback_before(stamp);
// Rollback address state vectors
let addr_indexes_rollback = any_addr_indexes.rollback_before(stamp);
let addr_data_rollback = addrs_data.rollback_before(stamp);
// Verify rollback consistency - all must agree on the same height
let consistent_height = rollback_states(
chain_state_rollback,
addr_indexes_rollback,
addr_data_rollback,
);
// Verify rollback consistency - all must agree on the same height
let consistent_height = rollback_states(
chain_state_rollback,
addr_indexes_rollback,
addr_data_rollback,
);
// If rollbacks are inconsistent, start fresh
if consistent_height.is_zero() {
warn!("Rollback consistency check failed: inconsistent heights");
return Ok(RecoveredState {
starting_height: Height::ZERO,
});
}
// If rollbacks are inconsistent, start fresh
if consistent_height.is_zero() {
warn!("Rollback consistency check failed: inconsistent heights");
return Ok(RecoveredState {
starting_height: Height::ZERO,
});
}
// Rollback can land at an earlier height (multi-block change file), which is fine.
// But if it lands AHEAD of target, that means rollback failed (missing change files).
if consistent_height > height {
warn!(
"Rollback failed: still at {} but target was {}, falling back to fresh start",
consistent_height, height
);
return Ok(RecoveredState {
starting_height: Height::ZERO,
});
}
// Rollback can land at an earlier height (multi-block change file), which is fine.
// But if it lands AHEAD of target, that means rollback failed (missing change files).
if consistent_height > height {
warn!(
"Rollback failed: still at {} but target was {}, falling back to fresh start",
consistent_height, height
);
return Ok(RecoveredState {
starting_height: Height::ZERO,
});
}
if consistent_height != height {
debug!(
"Rollback landed at {} instead of {}, will resume from there",
consistent_height, height
);
}
if consistent_height != height {
debug!(
"Rollback landed at {} instead of {}, will resume from there",
consistent_height, height
);
}
consistent_height
}
};
// Import UTXO cohort states - all must succeed
debug!(
+6 -5
View File
@@ -341,12 +341,13 @@ impl Vecs {
// Try to resume from checkpoint, fall back to fresh start if needed
let recovered_height = match start_mode {
StartMode::Resume(height) => {
let stamp = Stamp::from(height);
// Roll back only on a reorg. A clean resume has nothing to undo, and an
// interrupted run wrote no rollback metadata (periodic flushes use
// with_changes=false; only the final write creates the `changes/` dir),
// so `rollback_before` would fail with `NotFound`.
let chain_state_rollback = (height < current_height)
.then(|| self.supply_state.rollback_before(Stamp::from(height)));
// Rollback BytesVec state and capture results for validation
let chain_state_rollback = self.supply_state.rollback_before(stamp);
// Validate all rollbacks and imports are consistent
let recovered = recover_state(
height,
chain_state_rollback,
+91 -39
View File
@@ -2,7 +2,10 @@ use std::ops::Range;
use brk_error::Result;
use brk_indexer::{Indexer, Lengths};
use brk_oracle::{Config, Histogram, Oracle, START_HEIGHT, bin_to_cents, cents_to_bin};
use brk_oracle::{
bin_to_cents, cents_to_bin, for_each_round_dollar_bin, Config, HistogramRaw, Oracle,
START_HEIGHT_FAST, START_HEIGHT_SLOW,
};
use brk_types::{Cents, OutputType, Sats, TxIndex, TxOutIndex};
use tracing::info;
use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, StorageMode, VecIndex, WritableVec};
@@ -61,8 +64,8 @@ impl Vecs {
fn compute_prices(&mut self, indexer: &Indexer, exit: &Exit) -> Result<()> {
let starting_height = indexer.safe_lengths().height;
let source_version = indexer.vecs.outputs.value.version()
+ indexer.vecs.outputs.output_type.version();
let source_version =
indexer.vecs.outputs.value.version() + indexer.vecs.outputs.output_type.version();
self.spot
.cents
.height
@@ -71,7 +74,7 @@ impl Vecs {
let total_heights = indexer.vecs.blocks.timestamp.len();
if total_heights <= START_HEIGHT {
if total_heights <= START_HEIGHT_SLOW {
return Ok(());
}
@@ -83,12 +86,12 @@ impl Vecs {
.inner
.truncate_if_needed_at(truncate_to)?;
if self.spot.cents.height.len() < START_HEIGHT {
if self.spot.cents.height.len() < START_HEIGHT_SLOW {
for line in brk_oracle::PRICES
.lines()
.skip(self.spot.cents.height.len())
{
if self.spot.cents.height.len() >= START_HEIGHT {
if self.spot.cents.height.len() >= START_HEIGHT_SLOW {
break;
}
let dollars: f64 = line.parse().unwrap_or(0.0);
@@ -101,8 +104,8 @@ impl Vecs {
return Ok(());
}
let config = Config::default();
let committed = self.spot.cents.height.len();
let config = Config::for_height(committed);
let prev_cents = self
.spot
.cents
@@ -110,9 +113,9 @@ impl Vecs {
.collect_one_at(committed - 1)
.unwrap();
let seed_bin = cents_to_bin(prev_cents.inner() as f64);
let warmup = config.window_size.min(committed - START_HEIGHT);
let warmup = config.window_size.min(committed - START_HEIGHT_SLOW);
let mut oracle = Oracle::from_checkpoint(seed_bin, config, |o| {
Self::feed_blocks(o, indexer, (committed - warmup)..committed, None);
Self::feed_blocks_for_warmup(o, indexer, (committed - warmup)..committed, None);
});
let num_new = total_heights - committed;
@@ -121,19 +124,48 @@ impl Vecs {
committed, total_heights
);
let ref_bins =
Self::feed_blocks(&mut oracle, indexer, committed..total_heights, None);
// Slow cold-start EMA up to START_HEIGHT_FAST, then switch to the fast
// mature-market EMA. Steady-state runs start past START_HEIGHT_FAST and skip
// the slow segment entirely.
{
let mut processed = 0usize;
let mut push_ref_bin = |ref_bin| {
self.spot
.cents
.height
.inner
.push(Cents::new(bin_to_cents(ref_bin)));
for (i, ref_bin) in ref_bins.into_iter().enumerate() {
self.spot
.cents
.height
.inner
.push(Cents::new(bin_to_cents(ref_bin)));
processed += 1;
let progress = (processed * 100 / num_new) as u8;
if processed > 1 && progress > (((processed - 1) * 100 / num_new) as u8) {
info!("Oracle price computation: {}%", progress);
}
};
let progress = ((i + 1) * 100 / num_new) as u8;
if i > 0 && progress > ((i * 100 / num_new) as u8) {
info!("Oracle price computation: {}%", progress);
if committed < START_HEIGHT_FAST {
let slow_end = START_HEIGHT_FAST.min(total_heights);
Self::feed_blocks_with(
&mut oracle,
indexer,
committed..slow_end,
None,
|_, _, ref_bin| push_ref_bin(ref_bin),
);
if slow_end == START_HEIGHT_FAST {
oracle.reconfigure(Config::default());
}
}
let fast_start = committed.max(START_HEIGHT_FAST);
if fast_start < total_heights {
Self::feed_blocks_with(
&mut oracle,
indexer,
fast_start..total_heights,
None,
|_, _, ref_bin| push_ref_bin(ref_bin),
);
}
}
@@ -151,11 +183,8 @@ impl Vecs {
}
/// Feed a range of blocks from the indexer into an Oracle (skipping coinbase),
/// returning per-block ref_bin values.
///
/// A transaction carrying an `OP_RETURN` output is protocol machinery, not a
/// dollar-denominated payment, so all of its outputs are dropped from the
/// histogram. This needs per-transaction grouping of a block's outputs.
/// returning per-block ref_bin values. Outputs are grouped per transaction
/// because `for_each_round_dollar_bin` drops a whole tx on any OP_RETURN.
///
/// Pass `cap = None` from compute paths, when the indexer is quiescent and
/// raw vec lengths are authoritative. Pass `cap = Some(&safe_lengths)` from
@@ -166,6 +195,33 @@ impl Vecs {
range: Range<usize>,
cap: Option<&Lengths>,
) -> Vec<f64> {
let mut ref_bins = Vec::with_capacity(range.len());
Self::feed_blocks_with(oracle, indexer, range, cap, |_, _, ref_bin| {
ref_bins.push(ref_bin);
});
ref_bins
}
/// Feed blocks into an Oracle when callers only need the warmed EMA/window state.
pub fn feed_blocks_for_warmup<IM: StorageMode>(
oracle: &mut Oracle,
indexer: &Indexer<IM>,
range: Range<usize>,
cap: Option<&Lengths>,
) {
Self::feed_blocks_with(oracle, indexer, range, cap, |_, _, _| {});
}
/// Feed a range of blocks into an Oracle and call `on_block` after each
/// processed block. This lets callers observe derived state such as EMA
/// without duplicating the histogram extraction path.
pub fn feed_blocks_with<IM: StorageMode>(
oracle: &mut Oracle,
indexer: &Indexer<IM>,
range: Range<usize>,
cap: Option<&Lengths>,
mut on_block: impl FnMut(usize, &Oracle, f64),
) {
let (total_txs, total_outputs, height_len) = match cap {
Some(c) => (
c.tx_index.to_usize(),
@@ -193,8 +249,6 @@ impl Vecs {
.first_txout_index
.collect_range_at(range.start, collect_end);
let mut ref_bins = Vec::with_capacity(range.len());
// Cursor avoids per-block PcoVec page decompression for the
// tx-indexed first_txout_index lookup. Accessed tx_index values
// are strictly increasing across blocks, so it only advances forward.
@@ -239,26 +293,24 @@ impl Vecs {
&mut output_types,
);
let mut hist = Histogram::zeros();
let mut hist = HistogramRaw::zeros();
for tx in 0..tx_count {
let lo = tx_starts[tx] - out_start;
let hi = tx_starts
.get(tx + 1)
.map(|s| s - out_start)
.unwrap_or(out_end - out_start);
if output_types[lo..hi].contains(&OutputType::OpReturn) {
continue;
}
for i in lo..hi {
if let Some(bin) = oracle.output_to_bin(values[i], output_types[i]) {
hist.increment(bin);
}
}
let outputs = values[lo..hi]
.iter()
.copied()
.zip(output_types[lo..hi].iter().copied());
for_each_round_dollar_bin(range.start + idx, outputs, |bin| {
hist.increment(bin as usize)
});
}
ref_bins.push(oracle.process_histogram(&hist));
let ref_bin = oracle.process_histogram(&hist);
on_block(range.start + idx, oracle, ref_bin);
}
ref_bins
}
}
+16 -8
View File
@@ -1,6 +1,6 @@
//! Mempool info + price-blending output histogram.
use brk_oracle::Histogram;
use brk_oracle::HistogramRaw;
use brk_types::MempoolInfo;
use crate::Mempool;
@@ -11,13 +11,21 @@ impl Mempool {
self.read().info.clone()
}
/// Snapshot of pre-bucketed oracle bins across all live mempool tx
/// outputs. The total is maintained incrementally by `TxStore` on
/// every insert/remove, so this hot path is `O(NUM_BINS)` regardless
/// of pool size. Used by `live_price` to blend the mempool into the
/// committed oracle without re-parsing scripts per request.
/// Snapshot of pre-bucketed round-dollar-eligible bins across all live
/// mempool tx outputs. Maintained incrementally by `TxStore` on every
/// insert/remove, so this hot path is `O(NUM_BINS)` regardless of pool
/// size. Used by `live_price` to blend the mempool into the committed
/// oracle without re-parsing scripts per request.
#[must_use]
pub fn live_histogram(&self) -> Histogram {
self.read().txs.live_histogram()
pub fn live_eligible_histogram(&self) -> HistogramRaw {
self.read().txs.live_eligible_histogram()
}
/// Snapshot of the raw histogram: every live mempool output binned by
/// value with no payment filtering. Backs the `histogram/raw/live`
/// endpoint.
#[must_use]
pub fn live_raw_histogram(&self) -> HistogramRaw {
self.read().txs.live_raw_histogram()
}
}
@@ -0,0 +1,61 @@
use brk_oracle::{HistogramRaw, for_each_round_dollar_bin, sats_to_bin};
use brk_types::Transaction;
use crate::stores::tx_store::TxRecord;
/// The two live per-bin histograms the pool maintains incrementally as txs
/// enter and leave: `eligible` applies the round-dollar payment filter (it
/// feeds the oracle blend), `raw` bins every output by value with no filtering.
/// Add and remove run through the same code so the two stay symmetric.
#[derive(Default)]
pub struct LiveHistograms {
eligible: HistogramRaw,
raw: HistogramRaw,
}
impl LiveHistograms {
/// Fold a record's outputs into both histograms.
pub fn add(&mut self, record: &TxRecord) {
Self::eligible_bins(&record.tx, |bin| self.eligible[bin as usize] += 1);
for bin in Self::raw_bins(&record.tx) {
self.raw[bin] += 1;
}
}
/// Reverse a previous `add` for the same record.
pub fn remove(&mut self, record: &TxRecord) {
Self::eligible_bins(&record.tx, |bin| self.eligible[bin as usize] -= 1);
for bin in Self::raw_bins(&record.tx) {
self.raw[bin] -= 1;
}
}
/// Round-dollar-eligible bins, blended into the oracle by `live_price`.
pub fn eligible(&self) -> HistogramRaw {
self.eligible.clone()
}
/// Every live output binned by value, no payment filtering.
pub fn raw(&self) -> HistogramRaw {
self.raw.clone()
}
/// Round-dollar-eligible bins, applying the oracle payment filter. Calls
/// `emit(bin)` per eligible output. Deterministic over a tx's outputs,
/// which are never mutated after insert, so add and remove recompute it
/// identically rather than caching. Live mempool txs are post-tip, always
/// above the historical max-outputs cap window, so the cap never applies.
fn eligible_bins(tx: &Transaction, emit: impl FnMut(u16)) {
for_each_round_dollar_bin(
usize::MAX,
tx.output.iter().map(|o| (o.value, o.type_())),
emit,
);
}
/// Raw bin index per output, dropping only values outside the bin domain
/// (zero / out-of-range).
fn raw_bins(tx: &Transaction) -> impl Iterator<Item = usize> + '_ {
tx.output.iter().filter_map(|o| sats_to_bin(o.value))
}
}
+2 -2
View File
@@ -4,13 +4,13 @@
//! one lock-order discipline.
mod addr_tracker;
mod live_histograms;
mod outpoint_spends;
mod output_bins;
mod tx_graveyard;
mod tx_store;
pub use addr_tracker::AddrTracker;
pub use live_histograms::LiveHistograms;
pub use outpoint_spends::OutpointSpends;
pub use output_bins::OutputBins;
pub use tx_graveyard::{TxGraveyard, TxTombstone};
pub use tx_store::TxStore;
@@ -1,23 +0,0 @@
use brk_oracle::default_eligible_bin;
use brk_types::Transaction;
use smallvec::SmallVec;
/// Pre-bucketed oracle bins for a tx's eligible outputs. Computed once on
/// insert so `Mempool::live_histogram` can bin all live outputs without
/// re-parsing scripts or recomputing eligibility per request.
pub struct OutputBins(SmallVec<[u16; 4]>);
impl OutputBins {
pub fn from_tx(tx: &Transaction) -> Self {
Self(
tx.output
.iter()
.filter_map(|o| default_eligible_bin(o.value, o.type_()))
.collect(),
)
}
pub fn iter(&self) -> impl Iterator<Item = u16> + '_ {
self.0.iter().copied()
}
}
+63 -34
View File
@@ -1,28 +1,21 @@
use brk_oracle::Histogram;
use brk_oracle::HistogramRaw;
use brk_types::{MempoolRecentTx, Transaction, TxOut, Txid, TxidPrefix, Vin};
use rustc_hash::{FxHashMap, FxHashSet};
use crate::{state::TxEntry, stores::OutputBins};
use crate::{state::TxEntry, stores::LiveHistograms};
const RECENT_CAP: usize = 10;
/// Per-tx record: live tx body, its mempool entry, and the pre-bucketed
/// oracle bins for its outputs. Kept under one key so a single map probe
/// returns everything readers need.
/// Per-tx record: live tx body and its mempool entry, kept under one key
/// so a single map probe returns everything readers need.
pub struct TxRecord {
pub tx: Transaction,
pub entry: TxEntry,
pub output_bins: OutputBins,
}
impl TxRecord {
pub fn new(tx: Transaction, entry: TxEntry) -> Self {
let output_bins = OutputBins::from_tx(&tx);
Self {
tx,
entry,
output_bins,
}
Self { tx, entry }
}
}
@@ -32,15 +25,15 @@ impl TxRecord {
/// set of prefixes whose tx still has at least one `prevout: None`,
/// maintained on every `insert` / `remove_by_prefix` / `apply_fills`
/// so the post-update prevout filler can early-exit when empty.
/// `live_histogram` mirrors the union of each record's `OutputBins`,
/// kept in sync on `insert` / `remove_by_prefix` so the oracle-blend
/// read path is a single array clone, not a full pool walk.
/// `histograms` holds the eligible (oracle-blend) and raw per-bin output
/// histograms, kept in sync on `insert` / `remove_by_prefix` so each read
/// path is a single array clone, not a full pool walk.
#[derive(Default)]
pub struct TxStore {
records: FxHashMap<TxidPrefix, TxRecord>,
recent: Vec<MempoolRecentTx>,
unresolved: FxHashSet<TxidPrefix>,
live_histogram: Histogram,
histograms: LiveHistograms,
}
impl TxStore {
@@ -92,9 +85,7 @@ impl TxStore {
self.unresolved.insert(prefix);
}
let record = TxRecord::new(tx, entry);
for bin in record.output_bins.iter() {
self.live_histogram[bin as usize] += 1;
}
self.histograms.add(&record);
self.records.insert(prefix, record);
}
@@ -112,16 +103,21 @@ impl TxStore {
pub fn remove_by_prefix(&mut self, prefix: &TxidPrefix) -> Option<TxRecord> {
let record = self.records.remove(prefix)?;
self.unresolved.remove(prefix);
for bin in record.output_bins.iter() {
self.live_histogram[bin as usize] -= 1;
}
self.histograms.remove(&record);
Some(record)
}
/// Snapshot the live oracle-bin histogram. Maintained incrementally
/// on insert/remove, so this is `O(NUM_BINS)`, not `O(live_outputs)`.
pub fn live_histogram(&self) -> Histogram {
self.live_histogram.clone()
/// Snapshot the round-dollar-eligible histogram that feeds the oracle
/// blend. Maintained incrementally, so this is `O(NUM_BINS)`, not
/// `O(live_outputs)`.
pub fn live_eligible_histogram(&self) -> HistogramRaw {
self.histograms.eligible()
}
/// Snapshot the raw histogram: every live output binned by value with no
/// payment filtering. Maintained incrementally alongside the eligible one.
pub fn live_raw_histogram(&self) -> HistogramRaw {
self.histograms.raw()
}
/// Set of prefixes with at least one unfilled prevout. Used by the
@@ -263,7 +259,10 @@ mod tests {
assert_eq!(applied[0].value, new_prevout.value);
let record = store.record_by_prefix(&prefix).expect("record present");
assert_eq!(record.tx.input[0].prevout.as_ref().unwrap().value, new_prevout.value);
assert_eq!(
record.tx.input[0].prevout.as_ref().unwrap().value,
new_prevout.value
);
assert_eq!(
record.tx.input[1].prevout.as_ref().unwrap().value,
prev_present.value
@@ -277,7 +276,10 @@ mod tests {
let stray_prefix = TxidPrefix::from(&fake_txid(0xFF));
let applied = store.apply_fills(
&stray_prefix,
vec![(Vin::from(0u32), TxOut::from((ScriptBuf::new(), Sats::from(1u64))))],
vec![(
Vin::from(0u32),
TxOut::from((ScriptBuf::new(), Sats::from(1u64))),
)],
);
assert!(applied.is_empty());
}
@@ -319,10 +321,7 @@ mod tests {
let tx_a = fake_tx(
20,
&[Some(TxOut::from((p2wpkh_script(8), Sats::from(1_234u64))))],
&[
(p2wpkh_script(9), 2_345),
(p2wpkh_script(10), 3_456),
],
&[(p2wpkh_script(9), 2_345), (p2wpkh_script(10), 3_456)],
);
let tx_b = fake_tx(
21,
@@ -335,11 +334,41 @@ mod tests {
store.insert(tx_a, entry_a);
store.insert(tx_b, entry_b);
let total_after_both: u32 = store.live_histogram().iter().sum();
let total_after_both: u32 = store.live_eligible_histogram().iter().sum();
assert_eq!(total_after_both, 3, "two outputs + one output");
store.remove_by_prefix(&prefix_a);
let total_after_remove: u32 = store.live_histogram().iter().sum();
let total_after_remove: u32 = store.live_eligible_histogram().iter().sum();
assert_eq!(total_after_remove, 1);
}
#[test]
fn raw_histogram_bins_outputs_the_eligible_filter_drops() {
let mut store = TxStore::default();
// 2_345 sats is a round-dollar-eligible payment; 100_000_000 sats (1 BTC)
// is a round-BTC value the eligible filter drops but raw still bins.
let tx = fake_tx(
30,
&[Some(TxOut::from((p2wpkh_script(1), Sats::from(50_000u64))))],
&[(p2wpkh_script(2), 2_345), (p2wpkh_script(3), 100_000_000)],
);
let entry = entry_for(&tx, 100, 100);
let prefix = entry.txid_prefix();
store.insert(tx, entry);
assert_eq!(
store.live_eligible_histogram().iter().sum::<u32>(),
1,
"round-BTC output filtered out of the eligible histogram"
);
assert_eq!(
store.live_raw_histogram().iter().sum::<u32>(),
2,
"raw histogram bins every output"
);
store.remove_by_prefix(&prefix);
assert_eq!(store.live_eligible_histogram().iter().sum::<u32>(), 0);
assert_eq!(store.live_raw_histogram().iter().sum::<u32>(), 0);
}
}
+55 -39
View File
@@ -1,8 +1,8 @@
# brk_oracle
**Version 2**
**Version 3**
Pure on-chain BTC/USD price oracle. No exchange feeds, no external APIs. Derives the bitcoin price from transaction data alone. Tracks block by block from height 525,000 (May 2018) onward.
Pure on-chain BTC/USD price oracle. No exchange feeds, no external APIs. Derives the bitcoin price from transaction data alone. Tracks block by block from height 340,000 (January 2015) onward.
Inspired by [UTXOracle](https://utxo.live/oracle/) by [@SteveSimple](https://x.com/SteveSimple), which proved the concept. brk_oracle takes the same core insight and redesigns the algorithm for per-block resolution and rolling operation. See [comparison](#comparison-with-utxoracle) below.
@@ -42,13 +42,13 @@ The spacing between spikes is constant (set by the ratios between dollar amounts
## How it works
The oracle tracks the price incrementally, block by block, starting from a known seed price. Each new block nudges the estimate. The search window is narrow (about ±10 bins, or ±12%), so the oracle can only follow gradual movement — it cannot jump to an arbitrary price from scratch. This is by design: it makes the algorithm resistant to noise.
The oracle tracks the price incrementally, block by block, starting from a known seed price. Each new block nudges the estimate. The search window is narrow (about 12 bins, or +15% / -12% in price), so the oracle can only follow gradual movement, not jump to an arbitrary price from scratch. This is by design: it makes the algorithm resistant to noise.
For each new block:
### 1. Filter outputs
Skip the coinbase transaction, and skip every output of a transaction carrying an `OP_RETURN`: that transaction is protocol machinery, not a dollar-denominated payment, so its payout amounts are not price signal. Then exclude noisy outputs: script types dominated by protocol activity (P2TR by default), dust below 1,000 sats, and round BTC amounts (0.01, 0.1, 1.0 BTC, etc.) that create false spikes unrelated to dollar purchases.
Skip the coinbase transaction, and skip every output of a transaction carrying an `OP_RETURN`: that transaction is protocol machinery, not a dollar-denominated payment, so its payout amounts are not price signal. Below height 630,000, also skip every output of a transaction with more than 100 outputs: a large fan-out is a batch payout (exchange sweep, mixer), not a round-dollar payment, and the thin early signal needs it removed. Then exclude noisy outputs: script types dominated by protocol activity (P2TR by default), dust below 1,000 sats, and round BTC amounts (0.01, 0.1, 1.0 BTC, etc.) that create false spikes unrelated to dollar purchases.
### 2. Build a log-scale histogram
@@ -87,7 +87,7 @@ The fixed ratios between round-dollar amounts ($1, $2, $3, $5, ... $10,000) crea
The oracle slides this stencil across the EMA histogram within the search window. At each candidate position:
1. **Read** the EMA value at all 19 expected spike locations
2. **Normalize** each value by dividing by that offset's peak within the search window this gives rare amounts like $3 equal voting weight to common amounts like $100
2. **Normalize** each value by dividing by that offset's peak within the search window: this gives rare amounts like $3 equal voting weight to common amounts like $100
3. **Sum** the 19 normalized values into a single score
The position with the highest score is where the fingerprint best matches the histogram.
@@ -102,7 +102,7 @@ A $100 purchase at price P produces `$100 / P × 10⁸` sats, which lands in bin
= (10 log₁₀(P)) × 200
```
So the stencil's winning position the bin where $100 purchases land directly encodes the price:
So the stencil's winning position, the bin where $100 purchases land, directly encodes the price:
```
price = 10^(10 bin / 200) dollars
@@ -122,9 +122,9 @@ Parabolic interpolation between the best bin and its two neighbors refines the e
The oracle consumes one pre-built histogram per block via `process_histogram(&hist)`, a `[u32; 2400]` bin-count array, and returns the updated reference bin.
The caller does the filtering when it builds the histogram. For each block it skips the coinbase, drops every output of a transaction carrying an `OP_RETURN`, then bins the rest. `default_eligible_bin(sats, output_type)` (or `Oracle::output_to_bin` for a non-default `Config`) applies the per-output rules: excluded script types, dust, and round-BTC values. It returns the bin index, or `None` for a filtered output.
The caller filters as it builds the histogram, applying the [step 1](#1-filter-outputs) rules. Two helpers are exported for this: `eligible_bin(sats, output_type)` returns an output's bin index, or `None` if filtered, and `for_each_round_dollar_bin` wraps it with the per-transaction drops (coinbase, OP_RETURN, the >100-output cap below height 630,000) for callers holding a whole transaction's outputs.
The initial seed must be close to the real price at the starting height. The crate includes a `PRICES` constant with exchange prices for every height up to 630,000 to derive a seed from.
The initial seed must be close to the real price at the starting height. The crate includes a `PRICES` constant with exchange prices for heights 0..340,000. Its last entry, height 339,999 (one below `START_HEIGHT_SLOW`), seeds the oracle's first on-chain computation at height 340,000.
## Configuration
@@ -134,10 +134,12 @@ All parameters via `Config` with sensible defaults:
|-----------|---------|---------|
| `alpha` | 2/7 | EMA decay rate (~6-block span) |
| `window_size` | 12 | Ring buffer depth in blocks |
| `search_below` / `search_above` | 9 / 11 | Search window around previous estimate (bins) |
| `min_sats` | 1,000 | Dust threshold |
| `exclude_common_round_values` | true | Filter d × 10ⁿ (d ∈ {1,2,3,5,6}) to prevent false stencil matches |
| `excluded_output_types` | P2TR | Script types dominated by protocol activity |
| `search_below` / `search_above` | 12 / 11 | Search window around previous estimate (bins) |
| `shape_weight` | 0 | Shape-anchoring restoring-force weight. 0 disables it. `Config::slow()` sets 8 for the cold-start |
The output-filtering rules (1,000-sat dust floor, excluded P2TR, round-BTC exclusion) are not `Config` parameters: they are constants in the `filter` module so the indexer, per-request reconstruction, and mempool all bin identically. See [Input](#input).
Between heights 340,000 and 508,000 the oracle runs a slower cold-start configuration (`Config::slow()`: `alpha` = 0.10, ~19-block span, `window_size` = 40, `shape_weight` = 8). In the thin pre-2018 output mix the fast default octave-locks onto the round-dollar half-price pattern, so the slow EMA and the shape-anchoring restoring force resist that drift. At 508,000 `Oracle::reconfigure` switches to the defaults above (`shape_weight` back to 0), and `Config::for_height` returns the right one for any height.
## Comparison with UTXOracle
@@ -145,35 +147,36 @@ All parameters via `Config` with sensible defaults:
| | brk_oracle | UTXOracle |
|---|---|---|
| Resolution | Per-block (~10 min) + daily candles | Per-run consensus price + per-output intraday scatter |
| Resolution | Per-block (~10 min); daily OHLC built downstream | Per-run consensus price + per-output intraday scatter |
| Operation | Rolling: EMA over ring buffer, updates each block | Batch: processes a full day from scratch, stateless |
| Algorithm | Single-pass stencil scoring with per-offset normalization | Multi-step: dual stencil → rough estimate → output-to-USD mapping → iterative convergence |
| Steps to compute price | 7 (filter+bin → ring insert → EMA → per-offset peaks → score → argmax+parabolic → bin→price) | 10 (filter+bin → clip → smooth round BTC → sum → normalize → cap extremes → dual-stencil slide → neighbor weight-avg → output-to-USD map → iterative central price) |
| Stencil | 19 round-USD offsets ($1 to $10k), each normalized to its own peak | 803-point Gaussian + weighted spike template targeting 17 round-USD amounts |
| Round BTC handling | Excluded from histogram entirely | Histogram bins smoothed by averaging neighbors |
| Output filtering | Per-tx OP_RETURN drop, then per-output: script type, dust threshold, round BTC | Per-tx: exactly 2 outputs, ≤5 inputs, no same-day inputs, ≤500-byte witness |
| Validated from | Height 525,000 (May 2018) | December 2023 |
| Output filtering | Per-tx OP_RETURN drop, then per-output: script type, dust threshold, round BTC | Per-tx: not coinbase, no OP_RETURN, exactly 2 outputs, ≤5 inputs, no same-day inputs, ≤500-byte witness |
| Validated from | Height 340,000 (January 2015) | Dec 15, 2023 |
| Language | Rust | Python |
| Dependencies | None (pure computation, caller provides block data) | Bitcoin Core RPC |
| Dependencies | None (pure computation, caller provides block data) | bitcoin-cli + direct blk file reads |
| Bins per decade | 200 | 200 |
## Accuracy
Tested over 411,251 blocks (heights 525,000 to 949,800, as of May 2026) against exchange OHLC data. Error is measured per block as distance from the oracle estimate to the exchange high/low range at that height. If the oracle falls within the range, the error is zero.
Tested over 596,251 blocks (heights 340,000 to 950,800, as of May 2026) against exchange OHLC data. Error is measured per block as distance from the oracle estimate to the exchange high/low range at that height. If the oracle falls within the range, the error is zero.
### Per-block
| Metric | Value |
|--------|-------|
| Median error | 0.11% |
| 95th percentile | 0.67% |
| 99th percentile | 1.7% |
| 99.9th percentile | 5.4% |
| RMSE | 0.50% |
| Max error | 33.4% |
| Bias | +0.00 bins (essentially zero) |
| Blocks > 5% error | 472 (0.11%) |
| Blocks > 10% error | 177 |
| Blocks > 20% error | 3 |
| Median error | 0.15% |
| 95th percentile | 1.2% |
| 99th percentile | 3.4% |
| 99.9th percentile | 15.6% |
| RMSE | 0.97% |
| Max error | 33.8% |
| Bias | +0.05 bins (essentially zero) |
| Blocks > 5% error | 3,235 (0.543%) |
| Blocks > 10% error | 1,324 |
| Blocks > 20% error | 154 |
### Daily candles
@@ -181,36 +184,49 @@ Oracle daily OHLC built from per-block prices vs exchange daily OHLC:
| | Median | RMSE | Max |
|-------|--------|------|-----|
| Open | 0.21% | 0.65% | 15.3% |
| High | 0.53% | 1.12% | 28.0% |
| Low | 0.51% | 1.38% | 19.7% |
| Close | 0.24% | 0.73% | 15.4% |
| Open | 0.24% | 1.07% | 29.1% |
| High | 0.58% | 1.48% | 27.3% |
| Low | 0.53% | 1.95% | 55.1% |
| Close | 0.27% | 1.18% | 29.2% |
### By year
| Year | Blocks | Median | RMSE | Max | >5% | >10% | >20% | Price range |
|------|--------|--------|------|-----|-----|------|------|-------------|
| 2018 | 31,492 | 0.21% | 1.11% | 33.4% | 169 | 109 | 3 | $3,129$8,488 |
| 2019 | 54,272 | 0.16% | 0.69% | 17.4% | 165 | 53 | 0 | $3,338$13,868 |
| 2020 | 53,102 | 0.10% | 0.44% | 12.6% | 70 | 6 | 0 | $3,858$29,322 |
| 2021 | 52,733 | 0.07% | 0.47% | 14.4% | 42 | 9 | 0 | $27,678$69,000 |
| 2015 | 51,249 | 0.26% | 1.67% | 33.8% | 916 | 449 | 25 | $198$500 |
| 2016 | 54,753 | 0.33% | 0.80% | 16.9% | 150 | 33 | 0 | $351$989 |
| 2017 | 55,959 | 0.45% | 2.05% | 28.6% | 1,527 | 606 | 67 | $0$19,892 |
| 2018 | 54,531 | 0.18% | 1.31% | 31.6% | 411 | 207 | 62 | $3,129$17,178 |
| 2019 | 54,272 | 0.16% | 0.59% | 17.4% | 100 | 16 | 0 | $3,338$13,868 |
| 2020 | 53,102 | 0.10% | 0.42% | 11.6% | 61 | 3 | 0 | $3,858$29,322 |
| 2021 | 52,733 | 0.07% | 0.47% | 14.4% | 43 | 10 | 0 | $27,678$69,000 |
| 2022 | 53,230 | 0.07% | 0.32% | 6.8% | 10 | 0 | 0 | $15,460$48,240 |
| 2023 | 54,032 | 0.10% | 0.25% | 6.6% | 5 | 0 | 0 | $16,490$44,700 |
| 2024 | 53,367 | 0.10% | 0.28% | 6.7% | 7 | 0 | 0 | $38,555$108,298 |
| 2024 | 53,367 | 0.10% | 0.28% | 7.1% | 8 | 0 | 0 | $38,555$108,298 |
| 2025 | 53,113 | 0.11% | 0.25% | 5.8% | 4 | 0 | 0 | $74,409$126,198 |
| 2026 | 5,910 | 0.11% | 0.27% | 3.2% | 0 | 0 | 0 | $60,000$97,900 |
| 2026 | 5,910 | 0.10% | 0.27% | 3.2% | 0 | 0 | 0 | $60,000$97,900 |
The oracle is only as good as the signal it reads. The largest errors cluster in late 2018: the November price crash fell faster than the narrow search window could follow (33% max error), and on-chain volume was lower then, so the round-dollar pattern was weaker (1.1% RMSE for the year). By 2020 the signal is strong enough for 0.1% median accuracy, and since 2022 no block exceeds 10% error.
The oracle is only as good as the signal it reads. The largest errors cluster in the early cold-start, where thin 2015 on-chain volume gives a weaker round-dollar pattern: the 33.8% max error sits at height 341,498 (oracle ~$287 vs exchange ~$213) during the first weeks of warm-up. A second cluster sits just below the 508,000 regime switch, where the slow EMA lagged the fast early-2018 rally (~31.6% at height 507,278, oracle ~$6,685 vs exchange ~$8,800) before handing off to the fast default. The thin pre-2018 mix means 2015, 2017, and 2018 carry the bulk of the error (1.67%, 2.05%, and 1.31% RMSE). From 2019 the signal strengthens: by 2020 the oracle reaches 0.1% median accuracy, and since 2022 no block exceeds 10% error.
### Why no outlier smoothing?
Post-hoc smoothing for example, correcting any block whose price deviates more than 5% from both its neighbors would improve the aggregate numbers. This is deliberately not done, for two reasons:
Post-hoc smoothing, for example correcting any block whose price deviates more than 5% from both its neighbors, would improve the aggregate numbers. This is deliberately not done, for two reasons:
1. **Simplicity**: The oracle is a single forward pass with no lookback corrections. Adding smoothing means defining thresholds, neighbor windows, and replacement strategies, all of which add complexity for marginal gain.
2. **Finality**: Each block's price is produced once and never revised (unless the block itself is reorged). Downstream consumers can treat the oracle output as append-only. Smoothing would require retroactively changing already-published prices, breaking that property.
## Changelog
### v3
Changes from v2:
- **Earlier start with a cold-start regime**: on-chain tracking begins at height 340,000 (January 2015) instead of 525,000, adding about 185,000 blocks of history. Below height 508,000 the oracle runs a slower EMA (`Config::slow()`, ~19-block span, window 40) paired with a shape-anchoring restoring force (`shape_weight` 8) that pulls candidate scores toward a slowly-adapted profile of the round-dollar arm shape, resisting the half-price octave drift the fast default locks onto in the thinner pre-2018 output mix. At height 508,000 it switches to the fast default via `Oracle::reconfigure`, which restores `shape_weight` to 0 and turns the force off.
- **Max-outputs filter**: a transaction with more than 100 outputs is dropped from the histogram below height 630,000. Large fan-outs (exchange sweeps, mixer payouts) are batch machinery, not round-dollar payments, and the thin 2018-2020 signal needs them removed to stay locked onto the pattern. Above 630,000 on-chain volume is dense enough that the cap removes more genuine signal than noise, so it is lifted.
- **Wider up-reach**: `search_below` raised from 9 to 12 bins. The sharp 2018 reversal candles need extra room to follow a fast move upward in price.
`VERSION` is bumped to 3 so downstream consumers invalidate prices computed by an earlier algorithm.
### v2
Changes from v1:
@@ -1,295 +0,0 @@
//! Compare specific digit filter configurations across multiple start heights.
//!
//! Run with: cargo run -p brk_oracle --example compare_digits --release
use std::path::PathBuf;
use std::time::Instant;
use brk_indexer::Indexer;
use brk_oracle::{Config, Histogram, NUM_BINS, Oracle, PRICES, cents_to_bin, sats_to_bin};
use brk_types::{OutputType, Sats, TxIndex, TxOutIndex};
use vecdb::{AnyVec, ReadableVec, VecIndex};
const BINS_5PCT: f64 = 4.24;
const BINS_10PCT: f64 = 8.28;
const BINS_20PCT: f64 = 15.84;
fn bins_to_pct(bins: f64) -> f64 {
(10.0_f64.powf(bins / 200.0) - 1.0) * 100.0
}
fn seed_bin(start_height: usize) -> f64 {
let price: f64 = PRICES
.lines()
.nth(start_height - 1)
.expect("prices.txt too short")
.parse()
.expect("Failed to parse seed price");
cents_to_bin(price * 100.0)
}
fn leading_digit(sats: u64) -> u8 {
let log = (sats as f64).log10();
let magnitude = 10.0_f64.powf(log.floor());
let d = (sats as f64 / magnitude).round() as u8;
if d >= 10 { 1 } else { d }
}
fn is_round(sats: u64) -> bool {
let log = (sats as f64).log10();
let magnitude = 10.0_f64.powf(log.floor());
let leading = (sats as f64 / magnitude).round();
let round_val = leading * magnitude;
(sats as f64 - round_val).abs() <= round_val * 0.001
}
struct Stats {
total_sq_err: f64,
total_bias: f64,
max_err: f64,
total_blocks: u64,
gt_5pct: u64,
gt_10pct: u64,
gt_20pct: u64,
}
impl Stats {
fn new() -> Self {
Self {
total_sq_err: 0.0,
total_bias: 0.0,
max_err: 0.0,
total_blocks: 0,
gt_5pct: 0,
gt_10pct: 0,
gt_20pct: 0,
}
}
fn update(&mut self, err: f64) {
self.total_sq_err += err * err;
self.total_bias += err;
self.total_blocks += 1;
let abs_err = err.abs();
if abs_err > self.max_err {
self.max_err = abs_err;
}
if abs_err > BINS_5PCT {
self.gt_5pct += 1;
}
if abs_err > BINS_10PCT {
self.gt_10pct += 1;
}
if abs_err > BINS_20PCT {
self.gt_20pct += 1;
}
}
fn rmse_pct(&self) -> f64 {
bins_to_pct((self.total_sq_err / self.total_blocks as f64).sqrt())
}
fn max_pct(&self) -> f64 {
bins_to_pct(self.max_err)
}
fn bias(&self) -> f64 {
self.total_bias / self.total_blocks as f64
}
}
fn main() {
let t0 = Instant::now();
let data_dir = std::env::var("BRK_DIR")
.map(PathBuf::from)
.unwrap_or_else(|_| {
let home = std::env::var("HOME").unwrap();
PathBuf::from(home).join(".brk")
});
let indexer = Indexer::forced_import(&data_dir).expect("Failed to load indexer");
let total_heights = indexer.vecs.blocks.timestamp.len();
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let height_ohlc: Vec<[f64; 4]> = serde_json::from_str(
&std::fs::read_to_string(format!("{manifest_dir}/examples/height_price_ohlc.json"))
.expect("Failed to read height_price_ohlc.json"),
)
.expect("Failed to parse height OHLC");
let height_bands: Vec<(f64, f64)> = height_ohlc
.iter()
.map(|ohlc| {
let high = ohlc[1];
let low = ohlc[2];
if high > 0.0 && low > 0.0 {
(cents_to_bin(high * 100.0), cents_to_bin(low * 100.0))
} else {
(0.0, 0.0)
}
})
.collect();
// Configs to compare.
// 987654321
let masks: &[(u16, &str)] = &[
(0b0_0111_0111, "{1,2,3,5,6,7}"),
(0b0_0011_0111, "{1,2,3,5,6}"),
(0b0_0001_1111, "{1,2,3,4,5}"),
(0b0_0001_0111, "{1,2,3,5}"),
];
let start_heights: &[usize] = &[575_000, 600_000, 630_000];
// (mask_idx, start_idx) -> (Oracle, Stats)
let n = masks.len() * start_heights.len();
let mut oracles: Vec<Option<Oracle>> = (0..n).map(|_| None).collect();
let mut stats: Vec<Stats> = (0..n).map(|_| Stats::new()).collect();
let idx = |m: usize, s: usize| -> usize { m * start_heights.len() + s };
let total_txs = indexer.vecs.transactions.txid.len();
let total_outputs = indexer.vecs.outputs.value.len();
let first_tx_index: Vec<TxIndex> = indexer.vecs.transactions.first_tx_index.collect();
let out_first: Vec<TxOutIndex> = indexer.vecs.outputs.first_txout_index.collect();
let ref_config = Config::default();
let earliest_start = *start_heights.iter().min().unwrap();
for h in earliest_start..total_heights {
let ft = first_tx_index[h];
let next_ft = first_tx_index
.get(h + 1)
.copied()
.unwrap_or(TxIndex::from(total_txs));
let out_start = if ft.to_usize() + 1 < next_ft.to_usize() {
indexer
.vecs
.transactions
.first_txout_index
.collect_one(ft + 1)
.unwrap()
.to_usize()
} else {
out_first
.get(h + 1)
.copied()
.unwrap_or(TxOutIndex::from(total_outputs))
.to_usize()
};
let out_end = out_first
.get(h + 1)
.copied()
.unwrap_or(TxOutIndex::from(total_outputs))
.to_usize();
let values: Vec<Sats> = indexer
.vecs
.outputs
.value
.collect_range_at(out_start, out_end);
let output_types: Vec<OutputType> = indexer
.vecs
.outputs
.output_type
.collect_range_at(out_start, out_end);
// Build full histogram and per-digit histograms.
let mut full_hist = Histogram::zeros();
let mut digit_hist: [Histogram; 9] = std::array::from_fn(|_| Histogram::zeros());
for (sats, output_type) in values.into_iter().zip(output_types) {
if ref_config.excluded_output_types.contains(&output_type) {
continue;
}
if *sats < ref_config.min_sats {
continue;
}
if let Some(bin) = sats_to_bin(sats) {
full_hist.increment(bin);
if is_round(*sats) {
let d = leading_digit(*sats);
if (1..=9).contains(&d) {
digit_hist[(d - 1) as usize].increment(bin);
}
}
}
}
// Feed each (mask, start_height) combo.
for (mi, &(mask, _)) in masks.iter().enumerate() {
// Build filtered histogram for this mask.
let mut hist = full_hist.clone();
(0..9usize).for_each(|d| {
if mask & (1 << d) != 0 {
for bin in 0..NUM_BINS {
hist[bin] -= digit_hist[d][bin];
}
}
});
for (si, &sh) in start_heights.iter().enumerate() {
if h < sh {
continue;
}
let i = idx(mi, si);
if oracles[i].is_none() {
oracles[i] = Some(Oracle::new(
seed_bin(sh),
Config {
exclude_common_round_values: false,
..Default::default()
},
));
}
let ref_bin = oracles[i].as_mut().unwrap().process_histogram(&hist);
if h < height_bands.len() {
let (high_bin, low_bin) = height_bands[h];
if high_bin > 0.0 && low_bin > 0.0 {
let err = if ref_bin < high_bin {
ref_bin - high_bin
} else if ref_bin > low_bin {
ref_bin - low_bin
} else {
0.0
};
stats[i].update(err);
}
}
}
}
}
// Print results grouped by start height.
for (si, &sh) in start_heights.iter().enumerate() {
println!();
println!("@ {}k:", sh / 1000);
println!(
" {:<16} {:>8} {:>10} {:>10} {:>6} {:>6} {:>6} {:>8}",
"Digits", "Blocks", "RMSE%", "Max%", ">5%", ">10%", ">20%", "Bias"
);
println!(" {}", "-".repeat(72));
for (mi, &(_, label)) in masks.iter().enumerate() {
let s = &stats[idx(mi, si)];
println!(
" {:<16} {:>8} {:>7.3}% {:>7.1}% {:>6} {:>6} {:>6} {:>+8.2}",
label,
s.total_blocks,
s.rmse_pct(),
s.max_pct(),
s.gt_5pct,
s.gt_10pct,
s.gt_20pct,
s.bias()
);
}
}
println!("\nDone in {:.1}s", t0.elapsed().as_secs_f64());
}
+132 -133
View File
@@ -1,10 +1,12 @@
//! Verify oracle determinism: oracles started from different heights converge
//! to identical ref_bin values after the ring buffer fills.
//! Verify the production restart property: an oracle restored via
//! `from_checkpoint` (seeded from the previous block's stored cents price,
//! replayed over the last `window_size` blocks) produces bit-exact `ref_bin`
//! values matching a continuously-running oracle from the restart height
//! onward.
//!
//! Creates a reference oracle at height 575k and test oracles every 1000 blocks
//! up to 630k. After window_size blocks, each test oracle should produce the
//! same ref_bin as the reference, proving the truncated EMA provides
//! start-point independence.
//! Mirrors the production filter exactly (per-tx OP_RETURN drop + per-output
//! `eligible_bin`), so it exercises the same code path
//! `brk_computer::prices::compute::feed_blocks` uses at runtime.
//!
//! Run with: cargo run -p brk_oracle --example determinism --release
@@ -12,26 +14,47 @@ use std::path::PathBuf;
use brk_indexer::Indexer;
use brk_oracle::{
Config, Histogram, Oracle, PRICES, START_HEIGHT, cents_to_bin, default_eligible_bin,
Config, HistogramRaw, Oracle, PRICES, START_HEIGHT_FAST, bin_to_cents, cents_to_bin,
for_each_round_dollar_bin,
};
use brk_types::{OutputType, Sats, TxIndex, TxOutIndex};
use vecdb::{AnyVec, ReadableVec, VecIndex};
fn seed_bin(height: usize) -> f64 {
fn seed_bin_for_start_height() -> f64 {
let price: f64 = PRICES
.lines()
.nth(height - 1)
.expect("prices.txt too short")
.nth(START_HEIGHT_FAST - 1)
.expect("prices.txt too short for START_HEIGHT_FAST")
.parse()
.expect("Failed to parse seed price");
cents_to_bin(price * 100.0)
}
struct TestRun {
start_height: usize,
oracle: Option<Oracle>,
converged_at: Option<usize>,
diverged_after: bool,
struct Block {
height: usize,
values: Vec<Sats>,
output_types: Vec<OutputType>,
tx_starts: Vec<usize>,
out_start: usize,
out_end: usize,
}
fn build_histogram(block: &Block) -> HistogramRaw {
let mut hist = HistogramRaw::zeros();
for tx in 0..block.tx_starts.len() {
let lo = block.tx_starts[tx] - block.out_start;
let hi = block
.tx_starts
.get(tx + 1)
.map(|s| s - block.out_start)
.unwrap_or(block.out_end - block.out_start);
let outputs = block.values[lo..hi]
.iter()
.copied()
.zip(block.output_types[lo..hi].iter().copied());
for_each_round_dollar_bin(block.height, outputs, |bin| hist.increment(bin as usize));
}
hist
}
fn main() {
@@ -48,59 +71,50 @@ fn main() {
let config = Config::default();
let window_size = config.window_size;
let restart_offset = 1000;
let end_offset = restart_offset + window_size * 4;
let end_height = (START_HEIGHT_FAST + end_offset).min(total_heights);
let restart_at = START_HEIGHT_FAST + restart_offset;
let warmup_start = restart_at - window_size;
assert!(
end_height > restart_at,
"indexer has {total_heights} blocks; need at least {} to test restart at {restart_at}",
restart_at + 1
);
println!(
"Loading {} blocks ({START_HEIGHT_FAST}..{end_height})...",
end_height - START_HEIGHT_FAST
);
let total_txs = indexer.vecs.transactions.txid.len();
let total_outputs = indexer.vecs.outputs.value.len();
let first_tx_index: Vec<TxIndex> = indexer.vecs.transactions.first_tx_index.collect();
let out_first: Vec<TxOutIndex> = indexer.vecs.outputs.first_txout_index.collect();
let mut txout_cursor = indexer.vecs.transactions.first_txout_index.cursor();
// Reference oracle at 575k.
let ref_start = START_HEIGHT;
let mut ref_oracle = Oracle::new(seed_bin(ref_start), Config::default());
// Test oracles every 1000 blocks from 576k to 630k.
let mut runs: Vec<TestRun> = (576_000..=630_000)
.step_by(1000)
.map(|h| TestRun {
start_height: h,
oracle: None,
converged_at: None,
diverged_after: false,
})
.collect();
let last_start = runs.last().map(|r| r.start_height).unwrap_or(ref_start);
// Process enough blocks for all oracles to converge + verification margin.
let end_height = (last_start + window_size + 100).min(total_heights);
for h in START_HEIGHT..end_height {
let mut blocks: Vec<Block> = Vec::with_capacity(end_height - START_HEIGHT_FAST);
for h in START_HEIGHT_FAST..end_height {
let ft = first_tx_index[h];
let next_ft = first_tx_index
.get(h + 1)
.copied()
.unwrap_or(TxIndex::from(total_txs));
let out_start = if ft.to_usize() + 1 < next_ft.to_usize() {
indexer
.vecs
.transactions
.first_txout_index
.collect_one(ft + 1)
.unwrap()
.to_usize()
} else {
out_first
.get(h + 1)
.copied()
.unwrap_or(TxOutIndex::from(total_outputs))
.to_usize()
};
let block_first_tx = ft.to_usize() + 1;
let tx_count = next_ft.to_usize() - block_first_tx;
let out_end = out_first
.get(h + 1)
.copied()
.unwrap_or(TxOutIndex::from(total_outputs))
.to_usize();
txout_cursor.advance(block_first_tx - txout_cursor.position());
let mut tx_starts: Vec<usize> = Vec::with_capacity(tx_count);
for _ in 0..tx_count {
tx_starts.push(txout_cursor.next().unwrap().to_usize());
}
let out_start = tx_starts.first().copied().unwrap_or(out_end);
let values: Vec<Sats> = indexer
.vecs
.outputs
@@ -112,95 +126,80 @@ fn main() {
.output_type
.collect_range_at(out_start, out_end);
let mut hist = Histogram::zeros();
for (sats, output_type) in values.into_iter().zip(output_types) {
if let Some(bin) = default_eligible_bin(sats, output_type) {
hist.increment(bin as usize);
}
}
let ref_bin = ref_oracle.process_histogram(&hist);
for run in &mut runs {
if h < run.start_height {
continue;
}
if run.oracle.is_none() {
run.oracle = Some(Oracle::new(seed_bin(run.start_height), Config::default()));
}
let test_bin = run.oracle.as_mut().unwrap().process_histogram(&hist);
if run.converged_at.is_some() {
if test_bin != ref_bin {
run.diverged_after = true;
}
} else if test_bin == ref_bin {
run.converged_at = Some(h);
}
}
blocks.push(Block {
height: h,
values,
output_types,
tx_starts,
out_start,
out_end,
});
}
// Print results.
println!();
println!("{:<12} {:>16} {:>8}", "Start", "Converged at", "Blocks");
println!("{}", "-".repeat(40));
let mut max_blocks = 0usize;
let mut failed = Vec::new();
let mut diverged = Vec::new();
for run in &runs {
if let Some(converged) = run.converged_at {
let blocks = converged - run.start_height;
if blocks > max_blocks {
max_blocks = blocks;
}
println!("{:<12} {:>16} {:>8}", run.start_height, converged, blocks);
if run.diverged_after {
diverged.push(run.start_height);
}
} else {
println!("{:<12} {:>16} {:>8}", run.start_height, "NEVER", "-");
failed.push(run.start_height);
}
}
println!();
let mut continuous = Oracle::new(seed_bin_for_start_height(), config.clone());
let continuous_bins: Vec<f64> = blocks
.iter()
.map(|b| continuous.process_histogram(&build_histogram(b)))
.collect();
println!(
"{}/{} converged, max {} blocks to converge (window_size={})",
runs.len() - failed.len(),
runs.len(),
max_blocks,
window_size,
"Continuous oracle: {} blocks processed",
continuous_bins.len()
);
if !diverged.is_empty() {
println!("DIVERGED after convergence: {:?}", diverged);
}
if !failed.is_empty() {
println!("NEVER converged: {:?}", failed);
let prev_bin = continuous_bins[restart_at - START_HEIGHT_FAST - 1];
let seed_bin = cents_to_bin(bin_to_cents(prev_bin) as f64);
println!(
"Restart at {restart_at}: prev_bin={prev_bin:.4} -> cents -> seed_bin={seed_bin:.4} (delta {:.6})",
seed_bin - prev_bin
);
let warmup_slice = &blocks[warmup_start - START_HEIGHT_FAST..restart_at - START_HEIGHT_FAST];
let mut restored = Oracle::from_checkpoint(seed_bin, config.clone(), |o| {
for b in warmup_slice {
o.process_histogram(&build_histogram(b));
}
});
let restored_bins: Vec<f64> = blocks[restart_at - START_HEIGHT_FAST..]
.iter()
.map(|b| restored.process_histogram(&build_histogram(b)))
.collect();
println!("Restored oracle: {} blocks processed", restored_bins.len());
let mut mismatches: Vec<(usize, f64, f64)> = Vec::new();
for (i, &r) in restored_bins.iter().enumerate() {
let c = continuous_bins[restart_at - START_HEIGHT_FAST + i];
if r != c {
mismatches.push((restart_at + i, c, r));
}
}
// Assertions.
assert!(
failed.is_empty(),
"{} oracles never converged: {:?}",
failed.len(),
failed
);
assert!(
diverged.is_empty(),
"{} oracles diverged after convergence: {:?}",
diverged.len(),
diverged
);
assert!(
max_blocks <= window_size * 2,
"Convergence took {} blocks, expected <= {} (2 * window_size)",
max_blocks,
window_size * 2
println!();
if mismatches.is_empty() {
println!(
"All {} blocks from {restart_at} onward match exactly.",
restored_bins.len()
);
} else {
println!(
"{} of {} blocks differ (showing up to 5):",
mismatches.len(),
restored_bins.len()
);
for (h, c, r) in mismatches.iter().take(5) {
println!(
" h={h}: continuous={c:.6}, restored={r:.6}, delta={:.6}",
r - c
);
}
}
assert_eq!(
mismatches.len(),
0,
"restored oracle diverged from continuous oracle"
);
println!();
println!("All assertions passed!");
println!("Assertion passed: from_checkpoint restart is bit-exact.");
}
+132
View File
@@ -0,0 +1,132 @@
//! Dump the RAW per-output data over a height range for fully offline analysis.
//! Nothing is filtered or binned, so any downstream filter (round-BTC tolerance,
//! dust floor, type exclusion, OP_RETURN / batch-payout tx drops, log-bin
//! resolution) can be reconstructed in analysis WITHOUT re-dumping.
//!
//! For every non-coinbase output in [ORACLE_START, ORACLE_END) (default
//! 500000..510000) one row is written:
//! oracle_outputs_{start}_{end}.csv height,tx,sats,otype
//! where `tx` is the 0-based index of the (non-coinbase) transaction within the
//! block (so OP_RETURN-tx and >N-output-tx drops can be reapplied by grouping),
//! `sats` is the exact output value, and `otype` is `OutputType as u8`.
//!
//! Plus per-block metadata:
//! oracle_meta_{start}_{end}.csv height,timestamp,ex_low,ex_high,ex_close
//!
//! Run: cargo run -p brk_oracle --example dump_hist --release
use std::{
fs::File,
io::{BufWriter, Write},
path::PathBuf,
};
use brk_indexer::Indexer;
use brk_types::{OutputType, Sats, TxIndex, TxOutIndex};
use vecdb::{AnyVec, ReadableVec, VecIndex};
fn main() {
let data_dir = std::env::var("BRK_DIR")
.map(PathBuf::from)
.unwrap_or_else(|_| PathBuf::from(std::env::var("HOME").unwrap()).join(".brk"));
let out_dir = std::env::var("DUMP_DIR").unwrap_or_else(|_| "/tmp".to_string());
let start: usize = std::env::var("ORACLE_START")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(500_000);
let end: usize = std::env::var("ORACLE_END")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(510_000);
let indexer = Indexer::forced_import(&data_dir).expect("Failed to load indexer");
let total_heights = indexer.vecs.blocks.timestamp.len();
let end = end.min(total_heights);
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let height_ohlc: Vec<[f64; 4]> = serde_json::from_str(
&std::fs::read_to_string(format!("{manifest_dir}/examples/height_price_ohlc.json"))
.expect("read height_price_ohlc.json"),
)
.expect("parse height OHLC");
let timestamps: Vec<brk_types::Timestamp> = indexer.vecs.blocks.timestamp.collect();
let total_txs = indexer.vecs.transactions.txid.len();
let total_outputs = indexer.vecs.outputs.value.len();
let first_tx_index: Vec<TxIndex> = indexer.vecs.transactions.first_tx_index.collect();
let out_first: Vec<TxOutIndex> = indexer.vecs.outputs.first_txout_index.collect();
let mut txout_cursor = indexer.vecs.transactions.first_txout_index.cursor();
let mut tx_starts: Vec<usize> = Vec::new();
let out_path = format!("{out_dir}/oracle_outputs_{start}_{end}.csv");
let meta_path = format!("{out_dir}/oracle_meta_{start}_{end}.csv");
let mut out_w = BufWriter::new(File::create(&out_path).expect("create outputs csv"));
let mut meta_w = BufWriter::new(File::create(&meta_path).expect("create meta csv"));
writeln!(out_w, "height,tx,sats,otype").unwrap();
writeln!(meta_w, "height,timestamp,ex_low,ex_high,ex_close").unwrap();
eprintln!(
"otype legend: OpReturn={} P2TR={}",
OutputType::OpReturn as u8,
OutputType::P2TR as u8
);
let mut rows: u64 = 0;
for h in start..end {
let ft = first_tx_index[h];
let next_ft = first_tx_index
.get(h + 1)
.copied()
.unwrap_or(TxIndex::from(total_txs));
let block_first_tx = ft.to_usize() + 1; // skip coinbase
let tx_count = next_ft.to_usize() - block_first_tx;
let out_end = out_first
.get(h + 1)
.copied()
.unwrap_or(TxOutIndex::from(total_outputs))
.to_usize();
txout_cursor.advance(block_first_tx - txout_cursor.position());
tx_starts.clear();
for _ in 0..tx_count {
tx_starts.push(txout_cursor.next().unwrap().to_usize());
}
let out_start = tx_starts.first().copied().unwrap_or(out_end);
let values: Vec<Sats> = indexer
.vecs
.outputs
.value
.collect_range_at(out_start, out_end);
let output_types: Vec<OutputType> = indexer
.vecs
.outputs
.output_type
.collect_range_at(out_start, out_end);
for tx in 0..tx_count {
let lo = tx_starts[tx] - out_start;
let hi = tx_starts
.get(tx + 1)
.map(|s| s - out_start)
.unwrap_or(out_end - out_start);
for i in lo..hi {
writeln!(out_w, "{h},{tx},{},{}", *values[i], output_types[i] as u8).unwrap();
rows += 1;
}
}
let o = height_ohlc.get(h).copied().unwrap_or([0.0; 4]);
writeln!(
meta_w,
"{h},{},{:.2},{:.2},{:.2}",
*timestamps[h], o[2], o[1], o[3]
)
.unwrap();
}
out_w.flush().unwrap();
meta_w.flush().unwrap();
eprintln!("wrote {out_path} ({rows} output rows)");
eprintln!("wrote {meta_path}");
}
-272
View File
@@ -1,272 +0,0 @@
//! Diagnostic: sweep oracle start heights and clamp-top-N strategies.
//!
//! Run with: cargo run -p brk_oracle --example noise --release
use std::path::PathBuf;
use std::time::Instant;
use brk_indexer::Indexer;
use brk_oracle::{Config, Histogram, Oracle, PRICES, cents_to_bin, default_eligible_bin};
use brk_types::{Sats, TxIndex, TxOutIndex};
use vecdb::{AnyVec, ReadableVec, VecIndex};
const BINS_5PCT: f64 = 4.24;
const BINS_10PCT: f64 = 8.28;
const BINS_20PCT: f64 = 15.84;
const BPD: f64 = 200.0;
fn bins_to_pct(bins: f64) -> f64 {
(10.0_f64.powf(bins / BPD) - 1.0) * 100.0
}
fn seed_bin(start_height: usize) -> f64 {
let price: f64 = PRICES
.lines()
.nth(start_height - 1)
.expect("prices.txt too short")
.parse()
.expect("Failed to parse seed price");
cents_to_bin(price * 100.0)
}
/// Clamp the top N bins in `src` down to the (N+1)th highest value, writing into `dst`.
fn clamp_top_n(src: &Histogram, dst: &mut Histogram, n: usize) {
let mut top: Vec<u32> = src.iter().copied().filter(|&v| v > 0).collect();
top.sort_unstable_by(|a, b| b.cmp(a));
let clamp_to = if top.len() > n { top[n] } else { 0 };
for (i, &v) in src.iter().enumerate() {
dst[i] = v.min(clamp_to.max(v.min(clamp_to)));
}
}
fn main() {
let t0 = Instant::now();
let data_dir = std::env::var("BRK_DIR")
.map(PathBuf::from)
.unwrap_or_else(|_| {
let home = std::env::var("HOME").unwrap();
PathBuf::from(home).join(".brk")
});
let indexer = Indexer::forced_import(&data_dir).expect("Failed to load indexer");
let total_heights = indexer.vecs.blocks.timestamp.len();
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let height_ohlc: Vec<[f64; 4]> = serde_json::from_str(
&std::fs::read_to_string(format!("{manifest_dir}/examples/height_price_ohlc.json"))
.expect("Failed to read height_price_ohlc.json"),
)
.expect("Failed to parse height OHLC");
let height_bands: Vec<(f64, f64)> = height_ohlc
.iter()
.map(|ohlc| {
let high = ohlc[1];
let low = ohlc[2];
if high > 0.0 && low > 0.0 {
(cents_to_bin(high * 100.0), cents_to_bin(low * 100.0))
} else {
(0.0, 0.0)
}
})
.collect();
// Start heights: 630k, 600k, 575k, then 570k down to 500k by 5k.
let mut start_heights: Vec<usize> = vec![630_000, 600_000, 575_000];
let mut h = 570_000;
while h >= 500_000 {
start_heights.push(h);
h -= 5_000;
}
let lowest = *start_heights.iter().min().unwrap();
// Clamp-top-N values to test: 0 (no clamp), 2, 3, 5, 10.
let clamp_values: Vec<usize> = vec![0, 2, 3, 5, 10];
// Build per-block RAW histograms from the lowest start height.
eprintln!("Building histograms from height {}...", lowest);
let total_txs = indexer.vecs.transactions.txid.len();
let total_outputs = indexer.vecs.outputs.value.len();
let first_txout_index_reader = indexer.vecs.transactions.first_txout_index.reader();
let value_reader = indexer.vecs.outputs.value.reader();
let output_type_reader = indexer.vecs.outputs.output_type.reader();
let config = Config::default();
let total_blocks = total_heights - lowest;
struct BlockData {
hist: Histogram,
high_bin: f64,
low_bin: f64,
}
let mut blocks: Vec<BlockData> = Vec::with_capacity(total_blocks);
for h in lowest..total_heights {
let first_tx_index: TxIndex = indexer
.vecs
.transactions
.first_tx_index
.collect_one_at(h)
.unwrap();
let next_first_tx_index: TxIndex = indexer
.vecs
.transactions
.first_tx_index
.collect_one_at(h + 1)
.unwrap_or(TxIndex::from(total_txs));
let out_start = if first_tx_index.to_usize() + 1 < next_first_tx_index.to_usize() {
first_txout_index_reader
.get(first_tx_index.to_usize() + 1)
.to_usize()
} else {
indexer
.vecs
.outputs
.first_txout_index
.collect_one_at(h + 1)
.unwrap_or(TxOutIndex::from(total_outputs))
.to_usize()
};
let out_end: usize = indexer
.vecs
.outputs
.first_txout_index
.collect_one_at(h + 1)
.unwrap_or(TxOutIndex::from(total_outputs))
.to_usize();
let mut hist = Histogram::zeros();
for i in out_start..out_end {
let sats: Sats = value_reader.get(i);
let output_type = output_type_reader.get(i);
if let Some(bin) = default_eligible_bin(sats, output_type) {
hist.increment(bin as usize);
}
}
let (high_bin, low_bin) = if h < height_bands.len() {
height_bands[h]
} else {
(0.0, 0.0)
};
blocks.push(BlockData {
hist,
high_bin,
low_bin,
});
if (h - lowest).is_multiple_of(50_000) {
eprint!(
"\r {}/{} ({:.0}%)",
h - lowest,
total_blocks,
(h - lowest) as f64 / total_blocks as f64 * 100.0
);
}
}
eprintln!(
"\r {} blocks built in {:.1}s",
blocks.len(),
t0.elapsed().as_secs_f64()
);
// For each clamp value, run all start heights.
for &clamp_n in &clamp_values {
println!();
let label = if clamp_n == 0 {
"no clamp".to_string()
} else {
format!("clamp top {}", clamp_n)
};
println!("=== {} ===", label);
println!(
"{:>8} {:>8} {:>8} {:>8} {:>6} {:>6} {:>6} {:>8}",
"Start", "Blocks", "RMSE%", "Worst%", ">5%", ">10%", ">20%", "Worst@"
);
println!("{}", "-".repeat(72));
for &start_height in &start_heights {
let mut oracle = Oracle::new(seed_bin(start_height), config.clone());
let block_offset = start_height - lowest;
let mut worst_err: f64 = 0.0;
let mut worst_height: usize = 0;
let mut gt_5: u64 = 0;
let mut gt_10: u64 = 0;
let mut gt_20: u64 = 0;
let mut total_sq_err: f64 = 0.0;
let mut total_measured: u64 = 0;
let mut clamped_hist = Histogram::zeros();
for (i, bd) in blocks[block_offset..].iter().enumerate() {
if clamp_n > 0 {
clamp_top_n(&bd.hist, &mut clamped_hist, clamp_n);
oracle.process_histogram(&clamped_hist);
} else {
oracle.process_histogram(&bd.hist);
}
let height = start_height + i;
let ref_bin = oracle.ref_bin();
if bd.high_bin <= 0.0 || bd.low_bin <= 0.0 {
continue;
}
let err = if ref_bin < bd.high_bin {
ref_bin - bd.high_bin
} else if ref_bin > bd.low_bin {
ref_bin - bd.low_bin
} else {
0.0
};
total_measured += 1;
total_sq_err += err * err;
let abs_err = err.abs();
if abs_err > BINS_5PCT {
gt_5 += 1;
}
if abs_err > BINS_10PCT {
gt_10 += 1;
}
if abs_err > BINS_20PCT {
gt_20 += 1;
}
if abs_err > worst_err {
worst_err = abs_err;
worst_height = height;
}
}
let rmse = if total_measured > 0 {
bins_to_pct((total_sq_err / total_measured as f64).sqrt())
} else {
0.0
};
println!(
"{:>8} {:>8} {:>7.3}% {:>7.1}% {:>6} {:>6} {:>6} {}",
format!("{}k", start_height / 1000),
total_measured,
rmse,
bins_to_pct(worst_err),
gt_5,
gt_10,
gt_20,
worst_height,
);
}
}
println!("\nTotal time: {:.1}s", t0.elapsed().as_secs_f64());
}
+7 -7
View File
@@ -6,8 +6,8 @@ use std::path::PathBuf;
use brk_indexer::Indexer;
use brk_oracle::{
Config, Histogram, Oracle, PRICES, START_HEIGHT, bin_to_cents, cents_to_bin,
default_eligible_bin,
Config, HistogramRaw, Oracle, PRICES, START_HEIGHT_FAST, bin_to_cents, cents_to_bin,
eligible_bin,
};
use brk_types::{OutputType, Sats, TxIndex, TxOutIndex};
use vecdb::{AnyVec, ReadableVec, VecIndex};
@@ -174,7 +174,7 @@ fn main() {
let start_price: f64 = PRICES
.lines()
.nth(START_HEIGHT - 1)
.nth(START_HEIGHT_FAST - 1)
.expect("prices.txt too short")
.parse()
.expect("Failed to parse seed price");
@@ -201,7 +201,7 @@ fn main() {
let mut oracle_candles: Vec<DayCandle> = Vec::new();
let mut current_di: Option<usize> = None;
for h in START_HEIGHT..total_heights {
for h in START_HEIGHT_FAST..total_heights {
let ft = first_tx_index[h];
let next_ft = first_tx_index
.get(h + 1)
@@ -236,7 +236,7 @@ fn main() {
.collect_range_at(out_start, out_end);
// Drop every output of a tx carrying an OP_RETURN (protocol machinery).
let mut hist = Histogram::zeros();
let mut hist = HistogramRaw::zeros();
for tx in 0..tx_count {
let lo = tx_starts[tx] - out_start;
let hi = tx_starts
@@ -247,7 +247,7 @@ fn main() {
continue;
}
for i in lo..hi {
if let Some(bin) = default_eligible_bin(values[i], output_types[i]) {
if let Some(bin) = eligible_bin(values[i], output_types[i]) {
hist.increment(bin as usize);
}
}
@@ -376,7 +376,7 @@ fn main() {
println!(" Config: w12, alpha=2/7, search -9/+11, noisy/dust/round-btc filtered");
println!(
" Test range: height {} .. {} ({} blocks)",
START_HEIGHT,
START_HEIGHT_FAST,
total_heights - 1,
overall.total_blocks
);
File diff suppressed because it is too large Load Diff
-416
View File
@@ -1,416 +0,0 @@
//! Sweep round-value digit filter to find optimal configuration.
//!
//! Tests all 512 subsets of leading digits {1,...,9} to find which
//! digits to filter out for best oracle accuracy.
//!
//! Phase 1: single pass over indexer, precompute per-block histograms.
//! Phase 2: run 512 configs in parallel across CPU cores.
//!
//! Run with: cargo run -p brk_oracle --example sweep_digits --release
use std::path::PathBuf;
use std::time::Instant;
use brk_indexer::Indexer;
use brk_oracle::{Config, Histogram, Oracle, PRICES, cents_to_bin, sats_to_bin};
use brk_types::{OutputType, Sats, TxIndex, TxOutIndex};
use vecdb::{AnyVec, ReadableVec, VecIndex};
const BINS_5PCT: f64 = 4.24;
const BINS_10PCT: f64 = 8.28;
const BINS_20PCT: f64 = 15.84;
fn bins_to_pct(bins: f64) -> f64 {
(10.0_f64.powf(bins / 200.0) - 1.0) * 100.0
}
fn seed_bin(start_height: usize) -> f64 {
let price: f64 = PRICES
.lines()
.nth(start_height - 1)
.expect("prices.txt too short")
.parse()
.expect("Failed to parse seed price");
cents_to_bin(price * 100.0)
}
fn leading_digit(sats: u64) -> u8 {
let log = (sats as f64).log10();
let magnitude = 10.0_f64.powf(log.floor());
let d = (sats as f64 / magnitude).round() as u8;
if d >= 10 { 1 } else { d }
}
fn is_round(sats: u64) -> bool {
let log = (sats as f64).log10();
let magnitude = 10.0_f64.powf(log.floor());
let leading = (sats as f64 / magnitude).round();
let round_val = leading * magnitude;
(sats as f64 - round_val).abs() <= round_val * 0.001
}
fn mask_label(mask: u16) -> String {
let digits: String = (1..=9u8)
.filter(|&d| mask & (1 << (d - 1)) != 0)
.map(|d| char::from_digit(d as u32, 10).unwrap())
.collect();
if digits.is_empty() {
"none".to_string()
} else {
digits
}
}
struct Stats {
total_sq_err: f64,
total_bias: f64,
max_err: f64,
total_blocks: u64,
gt_5pct: u64,
gt_10pct: u64,
gt_20pct: u64,
}
impl Stats {
fn new() -> Self {
Self {
total_sq_err: 0.0,
total_bias: 0.0,
max_err: 0.0,
total_blocks: 0,
gt_5pct: 0,
gt_10pct: 0,
gt_20pct: 0,
}
}
fn update(&mut self, err: f64) {
self.total_sq_err += err * err;
self.total_bias += err;
self.total_blocks += 1;
let abs_err = err.abs();
if abs_err > self.max_err {
self.max_err = abs_err;
}
if abs_err > BINS_5PCT {
self.gt_5pct += 1;
}
if abs_err > BINS_10PCT {
self.gt_10pct += 1;
}
if abs_err > BINS_20PCT {
self.gt_20pct += 1;
}
}
fn rmse_pct(&self) -> f64 {
bins_to_pct((self.total_sq_err / self.total_blocks as f64).sqrt())
}
fn max_pct(&self) -> f64 {
bins_to_pct(self.max_err)
}
fn bias(&self) -> f64 {
self.total_bias / self.total_blocks as f64
}
}
struct BlockData {
full_hist: Histogram,
/// (bin_index, leading_digit) for outputs that are round values.
round_outputs: Vec<(u16, u8)>,
high_bin: f64,
low_bin: f64,
}
fn main() {
let t0 = Instant::now();
let data_dir = std::env::var("BRK_DIR")
.map(PathBuf::from)
.unwrap_or_else(|_| {
let home = std::env::var("HOME").unwrap();
PathBuf::from(home).join(".brk")
});
let indexer = Indexer::forced_import(&data_dir).expect("Failed to load indexer");
let total_heights = indexer.vecs.blocks.timestamp.len();
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let height_ohlc: Vec<[f64; 4]> = serde_json::from_str(
&std::fs::read_to_string(format!("{manifest_dir}/examples/height_price_ohlc.json"))
.expect("Failed to read height_price_ohlc.json"),
)
.expect("Failed to parse height OHLC");
let height_bands: Vec<(f64, f64)> = height_ohlc
.iter()
.map(|ohlc| {
let high = ohlc[1];
let low = ohlc[2];
if high > 0.0 && low > 0.0 {
(cents_to_bin(high * 100.0), cents_to_bin(low * 100.0))
} else {
(0.0, 0.0)
}
})
.collect();
let sweep_start: usize = 575_000;
// Phase 1: precompute per-block data in a single pass over the indexer.
eprintln!("Phase 1: precomputing block data...");
let total_txs = indexer.vecs.transactions.txid.len();
let total_outputs = indexer.vecs.outputs.value.len();
let first_tx_index: Vec<TxIndex> = indexer.vecs.transactions.first_tx_index.collect();
let out_first: Vec<TxOutIndex> = indexer.vecs.outputs.first_txout_index.collect();
let ref_config = Config::default();
let total_blocks = total_heights - sweep_start;
let mut blocks: Vec<BlockData> = Vec::with_capacity(total_blocks);
for h in sweep_start..total_heights {
let ft = first_tx_index[h];
let next_ft = first_tx_index
.get(h + 1)
.copied()
.unwrap_or(TxIndex::from(total_txs));
let out_start = if ft.to_usize() + 1 < next_ft.to_usize() {
indexer
.vecs
.transactions
.first_txout_index
.collect_one(ft + 1)
.unwrap()
.to_usize()
} else {
out_first
.get(h + 1)
.copied()
.unwrap_or(TxOutIndex::from(total_outputs))
.to_usize()
};
let out_end = out_first
.get(h + 1)
.copied()
.unwrap_or(TxOutIndex::from(total_outputs))
.to_usize();
let values: Vec<Sats> = indexer
.vecs
.outputs
.value
.collect_range_at(out_start, out_end);
let output_types: Vec<OutputType> = indexer
.vecs
.outputs
.output_type
.collect_range_at(out_start, out_end);
let mut full_hist = Histogram::zeros();
let mut round_outputs = Vec::new();
for (sats, output_type) in values.into_iter().zip(output_types) {
if ref_config.excluded_output_types.contains(&output_type) {
continue;
}
if *sats < ref_config.min_sats {
continue;
}
if let Some(bin) = sats_to_bin(sats) {
full_hist.increment(bin);
if is_round(*sats) {
let d = leading_digit(*sats);
if (1..=9).contains(&d) {
round_outputs.push((bin as u16, d));
}
}
}
}
let (high_bin, low_bin) = if h < height_bands.len() {
height_bands[h]
} else {
(0.0, 0.0)
};
blocks.push(BlockData {
full_hist,
round_outputs,
high_bin,
low_bin,
});
if (h - sweep_start).is_multiple_of(50_000) {
eprint!(
"\r {}/{} ({:.0}%)",
h - sweep_start,
total_blocks,
(h - sweep_start) as f64 / total_blocks as f64 * 100.0
);
}
}
let mem_hists = blocks.len() * std::mem::size_of::<Histogram>();
let mem_rounds: usize = blocks.iter().map(|b| b.round_outputs.len() * 3).sum();
eprintln!(
"\r {} blocks precomputed ({:.1} GB hists + {:.0} MB rounds) in {:.1}s",
blocks.len(),
mem_hists as f64 / 1e9,
mem_rounds as f64 / 1e6,
t0.elapsed().as_secs_f64()
);
// Phase 2: sweep digit masks in parallel.
// Always filter digit 1 (powers of 10), sweep digits 2-9.
let base_mask: u16 = 1 << 0; // digit 1 always on
let num_masks: usize = 256; // 2^8 subsets of {2,...,9}
let num_threads = std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(8);
eprintln!(
"Phase 2: sweeping {} masks across {} threads...",
num_masks, num_threads
);
let t1 = Instant::now();
let blocks = &blocks; // shared reference for threads
let all_results: Vec<(u16, Stats)> = std::thread::scope(|s| {
let masks_per_thread = num_masks.div_ceil(num_threads);
let handles: Vec<_> = (0..num_threads)
.map(|t| {
s.spawn(move || {
let mask_start = t * masks_per_thread;
let mask_end = ((t + 1) * masks_per_thread).min(num_masks);
let mut results = Vec::with_capacity(mask_end - mask_start);
for idx in mask_start..mask_end {
// Shift idx bits into positions 1-8 (digits 2-9) and add base_mask (digit 1).
let mask = base_mask | ((idx as u16) << 1);
let mut oracle = Oracle::new(
seed_bin(sweep_start),
Config {
exclude_common_round_values: false,
..Default::default()
},
);
let mut stats = Stats::new();
for bd in blocks.iter() {
let mut hist = bd.full_hist.clone();
for &(bin, digit) in &bd.round_outputs {
if mask & (1 << (digit - 1)) != 0 {
hist[bin as usize] -= 1;
}
}
let ref_bin = oracle.process_histogram(&hist);
if bd.high_bin > 0.0 && bd.low_bin > 0.0 {
let err = if ref_bin < bd.high_bin {
ref_bin - bd.high_bin
} else if ref_bin > bd.low_bin {
ref_bin - bd.low_bin
} else {
0.0
};
stats.update(err);
}
}
results.push((mask, stats));
}
results
})
})
.collect();
handles
.into_iter()
.flat_map(|h| h.join().unwrap())
.collect()
});
eprintln!(" Done in {:.1}s.", t1.elapsed().as_secs_f64());
// Sort by RMSE.
let mut results: Vec<&(u16, Stats)> = all_results.iter().collect();
results.sort_by(|a, b| a.1.rmse_pct().partial_cmp(&b.1.rmse_pct()).unwrap());
// Print top 20.
println!();
println!("Top 20 (by RMSE):");
println!(
"{:>4} {:>12} {:>10} {:>10} {:>6} {:>6} {:>6} {:>8}",
"#", "Digits", "RMSE%", "Max%", ">5%", ">10%", ">20%", "Bias"
);
println!("{}", "-".repeat(70));
for (rank, (mask, s)) in results.iter().take(20).enumerate() {
println!(
"{:>4} {:>12} {:>8.3}% {:>8.1}% {:>6} {:>6} {:>6} {:>+8.2}",
rank + 1,
mask_label(*mask),
s.rmse_pct(),
s.max_pct(),
s.gt_5pct,
s.gt_10pct,
s.gt_20pct,
s.bias()
);
}
// Print bottom 5.
println!();
println!("Bottom 5 (worst):");
println!(
"{:>4} {:>12} {:>10} {:>10} {:>6} {:>6} {:>6} {:>8}",
"#", "Digits", "RMSE%", "Max%", ">5%", ">10%", ">20%", "Bias"
);
println!("{}", "-".repeat(70));
for (mask, s) in results.iter().rev().take(5) {
println!(
"{:>4} {:>12} {:>8.3}% {:>8.1}% {:>6} {:>6} {:>6} {:>+8.2}",
"",
mask_label(*mask),
s.rmse_pct(),
s.max_pct(),
s.gt_5pct,
s.gt_10pct,
s.gt_20pct,
s.bias()
);
}
// Print current config {1,2,3,5} for reference.
let current_mask: u16 = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 4); // digits 1,2,3,5
let current_stats = all_results
.iter()
.find(|(m, _)| *m == current_mask)
.map(|(_, s)| s)
.unwrap();
let current_rank = results
.iter()
.position(|(m, _)| *m == current_mask)
.unwrap();
println!();
println!(
"Current {{1,2,3,5}} = rank {}/{}: RMSE {:.3}%, Max {:.1}%, >5%: {}, >10%: {}, >20%: {}",
current_rank + 1,
num_masks,
current_stats.rmse_pct(),
current_stats.max_pct(),
current_stats.gt_5pct,
current_stats.gt_10pct,
current_stats.gt_20pct,
);
println!("\nTotal time: {:.1}s", t0.elapsed().as_secs_f64());
}
@@ -1,452 +0,0 @@
//! Sweep round-value tolerance to find optimal rounding threshold.
//!
//! Tests different tolerance percentages (0%, 0.01%, 0.1%, 1%, etc.) for
//! detecting round BTC amounts, combined with several digit filter masks.
//!
//! Phase 1: single pass over indexer, store per-output relative errors.
//! Phase 2: sweep tolerance × mask combos across CPU cores.
//!
//! Run with: cargo run -p brk_oracle --example sweep_tolerance --release
use std::path::PathBuf;
use std::time::Instant;
use brk_indexer::Indexer;
use brk_oracle::{Config, Histogram, Oracle, PRICES, cents_to_bin, sats_to_bin};
use brk_types::{OutputType, Sats, TxIndex, TxOutIndex};
use vecdb::{AnyVec, ReadableVec, VecIndex};
const BINS_5PCT: f64 = 4.24;
const BINS_10PCT: f64 = 8.28;
const BINS_20PCT: f64 = 15.84;
fn bins_to_pct(bins: f64) -> f64 {
(10.0_f64.powf(bins / 200.0) - 1.0) * 100.0
}
fn seed_bin(start_height: usize) -> f64 {
let price: f64 = PRICES
.lines()
.nth(start_height - 1)
.expect("prices.txt too short")
.parse()
.expect("Failed to parse seed price");
cents_to_bin(price * 100.0)
}
fn leading_digit(sats: u64) -> u8 {
let log = (sats as f64).log10();
let magnitude = 10.0_f64.powf(log.floor());
let d = (sats as f64 / magnitude).round() as u8;
if d >= 10 { 1 } else { d }
}
/// Returns the relative error of `sats` from its nearest round value (d × 10^n).
/// e.g. 10_050 → leading=1, round_val=10_000, rel_err = 50/10000 = 0.005
fn relative_roundness(sats: u64) -> f64 {
let log = (sats as f64).log10();
let magnitude = 10.0_f64.powf(log.floor());
let leading = (sats as f64 / magnitude).round();
let round_val = leading * magnitude;
(sats as f64 - round_val).abs() / round_val
}
struct Stats {
total_sq_err: f64,
total_bias: f64,
max_err: f64,
total_blocks: u64,
gt_5pct: u64,
gt_10pct: u64,
gt_20pct: u64,
}
impl Stats {
fn new() -> Self {
Self {
total_sq_err: 0.0,
total_bias: 0.0,
max_err: 0.0,
total_blocks: 0,
gt_5pct: 0,
gt_10pct: 0,
gt_20pct: 0,
}
}
fn update(&mut self, err: f64) {
self.total_sq_err += err * err;
self.total_bias += err;
self.total_blocks += 1;
let abs_err = err.abs();
if abs_err > self.max_err {
self.max_err = abs_err;
}
if abs_err > BINS_5PCT {
self.gt_5pct += 1;
}
if abs_err > BINS_10PCT {
self.gt_10pct += 1;
}
if abs_err > BINS_20PCT {
self.gt_20pct += 1;
}
}
fn rmse_pct(&self) -> f64 {
bins_to_pct((self.total_sq_err / self.total_blocks as f64).sqrt())
}
fn max_pct(&self) -> f64 {
bins_to_pct(self.max_err)
}
fn bias(&self) -> f64 {
self.total_bias / self.total_blocks as f64
}
}
/// Per-output data: bin index, leading digit, relative error from round value.
struct RoundOutput {
bin: u16,
digit: u8,
rel_err: f32, // f32 is plenty of precision, saves memory
}
struct BlockData {
full_hist: Histogram,
round_outputs: Vec<RoundOutput>,
high_bin: f64,
low_bin: f64,
}
fn main() {
let t0 = Instant::now();
let data_dir = std::env::var("BRK_DIR")
.map(PathBuf::from)
.unwrap_or_else(|_| {
let home = std::env::var("HOME").unwrap();
PathBuf::from(home).join(".brk")
});
let indexer = Indexer::forced_import(&data_dir).expect("Failed to load indexer");
let total_heights = indexer.vecs.blocks.timestamp.len();
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let height_ohlc: Vec<[f64; 4]> = serde_json::from_str(
&std::fs::read_to_string(format!("{manifest_dir}/examples/height_price_ohlc.json"))
.expect("Failed to read height_price_ohlc.json"),
)
.expect("Failed to parse height OHLC");
let height_bands: Vec<(f64, f64)> = height_ohlc
.iter()
.map(|ohlc| {
let high = ohlc[1];
let low = ohlc[2];
if high > 0.0 && low > 0.0 {
(cents_to_bin(high * 100.0), cents_to_bin(low * 100.0))
} else {
(0.0, 0.0)
}
})
.collect();
let sweep_start: usize = 575_000;
// Phase 1: precompute per-block data.
// Store all potentially-round outputs with their relative error so we can
// filter at different tolerance thresholds in Phase 2.
eprintln!("Phase 1: precomputing block data...");
let total_txs = indexer.vecs.transactions.txid.len();
let total_outputs = indexer.vecs.outputs.value.len();
let first_tx_index: Vec<TxIndex> = indexer.vecs.transactions.first_tx_index.collect();
let out_first: Vec<TxOutIndex> = indexer.vecs.outputs.first_txout_index.collect();
let ref_config = Config::default();
let total_blocks = total_heights - sweep_start;
let mut blocks: Vec<BlockData> = Vec::with_capacity(total_blocks);
// Use the widest tolerance we'll test (5%) to decide what to store.
// Outputs beyond 5% relative error will never be filtered at any tolerance.
let max_tolerance: f64 = 0.05;
for h in sweep_start..total_heights {
let ft = first_tx_index[h];
let next_ft = first_tx_index
.get(h + 1)
.copied()
.unwrap_or(TxIndex::from(total_txs));
let out_start = if ft.to_usize() + 1 < next_ft.to_usize() {
indexer
.vecs
.transactions
.first_txout_index
.collect_one(ft + 1)
.unwrap()
.to_usize()
} else {
out_first
.get(h + 1)
.copied()
.unwrap_or(TxOutIndex::from(total_outputs))
.to_usize()
};
let out_end = out_first
.get(h + 1)
.copied()
.unwrap_or(TxOutIndex::from(total_outputs))
.to_usize();
let values: Vec<Sats> = indexer
.vecs
.outputs
.value
.collect_range_at(out_start, out_end);
let output_types: Vec<OutputType> = indexer
.vecs
.outputs
.output_type
.collect_range_at(out_start, out_end);
let mut full_hist = Histogram::zeros();
let mut round_outputs = Vec::new();
for (sats, output_type) in values.into_iter().zip(output_types) {
if ref_config.excluded_output_types.contains(&output_type) {
continue;
}
if *sats < ref_config.min_sats {
continue;
}
if let Some(bin) = sats_to_bin(sats) {
full_hist.increment(bin);
let d = leading_digit(*sats);
if (1..=9).contains(&d) {
let rel_err = relative_roundness(*sats);
if rel_err <= max_tolerance {
round_outputs.push(RoundOutput {
bin: bin as u16,
digit: d,
rel_err: rel_err as f32,
});
}
}
}
}
let (high_bin, low_bin) = if h < height_bands.len() {
height_bands[h]
} else {
(0.0, 0.0)
};
blocks.push(BlockData {
full_hist,
round_outputs,
high_bin,
low_bin,
});
if (h - sweep_start).is_multiple_of(50_000) {
eprint!(
"\r {}/{} ({:.0}%)",
h - sweep_start,
total_blocks,
(h - sweep_start) as f64 / total_blocks as f64 * 100.0
);
}
}
let mem_hists = blocks.len() * std::mem::size_of::<Histogram>();
let mem_rounds: usize = blocks
.iter()
.map(|b| b.round_outputs.len() * std::mem::size_of::<RoundOutput>())
.sum();
eprintln!(
"\r {} blocks precomputed ({:.1} GB hists + {:.0} MB rounds) in {:.1}s",
blocks.len(),
mem_hists as f64 / 1e9,
mem_rounds as f64 / 1e6,
t0.elapsed().as_secs_f64()
);
// Phase 2: sweep tolerance × mask combos.
// Tolerances as fractions (not percentages).
let tolerances: &[(f64, &str)] = &[
(0.0, "0%"),
(0.0001, "0.01%"),
(0.0005, "0.05%"),
(0.001, "0.1%"),
(0.002, "0.2%"),
(0.005, "0.5%"),
(0.01, "1%"),
(0.02, "2%"),
(0.05, "5%"),
];
// 987654321
let masks: &[(u16, &str)] = &[
(0b0_0000_0000, "none"),
(0b0_0001_0111, "{1,2,3,5}"),
(0b0_0001_1111, "{1,2,3,4,5}"),
(0b0_0011_0111, "{1,2,3,5,6}"),
(0b0_0111_0111, "{1,2,3,5,6,7}"),
(0b1_1111_1111, "{1-9}"),
];
let num_configs = tolerances.len() * masks.len();
let num_threads = std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(8);
eprintln!(
"Phase 2: sweeping {} configs ({} tolerances × {} masks) across {} threads...",
num_configs,
tolerances.len(),
masks.len(),
num_threads
);
let t1 = Instant::now();
let blocks = &blocks;
let tolerances_ref = tolerances;
let masks_ref = masks;
let all_results: Vec<(usize, usize, Stats)> = std::thread::scope(|s| {
let configs_per_thread = num_configs.div_ceil(num_threads);
let handles: Vec<_> = (0..num_threads)
.map(|t| {
s.spawn(move || {
let cfg_start = t * configs_per_thread;
let cfg_end = ((t + 1) * configs_per_thread).min(num_configs);
if cfg_start >= cfg_end {
return vec![];
}
let mut results = Vec::with_capacity(cfg_end - cfg_start);
for cfg_idx in cfg_start..cfg_end {
let ti = cfg_idx / masks_ref.len();
let mi = cfg_idx % masks_ref.len();
let (tolerance, _) = tolerances_ref[ti];
let (mask, _) = masks_ref[mi];
let mut oracle = Oracle::new(
seed_bin(sweep_start),
Config {
exclude_common_round_values: false,
..Default::default()
},
);
let mut stats = Stats::new();
for bd in blocks.iter() {
let mut hist = bd.full_hist.clone();
// Remove outputs matching this tolerance + mask.
let tol_f32 = tolerance as f32;
for ro in &bd.round_outputs {
if mask & (1 << (ro.digit - 1)) != 0 && ro.rel_err <= tol_f32 {
hist[ro.bin as usize] -= 1;
}
}
let ref_bin = oracle.process_histogram(&hist);
if bd.high_bin > 0.0 && bd.low_bin > 0.0 {
let err = if ref_bin < bd.high_bin {
ref_bin - bd.high_bin
} else if ref_bin > bd.low_bin {
ref_bin - bd.low_bin
} else {
0.0
};
stats.update(err);
}
}
results.push((ti, mi, stats));
}
results
})
})
.collect();
handles
.into_iter()
.flat_map(|h| h.join().unwrap())
.collect()
});
eprintln!(" Done in {:.1}s.", t1.elapsed().as_secs_f64());
// Print results grouped by tolerance.
println!();
println!(
"{:>8} {:>16} {:>8} {:>10} {:>10} {:>6} {:>6} {:>6} {:>8}",
"Tol", "Digits", "Blocks", "RMSE%", "Max%", ">5%", ">10%", ">20%", "Bias"
);
println!("{}", "-".repeat(88));
for (ti, &(_, tol_label)) in tolerances.iter().enumerate() {
for (mi, &(_, mask_label)) in masks.iter().enumerate() {
let (_, _, stats) = all_results
.iter()
.find(|(t, m, _)| *t == ti && *m == mi)
.unwrap();
println!(
"{:>8} {:>16} {:>8} {:>8.3}% {:>8.1}% {:>6} {:>6} {:>6} {:>+8.2}",
tol_label,
mask_label,
stats.total_blocks,
stats.rmse_pct(),
stats.max_pct(),
stats.gt_5pct,
stats.gt_10pct,
stats.gt_20pct,
stats.bias()
);
}
println!();
}
// Find overall best config by RMSE.
let best = all_results
.iter()
.min_by(|a, b| a.2.rmse_pct().partial_cmp(&b.2.rmse_pct()).unwrap())
.unwrap();
let (bti, bmi, bs) = best;
println!(
"Best: tolerance={}, digits={} → RMSE {:.3}%, Max {:.1}%, >5%: {}, >10%: {}, >20%: {}",
tolerances[*bti].1,
masks[*bmi].1,
bs.rmse_pct(),
bs.max_pct(),
bs.gt_5pct,
bs.gt_10pct,
bs.gt_20pct,
);
// Show current config for reference.
let current = all_results
.iter()
.find(|(t, m, _)| tolerances[*t].0 == 0.001 && masks[*m].0 == 0b0_0011_0111)
.unwrap();
let (_, _, cs) = current;
println!(
"Current: tolerance=0.1%, digits={{1,2,3,5,6}} → RMSE {:.3}%, Max {:.1}%, >5%: {}, >10%: {}, >20%: {}",
cs.rmse_pct(),
cs.max_pct(),
cs.gt_5pct,
cs.gt_10pct,
cs.gt_20pct,
);
println!("\nTotal time: {:.1}s", t0.elapsed().as_secs_f64());
}
-286
View File
@@ -1,286 +0,0 @@
//! Validate oracle accuracy against exchange reference prices.
//!
//! Run with: cargo run -p brk_oracle --example validate --release
//!
//! Requires:
//! - ~/.brk indexed blockchain data (brk_indexer)
//! - examples/height_price_ohlc.json (per-height [open, high, low, close] in dollars)
use std::path::PathBuf;
use brk_indexer::Indexer;
use brk_oracle::{
Config, Histogram, Oracle, PRICES, START_HEIGHT, cents_to_bin, default_eligible_bin,
};
use brk_types::{OutputType, Sats, TxIndex, TxOutIndex};
use vecdb::{AnyVec, ReadableVec, VecIndex};
const BINS_5PCT: f64 = 4.24;
const BINS_10PCT: f64 = 8.28;
const BINS_20PCT: f64 = 15.84;
fn bins_to_pct(bins: f64) -> f64 {
(10.0_f64.powf(bins / 200.0) - 1.0) * 100.0
}
fn seed_bin(start_height: usize) -> f64 {
let price: f64 = PRICES
.lines()
.nth(start_height - 1)
.expect("prices.txt too short")
.parse()
.expect("Failed to parse seed price");
cents_to_bin(price * 100.0)
}
struct Stats {
total_sq_err: f64,
total_bias: f64,
max_err: f64,
total_blocks: u64,
gt_5pct: u64,
gt_10pct: u64,
gt_20pct: u64,
}
impl Stats {
fn new() -> Self {
Self {
total_sq_err: 0.0,
total_bias: 0.0,
max_err: 0.0,
total_blocks: 0,
gt_5pct: 0,
gt_10pct: 0,
gt_20pct: 0,
}
}
fn update(&mut self, err: f64) {
self.total_sq_err += err * err;
self.total_bias += err;
self.total_blocks += 1;
let abs_err = err.abs();
if abs_err > self.max_err {
self.max_err = abs_err;
}
if abs_err > BINS_5PCT {
self.gt_5pct += 1;
}
if abs_err > BINS_10PCT {
self.gt_10pct += 1;
}
if abs_err > BINS_20PCT {
self.gt_20pct += 1;
}
}
fn rmse_pct(&self) -> f64 {
bins_to_pct((self.total_sq_err / self.total_blocks as f64).sqrt())
}
fn max_pct(&self) -> f64 {
bins_to_pct(self.max_err)
}
fn bias(&self) -> f64 {
self.total_bias / self.total_blocks as f64
}
}
struct Run {
label: &'static str,
start_height: usize,
oracle: Option<Oracle>,
stats: Stats,
}
fn main() {
let data_dir = std::env::var("BRK_DIR")
.map(PathBuf::from)
.unwrap_or_else(|_| {
let home = std::env::var("HOME").unwrap();
PathBuf::from(home).join(".brk")
});
let indexer = Indexer::forced_import(&data_dir).expect("Failed to load indexer");
let total_heights = indexer.vecs.blocks.timestamp.len();
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let height_ohlc: Vec<[f64; 4]> = serde_json::from_str(
&std::fs::read_to_string(format!("{manifest_dir}/examples/height_price_ohlc.json"))
.expect("Failed to read height_price_ohlc.json"),
)
.expect("Failed to parse height OHLC");
// Pre-compute per-height (high_bin, low_bin) tolerance band.
let height_bands: Vec<(f64, f64)> = height_ohlc
.iter()
.map(|ohlc| {
let high = ohlc[1];
let low = ohlc[2];
if high > 0.0 && low > 0.0 {
(cents_to_bin(high * 100.0), cents_to_bin(low * 100.0))
} else {
(0.0, 0.0)
}
})
.collect();
let mut runs = vec![
Run {
label: "w12 @ 575k",
start_height: 575_000,
oracle: None,
stats: Stats::new(),
},
Run {
label: "w12 @ 600k",
start_height: 600_000,
oracle: None,
stats: Stats::new(),
},
Run {
label: "w12 @ 630k",
start_height: 630_000,
oracle: None,
stats: Stats::new(),
},
];
// Build per-block filtered histograms from the indexer, feeding all oracles in one pass.
let total_txs = indexer.vecs.transactions.txid.len();
let total_outputs = indexer.vecs.outputs.value.len();
// Pre-collect height-indexed vecs (small). Transaction-indexed vecs are too large.
let first_tx_index: Vec<TxIndex> = indexer.vecs.transactions.first_tx_index.collect();
let out_first: Vec<TxOutIndex> = indexer.vecs.outputs.first_txout_index.collect();
for h in START_HEIGHT..total_heights {
let ft = first_tx_index[h];
let next_ft = first_tx_index
.get(h + 1)
.copied()
.unwrap_or(TxIndex::from(total_txs));
let out_start = if ft.to_usize() + 1 < next_ft.to_usize() {
indexer
.vecs
.transactions
.first_txout_index
.collect_one(ft + 1)
.unwrap()
.to_usize()
} else {
out_first
.get(h + 1)
.copied()
.unwrap_or(TxOutIndex::from(total_outputs))
.to_usize()
};
let out_end = out_first
.get(h + 1)
.copied()
.unwrap_or(TxOutIndex::from(total_outputs))
.to_usize();
// Build filtered histogram once for all oracles.
let values: Vec<Sats> = indexer
.vecs
.outputs
.value
.collect_range_at(out_start, out_end);
let output_types: Vec<OutputType> = indexer
.vecs
.outputs
.output_type
.collect_range_at(out_start, out_end);
let mut hist = Histogram::zeros();
for (sats, output_type) in values.into_iter().zip(output_types) {
if let Some(bin) = default_eligible_bin(sats, output_type) {
hist.increment(bin as usize);
}
}
for run in &mut runs {
if h < run.start_height {
continue;
}
if run.oracle.is_none() {
let config = Config::default();
run.oracle = Some(Oracle::new(seed_bin(run.start_height), config));
}
let ref_bin = run.oracle.as_mut().unwrap().process_histogram(&hist);
if h < height_bands.len() {
let (high_bin, low_bin) = height_bands[h];
if high_bin > 0.0 && low_bin > 0.0 {
let err = if ref_bin < high_bin {
ref_bin - high_bin
} else if ref_bin > low_bin {
ref_bin - low_bin
} else {
0.0
};
run.stats.update(err);
}
}
}
}
// Print results.
println!();
println!(
"{:<14} {:>8} {:>10} {:>10} {:>6} {:>6} {:>6} {:>8}",
"Config", "Blocks", "RMSE%", "Max%", ">5%", ">10%", ">20%", "Bias"
);
println!("{}", "-".repeat(72));
for run in &runs {
let s = &run.stats;
println!(
"{:<14} {:>8} {:>7.2}% {:>7.1}% {:>6} {:>6} {:>6} {:>+8.2}",
run.label,
s.total_blocks,
s.rmse_pct(),
s.max_pct(),
s.gt_5pct,
s.gt_10pct,
s.gt_20pct,
s.bias()
);
}
println!();
// Verify exact counts against reference.
// Reference: trunc w12 @ 575k: 261 >5%, 40 >10%, 0 >20%
// trunc w12 @ 600k: 174 >5%, 31 >10%, 0 >20%
// trunc w12 @ 630k: 84 >5%, 9 >10%, 0 >20%
let expected: &[(&str, u64, u64, u64)] = &[
("w12 @ 575k", 237, 22, 0),
("w12 @ 600k", 152, 15, 0),
("w12 @ 630k", 84, 9, 0),
];
for (run, &(label, exp_5, exp_10, exp_20)) in runs.iter().zip(expected) {
let s = &run.stats;
assert_eq!(
s.gt_20pct, exp_20,
"{label}: expected {exp_20} blocks >20%, got {}",
s.gt_20pct
);
assert_eq!(
s.gt_10pct, exp_10,
"{label}: expected {exp_10} blocks >10%, got {}",
s.gt_10pct
);
assert_eq!(
s.gt_5pct, exp_5,
"{label}: expected {exp_5} blocks >5%, got {}",
s.gt_5pct
);
}
println!("All assertions passed!");
}
+80 -16
View File
@@ -1,11 +1,14 @@
use brk_types::OutputType;
use std::ops::Range;
/// Dust floor used by `Config::default()` and `default_eligible_bin`.
pub(crate) const DEFAULT_MIN_SATS: u64 = 1000;
/// First height the oracle computes on-chain, with the slow cold-start EMA
/// ([`slow`](Config::slow)). Below it, prices come from [`PRICES`](crate::PRICES).
pub const START_HEIGHT_SLOW: usize = 340_000;
/// Output types skipped by `Config::default()` (protocol-dominated) and the
/// source of truth for `default_eligible_bin`'s precomputed exclusion mask.
pub(crate) const DEFAULT_EXCLUDED_OUTPUT_TYPES: &[OutputType] = &[OutputType::P2TR];
/// Height where the oracle switches slow -> fast EMA ([`default`](Config::default)).
/// The regimes are complementary: slow resists the round-USD half-price drift
/// that locks fast below here, while fast tracks the 2018-2019 crashes that lock
/// slow.
pub const START_HEIGHT_FAST: usize = 508_000;
#[derive(Clone)]
pub struct Config {
@@ -16,12 +19,12 @@ pub struct Config {
/// Search window bins below/above previous estimate. Asymmetric for log-scale.
pub search_below: usize,
pub search_above: usize,
/// Minimum output value in sats (dust filter).
pub min_sats: u64,
/// Exclude round BTC amounts that create false stencil matches.
pub exclude_common_round_values: bool,
/// Output types to ignore (e.g. P2TR, P2WSH are noisy).
pub excluded_output_types: Vec<OutputType>,
/// Weight of the adaptive shape-anchoring restoring force added to the
/// stencil score. `0.0` disables it (mature regime, where the fast EMA
/// tracks real moves the shape term would resist). The slow cold-start uses
/// a positive weight to resist round-USD octave aliasing in the thin early
/// output mix.
pub shape_weight: f64,
}
impl Default for Config {
@@ -29,11 +32,72 @@ impl Default for Config {
Self {
alpha: 2.0 / 7.0,
window_size: 12,
search_below: 9,
search_below: 12,
search_above: 11,
min_sats: DEFAULT_MIN_SATS,
exclude_common_round_values: true,
excluded_output_types: DEFAULT_EXCLUDED_OUTPUT_TYPES.to_vec(),
shape_weight: 0.0,
}
}
}
impl Config {
/// Cold-start config below [`START_HEIGHT_FAST`]: a slow EMA
/// (span ~19) that resists the round-USD half-price drift the fast default
/// octave-locks onto in the thin pre-2018 output mix. Window grows to 40 to
/// hold the decay, and a shape-anchoring restoring force (`shape_weight`)
/// pulls the pick toward the octave whose arm-shape looks like real payments.
pub fn slow() -> Self {
Self {
alpha: 0.10,
window_size: 40,
shape_weight: 8.0,
..Self::default()
}
}
/// Config for `height`: [`slow`](Self::slow) below [`START_HEIGHT_FAST`], else
/// [`default`](Self::default).
pub fn for_height(height: usize) -> Self {
if height < START_HEIGHT_FAST {
Self::slow()
} else {
Self::default()
}
}
/// Split a block range into sub-ranges with a single EMA configuration.
pub fn segments_for_range(range: Range<usize>) -> impl Iterator<Item = Range<usize>> {
let split = START_HEIGHT_FAST.max(range.start).min(range.end);
[range.start..split, split..range.end]
.into_iter()
.filter(|range| !range.is_empty())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn segments_for_range_splits_at_fast_start() {
let segments: Vec<_> =
Config::segments_for_range((START_HEIGHT_FAST - 2)..(START_HEIGHT_FAST + 2)).collect();
assert_eq!(
segments,
vec![
(START_HEIGHT_FAST - 2)..START_HEIGHT_FAST,
START_HEIGHT_FAST..(START_HEIGHT_FAST + 2),
]
);
}
#[test]
fn segments_for_range_omits_empty_sides() {
let slow: Vec<_> =
Config::segments_for_range((START_HEIGHT_FAST - 2)..START_HEIGHT_FAST).collect();
assert_eq!(slow, vec![(START_HEIGHT_FAST - 2)..START_HEIGHT_FAST]);
let fast: Vec<_> =
Config::segments_for_range(START_HEIGHT_FAST..(START_HEIGHT_FAST + 2)).collect();
assert_eq!(fast, vec![START_HEIGHT_FAST..(START_HEIGHT_FAST + 2)]);
}
}
+75
View File
@@ -0,0 +1,75 @@
use brk_types::{OutputType, Sats};
use crate::scale::sats_to_bin;
/// Dust floor: outputs below this many sats are too small to be payments.
const MIN_SATS: u64 = 1000;
/// Output types skipped entirely (protocol-dominated, too noisy to carry the
/// round-dollar signal).
const EXCLUDED_OUTPUT_TYPES: &[OutputType] = &[OutputType::P2TR];
/// Bitmask form of [`EXCLUDED_OUTPUT_TYPES`], folded at compile time so
/// [`eligible_bin`] checks membership with a single AND.
const EXCLUDED_MASK: u16 = {
let mut mask = 0u16;
let mut i = 0;
while i < EXCLUDED_OUTPUT_TYPES.len() {
mask |= 1u16 << EXCLUDED_OUTPUT_TYPES[i] as u8;
i += 1;
}
mask
};
/// A transaction with more than this many outputs is a batch payout (exchange
/// sweep, mixer fan-out), not a round-dollar payment, so it is dropped below
/// [`MAX_OUTPUTS_UNTIL_HEIGHT`].
pub const MAX_OUTPUTS: usize = 100;
/// Height below which the [`MAX_OUTPUTS`] cap applies. The thin 2018-2020
/// signal needs batch payouts removed to stay locked onto the round-dollar
/// pattern. Above this height on-chain volume is dense enough that the cap
/// removes more genuine signal than noise, so it is lifted.
pub const MAX_OUTPUTS_UNTIL_HEIGHT: usize = 630_000;
/// Bin index for `(sats, output_type)`, or `None` for an excluded type (P2TR),
/// dust, a round-BTC value, or an out-of-range bin. The per-output half of the
/// round-dollar payment filter.
#[inline(always)]
pub fn eligible_bin(sats: Sats, output_type: OutputType) -> Option<u16> {
if EXCLUDED_MASK & (1u16 << output_type as u8) != 0 {
return None;
}
if *sats < MIN_SATS || sats.is_common_round_value() {
return None;
}
sats_to_bin(sats).map(|b| b as u16)
}
/// The on-chain round-dollar payment filter, shared by the indexer warm-up,
/// per-request reconstruction, and the mempool's live histogram so every path
/// bins identically. Calls `emit(bin)` for each eligible output, in order.
///
/// A whole transaction is dropped when it carries any OP_RETURN output (data
/// carriers, not payments) or, below [`MAX_OUTPUTS_UNTIL_HEIGHT`], when it has
/// more than [`MAX_OUTPUTS`] outputs (batch payouts). `height` is the block these
/// outputs belong to. The mempool, always past the cap window, passes
/// `usize::MAX`.
#[inline]
pub fn for_each_round_dollar_bin(
height: usize,
outputs: impl ExactSizeIterator<Item = (Sats, OutputType)> + Clone,
mut emit: impl FnMut(u16),
) {
if height < MAX_OUTPUTS_UNTIL_HEIGHT && outputs.len() > MAX_OUTPUTS {
return;
}
if outputs.clone().any(|(_, ty)| ty == OutputType::OpReturn) {
return;
}
for (sats, ty) in outputs {
if let Some(bin) = eligible_bin(sats, ty) {
emit(bin);
}
}
}
-41
View File
@@ -1,41 +0,0 @@
use crate::NUM_BINS;
/// Per-block oracle histogram: count of eligible outputs per bin. Wraps
/// the raw `[u32; NUM_BINS]` so callers can't pass arbitrary bin-indexed
/// arrays to `Oracle::process_histogram`. Deref to the underlying array
/// gives indexing for read paths.
#[derive(Clone)]
pub struct Histogram([u32; NUM_BINS]);
impl Histogram {
#[inline]
pub fn zeros() -> Self {
Self([0; NUM_BINS])
}
#[inline]
pub fn increment(&mut self, bin: usize) {
self.0[bin] += 1;
}
}
impl Default for Histogram {
fn default() -> Self {
Self::zeros()
}
}
impl std::ops::Deref for Histogram {
type Target = [u32; NUM_BINS];
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for Histogram {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
+137 -246
View File
@@ -2,221 +2,71 @@
//!
//! Detects round-dollar transaction patterns ($1, $5, $10, ... $10,000) in Bitcoin
//! block outputs to derive the current price without any exchange data.
//!
//! Behavior changes by height along two independent axes, each in its own module:
//!
//! - EMA regime (`config`): below [`START_HEIGHT_SLOW`] prices come from the baked
//! [`PRICES`]. From there to [`START_HEIGHT_FAST`] a slow cold-start EMA runs with
//! a shape-anchoring restoring force. At [`START_HEIGHT_FAST`] it switches to a
//! fast EMA that tracks mature-market volatility.
//! - Output filter (`filter`): below [`MAX_OUTPUTS_UNTIL_HEIGHT`] batch-payout
//! transactions are dropped from the histogram. Above it the cap is lifted.
//!
//! The two boundaries differ on purpose. The EMA must hand off to fast before the
//! 2020 crash, while the output cap helps the thin pre-2020 mix for longer.
use brk_types::{Cents, Dollars, OutputType, Sats};
use brk_types::{Cents, Dollars};
mod config;
mod histogram;
mod filter;
mod scale;
mod shape;
mod stencil;
mod window;
use config::{DEFAULT_EXCLUDED_OUTPUT_TYPES, DEFAULT_MIN_SATS};
pub use config::Config;
pub use histogram::Histogram;
pub use config::{Config, START_HEIGHT_FAST, START_HEIGHT_SLOW};
pub use filter::{MAX_OUTPUTS, MAX_OUTPUTS_UNTIL_HEIGHT, eligible_bin, for_each_round_dollar_bin};
pub use scale::{
BINS_PER_DECADE, HistogramEma, HistogramEmaCompact, HistogramRaw, NUM_BINS, bin_to_cents,
cents_to_bin, sats_to_bin,
};
use shape::ShapeAnchor;
use stencil::find_best_bin;
use window::EmaWindow;
/// Oracle algorithm version. Bump on any change that alters computed prices
/// so downstream consumers can invalidate cached results.
pub const VERSION: u32 = 2;
pub const VERSION: u32 = 3;
/// Pre-oracle dollar prices, one per line, heights 0..630_000.
/// Pre-oracle dollar prices, one per line, heights 0..340_000. The last entry
/// seeds the oracle's first on-chain computation at [`START_HEIGHT_SLOW`].
pub const PRICES: &str = include_str!("prices.txt");
/// First height where the oracle computes from on-chain data.
pub const START_HEIGHT: usize = 525_000;
pub const BINS_PER_DECADE: usize = 200;
const MIN_LOG_BTC: i32 = -8;
const MAX_LOG_BTC: i32 = 4;
pub const NUM_BINS: usize = BINS_PER_DECADE * (MAX_LOG_BTC - MIN_LOG_BTC) as usize;
/// Bin offsets for 19 round-USD amounts relative to the $100 reference (offset 0).
/// Each offset = log10(amount / 100) * BINS_PER_DECADE.
const STENCIL_OFFSETS: [i32; 19] = [
-400, // $1
-340, // $2
-305, // $3
-260, // $5
-200, // $10
-165, // $15
-140, // $20
-120, // $25
-105, // $30
-60, // $50
0, // $100
35, // $150
60, // $200
95, // $300
140, // $500
200, // $1000
260, // $2000
340, // $5000
400, // $10000
];
/// Maps a satoshi value to its log-scale bin index.
/// bin = round(log10(sats) * BINS_PER_DECADE).
#[inline(always)]
pub fn sats_to_bin(sats: Sats) -> Option<usize> {
if sats.is_zero() {
return None;
}
let bin = ((*sats as f64).log10() * BINS_PER_DECADE as f64).round() as i64;
if bin >= 0 && (bin as usize) < NUM_BINS {
Some(bin as usize)
} else {
None
}
}
/// Bitmask form of `DEFAULT_EXCLUDED_OUTPUT_TYPES`, evaluated at compile
/// time so `default_eligible_bin` checks membership with a single AND.
const DEFAULT_EXCLUDED_MASK: u16 = {
let mut mask = 0u16;
let mut i = 0;
while i < DEFAULT_EXCLUDED_OUTPUT_TYPES.len() {
mask |= 1u16 << DEFAULT_EXCLUDED_OUTPUT_TYPES[i] as u8;
i += 1;
}
mask
};
/// Bin index for `(sats, output_type)` under `Config::default()` rules.
/// Returns `None` for excluded types (P2TR/P2WSH), dust, round-BTC values,
/// or out-of-range bins. Mirror of `Oracle::output_to_bin` for callers that
/// can pre-bin outputs at write time and don't have an `Oracle` handle.
#[inline(always)]
pub fn default_eligible_bin(sats: Sats, output_type: OutputType) -> Option<u16> {
if DEFAULT_EXCLUDED_MASK & (1u16 << output_type as u8) != 0 {
return None;
}
if *sats < DEFAULT_MIN_SATS || sats.is_common_round_value() {
return None;
}
sats_to_bin(sats).map(|b| b as u16)
}
/// Converts a fractional bin to a USD price in cents.
/// For a $D output at price P: sats = D * 1e8 / P, so P = 10^(10 - bin/200) dollars,
/// where 10 = log10($100 reference * 1e8 sats/BTC).
#[inline]
pub fn bin_to_cents(bin: f64) -> u64 {
let dollars = 10.0_f64.powf(10.0 - bin / BINS_PER_DECADE as f64);
(dollars * 100.0).round() as u64
}
/// Converts a USD price in cents to a fractional bin (inverse of bin_to_cents).
#[inline]
pub fn cents_to_bin(cents: f64) -> f64 {
(10.0 - (cents / 100.0).log10()) * BINS_PER_DECADE as f64
}
/// Scores each candidate bin in the search window by summing normalized stencil
/// matches across the EMA histogram, then refines with parabolic interpolation.
fn find_best_bin(
ema: &[f64; NUM_BINS],
prev_bin: f64,
search_below: usize,
search_above: usize,
) -> f64 {
let center = prev_bin.round() as usize;
let search_start = center.saturating_sub(search_below);
let search_end = (center + search_above + 1).min(NUM_BINS);
if search_start >= search_end {
return prev_bin;
}
// Per-offset peak within the search window (for normalization).
let mut track_norm = [0.0f64; 19];
for (i, &offset) in STENCIL_OFFSETS.iter().enumerate() {
for bin in search_start..search_end {
let idx = bin as i32 + offset;
if idx >= 0 && (idx as usize) < NUM_BINS {
track_norm[i] = track_norm[i].max(ema[idx as usize]);
}
}
}
let score = |bin: usize| -> f64 {
let mut total = 0.0;
for (i, &offset) in STENCIL_OFFSETS.iter().enumerate() {
let idx = bin as i32 + offset;
if idx >= 0 && (idx as usize) < NUM_BINS && track_norm[i] > 0.0 {
total += ema[idx as usize] / track_norm[i];
}
}
total
};
let mut best_bin = search_start;
let mut best_score = score(search_start);
for bin in (search_start + 1)..search_end {
let candidate = score(bin);
if candidate > best_score {
best_score = candidate;
best_bin = bin;
}
}
// Parabolic sub-bin interpolation for fractional precision.
let score_center = best_score;
let score_left = if best_bin > search_start {
score(best_bin - 1)
} else {
score_center
};
let score_right = if best_bin + 1 < search_end {
score(best_bin + 1)
} else {
score_center
};
let denom = score_left - 2.0 * score_center + score_right;
let sub_bin = if denom.abs() > 1e-10 {
(0.5 * (score_left - score_right) / denom).clamp(-0.5, 0.5)
} else {
0.0
};
best_bin as f64 + sub_bin
}
#[derive(Clone)]
pub struct Oracle {
histograms: Vec<Histogram>,
ema: Box<[f64; NUM_BINS]>,
cursor: usize,
filled: usize,
window: EmaWindow,
ref_bin: f64,
config: Config,
weights: Vec<f64>,
excluded_mask: u16,
warmup: bool,
/// Shape-anchoring restoring force, inert outside the slow cold-start
/// regime (zero weight). See [`ShapeAnchor`](shape::ShapeAnchor).
shape: ShapeAnchor,
}
impl Oracle {
pub fn new(start_bin: f64, config: Config) -> Self {
let window_size = config.window_size;
let decay = 1.0 - config.alpha;
let weights: Vec<f64> = (0..window_size)
.map(|i| config.alpha * decay.powi(i as i32))
.collect();
let excluded_mask = config
.excluded_output_types
.iter()
.fold(0u16, |mask, ot| mask | (1 << *ot as u8));
Self {
histograms: vec![Histogram::zeros(); window_size],
ema: Box::new([0.0; NUM_BINS]),
cursor: 0,
filled: 0,
window: EmaWindow::new(config.window_size, config.alpha),
ref_bin: start_bin,
weights,
excluded_mask,
warmup: false,
shape: ShapeAnchor::new(config.shape_weight),
config,
}
}
/// Create an oracle restored from a known price. `fill` should call
/// `process_histogram` for the warmup blocks; during warmup the ring
/// `process_histogram` for the warmup blocks. During warmup the ring
/// fills without recomputing EMA or searching, then we recompute once
/// at the end so the first non-warmup call has a primed EMA.
pub fn from_checkpoint(ref_bin: f64, config: Config, fill: impl FnOnce(&mut Self)) -> Self {
@@ -224,34 +74,51 @@ impl Oracle {
oracle.warmup = true;
fill(&mut oracle);
oracle.warmup = false;
oracle.recompute_ema();
oracle.window.recompute();
oracle
}
pub fn process_histogram(&mut self, hist: &Histogram) -> f64 {
self.histograms[self.cursor] = hist.clone();
self.cursor = (self.cursor + 1) % self.config.window_size;
if self.filled < self.config.window_size {
self.filled += 1;
}
pub fn process_histogram(&mut self, hist: &HistogramRaw) -> f64 {
self.window.push(hist);
if !self.warmup {
self.recompute_ema();
self.window.recompute();
self.ref_bin = find_best_bin(
&self.ema,
self.window.ema(),
self.ref_bin,
self.config.search_below,
self.config.search_above,
&self.shape,
);
self.shape.update(self.window.ema(), self.ref_bin.round() as i64);
}
self.ref_bin
}
/// Switch EMA regime mid-stream (slow -> fast at [`START_HEIGHT_FAST`]) by
/// re-warming under `config` over the most recent `config.window_size` raw
/// histograms, so a continuous build and an incremental warm-up reach the
/// same state. `ref_bin` carries over.
pub fn reconfigure(&mut self, config: Config) {
let kept = self.window.recent(config.window_size);
*self = Self::from_checkpoint(self.ref_bin, config, |o| {
kept.iter().for_each(|h| {
o.process_histogram(h);
});
});
}
pub fn ref_bin(&self) -> f64 {
self.ref_bin
}
/// The current weighted EMA over the window, one value per log-scale bin.
/// `ema()[i]` is bin `i` (see `sats_to_bin`).
pub fn ema(&self) -> &HistogramEma {
self.window.ema()
}
pub fn price_cents(&self) -> Cents {
bin_to_cents(self.ref_bin).into()
}
@@ -259,65 +126,89 @@ impl Oracle {
pub fn price_dollars(&self) -> Dollars {
self.price_cents().into()
}
/// Config-aware bin index for `(sats, output_type)`. Returns `None`
/// for excluded types, dust, round-BTC values, or out-of-range bins.
/// Callers under `Config::default()` should use `default_eligible_bin`
/// (free function) to skip the `&self` indirection.
#[inline(always)]
pub fn output_to_bin(&self, sats: Sats, output_type: OutputType) -> Option<usize> {
if self.excluded_mask & (1 << output_type as u8) != 0 {
return None;
}
if *sats < self.config.min_sats
|| (self.config.exclude_common_round_values && sats.is_common_round_value())
{
return None;
}
sats_to_bin(sats)
}
fn recompute_ema(&mut self) {
self.ema.fill(0.0);
for age in 0..self.filled {
let idx = (self.cursor + self.config.window_size - 1 - age) % self.config.window_size;
let weight = self.weights[age];
let h = &self.histograms[idx];
(0..NUM_BINS).for_each(|bin| {
self.ema[bin] += weight * h[bin] as f64;
});
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sats_to_bin_round_trip() {
assert_eq!(sats_to_bin(Sats::new(100_000_000)), Some(1600));
assert_eq!(sats_to_bin(Sats::new(1)), Some(0));
assert_eq!(sats_to_bin(Sats::ZERO), None);
}
#[test]
fn bin_to_cents_known_values() {
assert_eq!(bin_to_cents(1600.0), 10000);
assert_eq!(bin_to_cents(1800.0), 1000);
}
#[test]
fn sats_to_bin_boundary() {
assert_eq!(sats_to_bin(Sats::new(1_000_000_000_000)), None);
let sats = 10.0_f64.powf(11.995) as u64;
assert!(sats_to_bin(Sats::new(sats)).is_some());
}
#[test]
fn oracle_basic() {
let oracle = Oracle::new(1600.0, Config::default());
assert_eq!(oracle.ref_bin(), 1600.0);
assert_eq!(oracle.price_cents(), bin_to_cents(1600.0).into());
}
// reconfigure must leave the oracle in the same state as a fresh warm-up
// over the most recent window of raw histograms. The continuous build and
// the incremental resume rely on this agreeing at the slow -> fast seam.
#[test]
fn reconfigure_matches_fresh_warmup() {
let hists: Vec<HistogramRaw> = (0..60)
.map(|i| {
let mut h = HistogramRaw::zeros();
h.increment(1200 + i % 7);
h.increment(1600 + i % 5);
h
})
.collect();
let fast = Config::default();
let mut switched = Oracle::new(1600.0, Config::slow());
hists.iter().for_each(|h| {
switched.process_histogram(h);
});
switched.reconfigure(fast.clone());
let keep = fast.window_size;
let fresh = Oracle::from_checkpoint(switched.ref_bin(), fast, |o| {
hists[hists.len() - keep..].iter().for_each(|h| {
o.process_histogram(h);
});
});
assert!(switched.ema().iter().eq(fresh.ema().iter()));
}
#[test]
fn sequential_ema_matches_fresh_warmups() {
let hists: Vec<HistogramRaw> = (0..80)
.map(|i| {
let mut h = HistogramRaw::zeros();
h.increment(1000 + i % 11);
h.increment(1300 + i % 13);
h.increment(1700 + i % 17);
h
})
.collect();
for config in [Config::slow(), Config::default()] {
let query_start = config.window_size + 5;
let query_end = query_start + 20;
let seed = 1600.0;
let mut sequential = Oracle::from_checkpoint(seed, config.clone(), |o| {
hists[query_start + 1 - config.window_size..query_start + 1]
.iter()
.for_each(|h| {
o.process_histogram(h);
});
});
for height in query_start..query_end {
if height != query_start {
sequential.process_histogram(&hists[height]);
}
let fresh = Oracle::from_checkpoint(seed, config.clone(), |o| {
hists[height + 1 - config.window_size..height + 1]
.iter()
.for_each(|h| {
o.process_histogram(h);
});
});
assert!(sequential.ema().iter().eq(fresh.ema().iter()));
}
}
}
}
File diff suppressed because it is too large Load Diff
+72
View File
@@ -0,0 +1,72 @@
use brk_types::{Histogram, Sats};
pub const BINS_PER_DECADE: usize = 200;
const MIN_LOG_BTC: i32 = -8;
const MAX_LOG_BTC: i32 = 4;
pub const NUM_BINS: usize = BINS_PER_DECADE * (MAX_LOG_BTC - MIN_LOG_BTC) as usize;
/// Per-bin integer counts on the oracle log scale: used for both oracle-eligible
/// payment histograms and unfiltered output histograms.
pub type HistogramRaw = Histogram<u32, NUM_BINS>;
/// Smoothed EMA over the window, one `f64` per bin. The stencil search reads it,
/// never serialized (projected to [`HistogramEmaCompact`] for the wire).
pub type HistogramEma = Histogram<f64, NUM_BINS>;
/// Quantized `u16` projection of [`HistogramEma`] for the `histogram/ema/*` wire.
pub type HistogramEmaCompact = Histogram<u16, NUM_BINS>;
/// Maps a satoshi value to its log-scale bin index.
/// bin = round(log10(sats) * BINS_PER_DECADE).
#[inline(always)]
pub fn sats_to_bin(sats: Sats) -> Option<usize> {
if sats.is_zero() {
return None;
}
let bin = ((*sats as f64).log10() * BINS_PER_DECADE as f64).round() as i64;
if bin >= 0 && (bin as usize) < NUM_BINS {
Some(bin as usize)
} else {
None
}
}
/// Converts a fractional bin to a USD price in cents.
/// For a $D output at price P: sats = D * 1e8 / P, so P = 10^(10 - bin/200) dollars,
/// where 10 = log10($100 reference * 1e8 sats/BTC).
#[inline]
pub fn bin_to_cents(bin: f64) -> u64 {
let dollars = 10.0_f64.powf(10.0 - bin / BINS_PER_DECADE as f64);
(dollars * 100.0).round() as u64
}
/// Converts a USD price in cents to a fractional bin (inverse of bin_to_cents).
#[inline]
pub fn cents_to_bin(cents: f64) -> f64 {
(10.0 - (cents / 100.0).log10()) * BINS_PER_DECADE as f64
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sats_to_bin_round_trip() {
assert_eq!(sats_to_bin(Sats::new(100_000_000)), Some(1600));
assert_eq!(sats_to_bin(Sats::new(1)), Some(0));
assert_eq!(sats_to_bin(Sats::ZERO), None);
}
#[test]
fn bin_to_cents_known_values() {
assert_eq!(bin_to_cents(1600.0), 10000);
assert_eq!(bin_to_cents(1800.0), 1000);
}
#[test]
fn sats_to_bin_boundary() {
assert_eq!(sats_to_bin(Sats::new(1_000_000_000_000)), None);
let sats = 10.0_f64.powf(11.995) as u64;
assert!(sats_to_bin(Sats::new(sats)).is_some());
}
}
+72
View File
@@ -0,0 +1,72 @@
use crate::{
scale::HistogramEma,
stencil::{N_ARMS, normalized_arms_at},
};
/// EMA rate for the adaptive shape template (~250-block time constant), slow
/// enough that a transient octave slide can't corrupt the profile before the
/// pick recovers.
const SHAPE_BETA: f64 = 0.004;
/// Adaptive shape-anchoring restoring force for the slow cold-start regime.
///
/// Holds a round-USD shape template (`profile`), re-estimated each block from the
/// arm vector at the pick, and adds a per-candidate score pulling the search
/// toward the octave whose payment shape looks real. This lets the slow EMA
/// resist round-USD octave aliasing in the thin pre-2018 output mix.
///
/// A zero `weight` makes it inert ([`score`](Self::score) returns 0,
/// [`update`](Self::update) is a no-op), so the fast regime carries it for free
/// without call sites special-casing the disabled path.
#[derive(Clone)]
pub(crate) struct ShapeAnchor {
weight: f64,
/// Seeded flat (every arm equal). The slow EMA learns the real payment shape
/// within a few hundred blocks, so no hand-tuned starting guess is needed.
profile: [f64; N_ARMS],
}
impl ShapeAnchor {
pub(crate) fn new(weight: f64) -> Self {
Self {
weight,
profile: [1.0 / N_ARMS as f64; N_ARMS],
}
}
/// Restoring-force contribution to a candidate bin's score: `weight` times the
/// shape match against the learned profile. 0 when inert or the bin is empty.
pub(crate) fn score(&self, ema: &HistogramEma, bin: i64) -> f64 {
if self.weight == 0.0 {
return 0.0;
}
self.weight * self.shape_match(ema, bin)
}
/// Blend the L1-normalized arm shape at `pick` into the profile (slow EMA,
/// [`SHAPE_BETA`]). No-op when inert or the pick is empty.
pub(crate) fn update(&mut self, ema: &HistogramEma, pick: i64) {
if self.weight == 0.0 {
return;
}
if let Some(arms) = normalized_arms_at(ema, pick) {
(0..N_ARMS).for_each(|i| {
self.profile[i] = (1.0 - SHAPE_BETA) * self.profile[i] + SHAPE_BETA * arms[i];
});
}
}
/// Shape match `1 - L1distance` between the candidate's L1-normalized arm
/// vector and the profile. 1.0 is an identical shape and it falls as mass
/// shifts off the round-USD ladder. 0 for an empty (no-mass) center.
fn shape_match(&self, ema: &HistogramEma, center: i64) -> f64 {
match normalized_arms_at(ema, center) {
Some(arms) => {
1.0 - (0..N_ARMS)
.map(|i| (arms[i] - self.profile[i]).abs())
.sum::<f64>()
}
None => 0.0,
}
}
}
+129
View File
@@ -0,0 +1,129 @@
use crate::{
scale::{HistogramEma, NUM_BINS},
shape::ShapeAnchor,
};
/// Bin offsets for 19 round-USD amounts relative to the $100 reference (offset 0).
/// Each offset = log10(amount / 100) * BINS_PER_DECADE.
const STENCIL_OFFSETS: [i32; 19] = [
-400, // $1
-340, // $2
-305, // $3
-260, // $5
-200, // $10
-165, // $15
-140, // $20
-120, // $25
-105, // $30
-60, // $50
0, // $100
35, // $150
60, // $200
95, // $300
140, // $500
200, // $1000
260, // $2000
340, // $5000
400, // $10000
];
/// Number of round-USD stencil arms.
pub(crate) const N_ARMS: usize = STENCIL_OFFSETS.len();
/// EMA mass at `idx`, or 0.0 when the index falls outside the histogram.
#[inline(always)]
fn bin_value(ema: &HistogramEma, idx: i64) -> f64 {
if idx >= 0 && (idx as usize) < NUM_BINS {
ema[idx as usize]
} else {
0.0
}
}
/// Raw EMA mass on each of the 19 stencil arms at `center`.
fn arms_at(ema: &HistogramEma, center: i64) -> [f64; N_ARMS] {
STENCIL_OFFSETS.map(|offset| bin_value(ema, center + offset as i64))
}
/// [`arms_at`] L1-normalized to sum 1, or `None` when the center carries no mass.
pub(crate) fn normalized_arms_at(ema: &HistogramEma, center: i64) -> Option<[f64; N_ARMS]> {
let mut arms = arms_at(ema, center);
let sum: f64 = arms.iter().sum();
if sum <= 0.0 {
return None;
}
for arm in &mut arms {
*arm /= sum;
}
Some(arms)
}
/// Scores each candidate bin in the search window by summing normalized stencil
/// matches across the EMA histogram, then refines with parabolic interpolation.
/// Each candidate also picks up `shape`'s shape-anchoring restoring force, which
/// is inert (adds 0) outside the slow cold-start regime.
pub(crate) fn find_best_bin(
ema: &HistogramEma,
prev_bin: f64,
search_below: usize,
search_above: usize,
shape: &ShapeAnchor,
) -> f64 {
let center = prev_bin.round() as usize;
let search_start = center.saturating_sub(search_below);
let search_end = (center + search_above + 1).min(NUM_BINS);
if search_start >= search_end {
return prev_bin;
}
// Per-offset peak within the search window (for normalization).
let mut arm_peaks = [0.0f64; N_ARMS];
for (i, &offset) in STENCIL_OFFSETS.iter().enumerate() {
for bin in search_start..search_end {
arm_peaks[i] = arm_peaks[i].max(bin_value(ema, bin as i64 + offset as i64));
}
}
let score = |bin: usize| -> f64 {
let mut total = 0.0;
for (i, &offset) in STENCIL_OFFSETS.iter().enumerate() {
if arm_peaks[i] > 0.0 {
total += bin_value(ema, bin as i64 + offset as i64) / arm_peaks[i];
}
}
total += shape.score(ema, bin as i64);
total
};
let mut best_bin = search_start;
let mut best_score = score(search_start);
for bin in (search_start + 1)..search_end {
let candidate = score(bin);
if candidate > best_score {
best_score = candidate;
best_bin = bin;
}
}
// Parabolic sub-bin interpolation for fractional precision.
let score_center = best_score;
let score_left = if best_bin > search_start {
score(best_bin - 1)
} else {
score_center
};
let score_right = if best_bin + 1 < search_end {
score(best_bin + 1)
} else {
score_center
};
let denom = score_left - 2.0 * score_center + score_right;
let sub_bin = if denom.abs() > 1e-10 {
(0.5 * (score_left - score_right) / denom).clamp(-0.5, 0.5)
} else {
0.0
};
best_bin as f64 + sub_bin
}
+74
View File
@@ -0,0 +1,74 @@
use crate::scale::{HistogramEma, HistogramRaw};
/// A sliding window of the most recent raw block histograms and their weighted
/// exponential moving average.
///
/// [`push`](Self::push) records a block into a fixed-size ring.
/// [`recompute`](Self::recompute) folds the ring into [`ema`](Self::ema) with
/// per-age weights `alpha * (1 - alpha)^age` (newest block is age 0). Recording
/// and recomputing are separate steps so warm-up can fill the ring without
/// paying for the EMA until the first real query.
#[derive(Clone)]
pub(crate) struct EmaWindow {
histograms: Vec<HistogramRaw>,
weights: Vec<f64>,
ema: Box<HistogramEma>,
cursor: usize,
filled: usize,
}
impl EmaWindow {
pub(crate) fn new(window_size: usize, alpha: f64) -> Self {
let decay = 1.0 - alpha;
let weights = (0..window_size)
.map(|i| alpha * decay.powi(i as i32))
.collect();
Self {
histograms: vec![HistogramRaw::zeros(); window_size],
weights,
ema: Box::new(HistogramEma::zeros()),
cursor: 0,
filled: 0,
}
}
/// Record `hist` as the newest block, evicting the oldest once full.
pub(crate) fn push(&mut self, hist: &HistogramRaw) {
let window = self.histograms.len();
self.histograms[self.cursor] = hist.clone();
self.cursor = (self.cursor + 1) % window;
self.filled = (self.filled + 1).min(window);
}
/// Ring index of the block `age` steps back from the newest (age 0).
fn index_at_age(&self, age: usize) -> usize {
let window = self.histograms.len();
(self.cursor + window - 1 - age) % window
}
/// Fold the ring into the weighted EMA, newest block weighted `weights[0]`.
pub(crate) fn recompute(&mut self) {
self.ema.fill(0.0);
for age in 0..self.filled {
let weight = self.weights[age];
let h = &self.histograms[self.index_at_age(age)];
self.ema
.iter_mut()
.zip(h.iter())
.for_each(|(e, &c)| *e += weight * c as f64);
}
}
pub(crate) fn ema(&self) -> &HistogramEma {
&self.ema
}
/// The most recent `min(filled, n)` raw histograms, oldest first - the
/// hand-off a regime switch replays into a fresh window of size `n`.
pub(crate) fn recent(&self, n: usize) -> Vec<HistogramRaw> {
(0..self.filled.min(n))
.rev()
.map(|age| self.histograms[self.index_at_age(age)].clone())
.collect()
}
}
+1
View File
@@ -3,6 +3,7 @@ mod block;
mod cpfp;
mod mempool;
mod mining;
mod oracle;
mod price;
mod series;
mod tx;
+258
View File
@@ -0,0 +1,258 @@
use std::{ops::Range, sync::Arc};
use brk_computer::prices::Vecs as PricesVecs;
use brk_error::{Error, Result};
use brk_indexer::Lengths;
use brk_oracle::{
cents_to_bin, sats_to_bin, Config, HistogramEma, HistogramEmaCompact, HistogramRaw, Oracle,
};
use brk_types::{Day1, Dollars, TxOutIndex};
use vecdb::{AnyVec, ReadableVec, VecIndex};
use crate::Query;
impl Query {
pub fn live_price(&self) -> Result<Dollars> {
Ok(self.live_oracle()?.price_dollars())
}
/// Smoothed payment output histogram at the live tip, quantized for the wire.
pub fn live_payment_histogram(&self) -> Result<HistogramEmaCompact> {
Ok(self.live_oracle()?.ema().to_compact())
}
/// Smoothed payment output histogram for a confirmed `height`, deterministically
/// reconstructed by replaying the window ending at `height`. EMA values are
/// seed-independent, so the result is exact.
pub fn confirmed_payment_histogram(&self, height: usize) -> Result<HistogramEmaCompact> {
let safe = self.check_histogram_height(height)?;
Ok(self.ema_oracle_at(height, &safe)?.ema().to_compact())
}
/// Smoothed payment output histogram for a calendar `day`: the bin-by-bin average of
/// every confirmed block's per-block EMA. The first block in each EMA config
/// segment is reconstructed exactly, then later blocks in the segment are walked
/// sequentially. Averaging keeps the result an intensive per-block rate rather
/// than letting a busy day dominate.
pub fn confirmed_payment_histogram_day(&self, day: Day1) -> Result<HistogramEmaCompact> {
let safe = self.safe_lengths();
let range = self.day_block_range(day, &safe)?;
Ok(self
.average_payment_histogram_range(range, &safe)?
.to_compact())
}
fn average_payment_histogram_range(
&self,
range: Range<usize>,
safe: &Lengths,
) -> Result<HistogramEma> {
let count = range.len();
let mut acc = HistogramEma::zeros();
for segment in Config::segments_for_range(range) {
let mut oracle = self.ema_oracle_at(segment.start, safe)?;
acc.add_from(oracle.ema());
let feed_start = segment.start + 1;
if feed_start < segment.end {
PricesVecs::feed_blocks_with(
&mut oracle,
self.indexer(),
feed_start..segment.end,
Some(safe),
|_, oracle, _| acc.add_from(oracle.ema()),
);
}
}
acc.divide_by(count as f64);
Ok(acc)
}
/// Unfiltered per-bin output counts at the live tip: every forming-block
/// mempool output binned by value, with none of the round-dollar payment
/// filters applied. Zeros when no mempool is configured.
pub fn live_output_histogram(&self) -> Result<HistogramRaw> {
Ok(match self.mempool() {
Some(mempool) => mempool.live_raw_histogram(),
None => HistogramRaw::zeros(),
})
}
/// Unfiltered per-bin output counts for a confirmed `height`: every output
/// in the block binned by value, with no payment filtering.
pub fn confirmed_output_histogram(&self, height: usize) -> Result<HistogramRaw> {
let safe = self.check_histogram_height(height)?;
Ok(self.output_histogram_for_blocks(height..height + 1, &safe))
}
/// Unfiltered per-bin output counts for a calendar `day`: every block's output
/// histogram summed bin-by-bin. Raw counts are additive, so the day total is
/// just the sum across its confirmed blocks.
pub fn confirmed_output_histogram_day(&self, day: Day1) -> Result<HistogramRaw> {
let safe = self.safe_lengths();
let range = self.day_block_range(day, &safe)?;
Ok(self.output_histogram_for_blocks(range, &safe))
}
/// The live tip oracle: the cached committed base, with the forming block's
/// mempool outputs blended in as a final slot when a mempool is configured.
fn live_oracle(&self) -> Result<Oracle> {
let mut oracle = (*self.cached_oracle()?).clone();
if let Some(mempool) = self.mempool() {
oracle.process_histogram(&mempool.live_eligible_histogram());
}
Ok(oracle)
}
/// Tip oracle warmed over the last `window_size` committed blocks, seeded
/// from the last committed price. Cached per tip height; rebuilt on advance
/// or reorg.
fn cached_oracle(&self) -> Result<Arc<Oracle>> {
let safe = self.safe_lengths();
let height = safe.height;
if let Some(oracle) = self
.0
.live_oracle
.read()
.unwrap()
.as_ref()
.filter(|(h, _)| *h == height)
.map(|(_, o)| o.clone())
{
return Ok(oracle);
}
let last = self
.computer()
.prices
.spot
.cents
.height
.len()
.saturating_sub(1);
let seed_bin = self.seed_bin_at(last)?;
let oracle = Arc::new(self.warm_oracle(seed_bin, height.to_usize(), &safe));
let mut cache = self.0.live_oracle.write().unwrap();
if cache.as_ref().is_none_or(|(h, _)| *h != height) {
*cache = Some((height, oracle.clone()));
}
Ok(oracle)
}
/// Oracle warmed to just after `height`, ready for its per-block EMA. Seeds
/// from the stored spot price at `height`, though the EMA is seed-independent
/// so the seed only sets the price read-out, not the window contents.
fn ema_oracle_at(&self, height: usize, safe: &Lengths) -> Result<Oracle> {
let seed_bin = self.seed_bin_at(height)?;
Ok(self.warm_oracle(seed_bin, height + 1, safe))
}
/// An oracle seeded at `seed_bin` and warmed by replaying the `window_size`
/// committed blocks ending just before `end`. Reads are capped at `safe` so
/// concurrent indexer writes past the cap stay invisible.
fn warm_oracle(&self, seed_bin: f64, end: usize, safe: &Lengths) -> Oracle {
let config = Config::for_height(end.saturating_sub(1));
let start = end.saturating_sub(config.window_size);
Oracle::from_checkpoint(seed_bin, config, |o| {
PricesVecs::feed_blocks_for_warmup(o, self.indexer(), start..end, Some(safe));
})
}
/// Seed bin for an oracle warm-up: the stored spot price at `height` mapped
/// `cents -> bin`. 404s when the oracle prices aren't computed that far yet,
/// which also covers the stamp-before-write race where the vec length leads
/// the readable data.
fn seed_bin_at(&self, height: usize) -> Result<f64> {
let cents = self
.computer()
.prices
.spot
.cents
.height
.collect_one_at(height)
.ok_or_else(|| Error::NotFound("oracle prices not yet computed".to_string()))?;
Ok(cents_to_bin(cents.inner() as f64))
}
fn histogram_bound(&self, safe: &Lengths) -> usize {
self.computer()
.prices
.spot
.cents
.height
.len()
.min(safe.height.to_usize())
}
/// `height < min(spot price len, safe height)` or 404.
/// Returns the safe lengths so callers cap reads at the same bound.
fn check_histogram_height(&self, height: usize) -> Result<Lengths> {
let safe = self.safe_lengths();
let bound = self.histogram_bound(&safe);
if height >= bound {
return Err(Error::NotFound(format!(
"oracle histogram unavailable for height {height}"
)));
}
Ok(safe)
}
/// The confirmed block heights `[first, end)` of calendar `day`, clamped to
/// the same histogram-available bound as `check_histogram_height`. 404 when
/// the day has no committed blocks in range.
fn day_block_range(&self, day: Day1, safe: &Lengths) -> Result<Range<usize>> {
let first_height = &self.computer().indexes.day1.first_height;
let bound = self.histogram_bound(safe);
let start = first_height
.collect_one(day)
.map_or(usize::MAX, |h| h.to_usize());
let end = first_height
.collect_one(day + 1)
.map_or(bound, |h| h.to_usize())
.min(bound);
if start >= end {
return Err(Error::NotFound(format!(
"oracle histogram unavailable for day {day}"
)));
}
Ok(start..end)
}
/// Unfiltered histogram for a contiguous confirmed block range: every output,
/// coinbase included, binned by value via `sats_to_bin` with no payment
/// filtering. Raw counts are additive, so a day can be read as one output
/// range instead of one block at a time.
fn output_histogram_for_blocks(&self, range: Range<usize>, safe: &Lengths) -> HistogramRaw {
let indexer = self.indexer();
let safe_height = safe.height.to_usize();
let total_outputs = safe.txout_index.to_usize();
let first_txout_index = &indexer.vecs.outputs.first_txout_index;
let out_start = first_txout_index
.collect_one_at(range.start)
.unwrap()
.to_usize();
let out_end = if range.end < safe_height {
first_txout_index.collect_one_at(range.end).unwrap()
} else {
TxOutIndex::from(total_outputs)
}
.to_usize();
let mut hist = HistogramRaw::zeros();
indexer
.vecs
.outputs
.value
.for_each_range_at(out_start, out_end, |sats| {
if let Some(bin) = sats_to_bin(sats) {
hist.increment(bin);
}
});
hist
}
}
+2 -60
View File
@@ -1,70 +1,12 @@
use std::sync::Arc;
use brk_computer::prices::Vecs as PricesVecs;
use brk_error::{Error, Result};
use brk_oracle::{Config, Oracle, cents_to_bin};
use brk_error::Result;
use brk_types::{
Dollars, ExchangeRates, HistoricalPrice, HistoricalPriceEntry, Hour4, INDEX_EPOCH, Timestamp,
};
use vecdb::{AnyVec, ReadableVec, VecIndex};
use vecdb::ReadableVec;
use crate::Query;
impl Query {
pub fn live_price(&self) -> Result<Dollars> {
let base = self.cached_oracle()?;
Ok(match self.mempool() {
Some(mempool) => {
let mut oracle = (*base).clone();
oracle.process_histogram(&mempool.live_histogram());
oracle.price_dollars()
}
None => base.price_dollars(),
})
}
/// Oracle warmed by the last `window_size` committed blocks, seeded from
/// the last committed price. Cached per tip height; rebuilt on advance or
/// reorg. Reads are capped at `safe_lengths` so concurrent indexer writes
/// stay invisible.
fn cached_oracle(&self) -> Result<Arc<Oracle>> {
let safe_lengths = self.safe_lengths();
let height = safe_lengths.height;
if let Some(oracle) = self
.0
.live_oracle
.read()
.unwrap()
.as_ref()
.filter(|(h, _)| *h == height)
.map(|(_, o)| o.clone())
{
return Ok(oracle);
}
let cents_height = &self.computer().prices.spot.cents.height;
let last_cents = cents_height
.len()
.checked_sub(1)
.and_then(|i| cents_height.collect_one_at(i))
.ok_or_else(|| Error::NotFound("oracle prices not yet computed".to_string()))?;
let config = Config::default();
let seed_bin = cents_to_bin(last_cents.inner() as f64);
let tip = height.to_usize();
let warmup_range = tip.saturating_sub(config.window_size)..tip;
let oracle = Arc::new(Oracle::from_checkpoint(seed_bin, config, |o| {
PricesVecs::feed_blocks(o, self.indexer(), warmup_range, Some(&safe_lengths));
}));
let mut cache = self.0.live_oracle.write().unwrap();
if cache.as_ref().is_none_or(|(h, _)| *h != height) {
*cache = Some((height, oracle.clone()));
}
Ok(oracle)
}
pub fn historical_price(&self, timestamp: Option<Timestamp>) -> Result<HistoricalPrice> {
let prices = match timestamp {
Some(ts) => self.price_at(ts)?,
+1
View File
@@ -19,6 +19,7 @@ brk_computer = { workspace = true }
brk_error = { workspace = true, features = ["jiff", "serde_json", "tokio", "vecdb"] }
brk_indexer = { workspace = true }
brk_logger = { workspace = true }
brk_oracle = { workspace = true }
brk_query = { workspace = true }
brk_reader = { workspace = true }
brk_rpc = { workspace = true }
+3
View File
@@ -25,6 +25,7 @@ mod mempool;
mod metrics;
mod mining;
mod openapi;
mod oracle;
mod series;
mod series_legacy;
mod server;
@@ -38,6 +39,7 @@ use general::GeneralRoutes;
use mempool::MempoolRoutes;
use mining::MiningRoutes;
pub use openapi::*;
use oracle::OracleRoutes;
use transactions::TxRoutes;
pub trait ApiRoutes {
@@ -57,6 +59,7 @@ impl ApiRoutes for ApiRouter<AppState> {
.add_mining_routes()
.add_fees_routes()
.add_mempool_routes()
.add_oracle_routes()
.add_tx_routes()
.api_route(
"/openapi.json",
+15
View File
@@ -177,6 +177,21 @@ All errors return structured JSON with a consistent format:
),
..Default::default()
},
Tag {
name: "Oracle".to_string(),
description: Some(
"On-chain BTC/USD price derived purely from round-dollar payment patterns in \
transaction outputs, with no external price feed. Payment activity is binned on a \
log scale, and a smoothed EMA over recent blocks locates the price.\n\n\
Histograms come in two flavors, each available at the live tip (mempool-blended) \
or at any confirmed height: `raw` bins every output by value with no filtering, \
while `ema` is the smoothed round-dollar window the price is read from. The live \
price is also at `/api/mempool/price`. Confirmed per-height price history is at \
`/api/vecs/height-to-price`."
.to_string(),
),
..Default::default()
},
Tag {
name: "URPD".to_string(),
description: Some(
+195
View File
@@ -0,0 +1,195 @@
use aide::axum::{ApiRouter, routing::get_with};
use axum::{
extract::{Path, State},
http::{HeaderMap, Uri},
response::IntoResponse,
};
use brk_oracle::{HistogramEmaCompact, HistogramRaw};
use brk_types::{Day1, Dollars, Version};
use crate::{
AppState,
extended::TransformResponseExtended,
params::{Empty, HeightOrDate, HeightOrDateParam},
};
pub trait OracleRoutes {
fn add_oracle_routes(self) -> Self;
}
impl OracleRoutes for ApiRouter<AppState> {
fn add_oracle_routes(self) -> Self {
self.api_route(
"/api/oracle/price",
get_with(
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
state
.respond_json(&headers, state.mempool_strategy(), &uri, |q| q.live_price())
.await
},
|op| {
op.id("get_oracle_price")
.oracle_tag()
.summary("Live BTC/USD price")
.description(
"Current BTC/USD price in dollars. Same value as \
`/api/mempool/price`. Confirmed per-height history is available at \
`/api/vecs/height-to-price`.",
)
.json_response::<Dollars>()
.not_modified()
.server_error()
},
),
)
.api_route(
"/api/oracle/histogram/payments/live",
get_with(
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
state
.respond_json(&headers, state.mempool_strategy(), &uri, |q| {
q.live_payment_histogram()
})
.await
},
|op| {
op.id("get_oracle_histogram_payments_live")
.oracle_tag()
.summary("Live payment output histogram")
.description(
"Live smoothed histogram of oracle-eligible payment outputs, binned \
by output value on the oracle log scale. It combines the committed \
oracle window with the forming mempool block. A flat array of \
log-scale bins.",
)
.json_response::<HistogramEmaCompact>()
.not_modified()
.server_error()
},
),
)
.api_route(
"/api/oracle/histogram/payments/{point}",
get_with(
async |uri: Uri,
headers: HeaderMap,
Path(path): Path<HeightOrDateParam>,
_: Empty,
State(state): State<AppState>| {
let version = Version::new(brk_oracle::VERSION);
match path.resolve() {
Ok(HeightOrDate::Date(date)) => {
let strategy = state.date_strategy(version, date);
state
.respond_json(&headers, strategy, &uri, move |q| {
q.confirmed_payment_histogram_day(Day1::try_from(date)?)
})
.await
}
Ok(HeightOrDate::Height(height)) => {
let strategy = state.height_strategy(version, height);
state
.respond_json(&headers, strategy, &uri, move |q| {
q.confirmed_payment_histogram(usize::from(height))
})
.await
}
Err(e) => e.into_response(),
}
},
|op| {
op.id("get_oracle_histogram_payments")
.oracle_tag()
.summary("Payment output histogram at height or day")
.description(
"Smoothed histogram of oracle-eligible payment outputs for a \
confirmed point. A block height (`840000`) gives that block's oracle \
payment histogram; a calendar date (`YYYY-MM-DD`) gives the average \
of that day's per-block payment histograms. A flat array of log-scale \
bins.",
)
.json_response::<HistogramEmaCompact>()
.not_modified()
.bad_request()
.not_found()
.server_error()
},
),
)
.api_route(
"/api/oracle/histogram/outputs/live",
get_with(
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
state
.respond_json(&headers, state.mempool_strategy(), &uri, |q| {
q.live_output_histogram()
})
.await
},
|op| {
op.id("get_oracle_histogram_outputs_live")
.oracle_tag()
.summary("Live output value histogram")
.description(
"Live unfiltered output value histogram for the forming mempool \
block. Every live output is binned by value on the oracle log scale; \
no oracle payment filters are applied. A flat array of log-scale \
bins, all zero when no mempool is configured.",
)
.json_response::<HistogramRaw>()
.not_modified()
.server_error()
},
),
)
.api_route(
"/api/oracle/histogram/outputs/{point}",
get_with(
async |uri: Uri,
headers: HeaderMap,
Path(path): Path<HeightOrDateParam>,
_: Empty,
State(state): State<AppState>| {
let version = Version::new(brk_oracle::VERSION);
match path.resolve() {
Ok(HeightOrDate::Date(date)) => {
let strategy = state.date_strategy(version, date);
state
.respond_json(&headers, strategy, &uri, move |q| {
q.confirmed_output_histogram_day(Day1::try_from(date)?)
})
.await
}
Ok(HeightOrDate::Height(height)) => {
let strategy = state.height_strategy(version, height);
state
.respond_json(&headers, strategy, &uri, move |q| {
q.confirmed_output_histogram(usize::from(height))
})
.await
}
Err(e) => e.into_response(),
}
},
|op| {
op.id("get_oracle_histogram_outputs")
.oracle_tag()
.summary("Output value histogram at height or day")
.description(
"Unfiltered output value histogram for a confirmed point. A block \
height (`840000`) gives every output in that block, coinbase \
included, binned by value on the oracle log scale; a calendar date \
(`YYYY-MM-DD`) sums every block that day. A flat array of log-scale \
bins.",
)
.json_response::<HistogramRaw>()
.not_modified()
.bad_request()
.not_found()
.server_error()
},
),
)
}
}
+4 -3
View File
@@ -16,7 +16,8 @@ use brk_query::{Query as BrkQuery, ResolvedQuery};
use brk_traversable::TreeNode;
use brk_types::{
DataRangeFormat, Format, IndexInfo, Output, PaginatedSeries, Pagination, SearchQuery,
SeriesCount, SeriesData, SeriesInfo, SeriesNameWithIndex, SeriesSelection,
SeriesCount, SeriesData, SeriesInfo, SeriesNameWithIndex, SeriesOutput, SeriesSelection,
Version,
};
use crate::{
@@ -67,7 +68,7 @@ pub(super) async fn serve(
.await)
}
fn output_to_bytes(out: brk_types::SeriesOutput) -> BrkResult<Bytes> {
fn output_to_bytes(out: SeriesOutput) -> BrkResult<Bytes> {
Ok(match out.output {
Output::CSV(s) => Bytes::from(s),
Output::Json(v) => Bytes::from(v),
@@ -365,7 +366,7 @@ impl ApiSeriesRoutes for ApiRouter<AppState> {
.series_tag()
.summary("Get series version")
.description("Returns the current version of a series. Changes when the series data is updated.")
.json_response::<brk_types::Version>()
.json_response::<Version>()
.not_modified()
.not_found(),
),
@@ -12,6 +12,7 @@ pub trait TransformResponseExtended<'t> {
fn mining_tag(self) -> Self;
fn fees_tag(self) -> Self;
fn mempool_tag(self) -> Self;
fn oracle_tag(self) -> Self;
fn transactions_tag(self) -> Self;
fn server_tag(self) -> Self;
fn series_tag(self) -> Self;
@@ -73,6 +74,10 @@ impl<'t> TransformResponseExtended<'t> for TransformOperation<'t> {
self.tag("Mempool")
}
fn oracle_tag(self) -> Self {
self.tag("Oracle")
}
fn transactions_tag(self) -> Self {
self.tag("Transactions")
}
@@ -0,0 +1,38 @@
use brk_types::{Date, Height};
use schemars::JsonSchema;
use serde::Deserialize;
use crate::Error;
/// Path parameter accepting either a block height (`840000`) or a calendar date
/// (`YYYY-MM-DD`). The handler resolves it and dispatches to the per-height or
/// per-day variant, choosing the matching cache strategy.
#[derive(Deserialize, JsonSchema)]
pub struct HeightOrDateParam {
#[schemars(example = &"840000")]
pub point: String,
}
/// A resolved [`HeightOrDateParam`]: a confirmed block height or a calendar day.
pub enum HeightOrDate {
Height(Height),
Date(Date),
}
impl HeightOrDateParam {
/// Parses the raw `point`: a `YYYY-MM-DD` string is a [`Date`], an all-digit
/// string is a [`Height`], anything else is a 400. Dates are tried first
/// because their dashes keep them from parsing as a height.
pub fn resolve(&self) -> Result<HeightOrDate, Error> {
if let Ok(date) = self.point.parse::<Date>() {
Ok(HeightOrDate::Date(date))
} else if let Ok(height) = self.point.parse::<usize>() {
Ok(HeightOrDate::Height(Height::from(height)))
} else {
Err(Error::bad_request(format!(
"expected a block height or YYYY-MM-DD date, got `{}`",
self.point
)))
}
}
}
+2
View File
@@ -5,6 +5,7 @@ mod blockhash_param;
mod blockhash_start_index;
mod blockhash_tx_index;
mod empty;
mod height_or_date_param;
mod height_param;
mod next_block_hash_param;
mod pool_slug_param;
@@ -25,6 +26,7 @@ pub use blockhash_param::*;
pub use blockhash_start_index::*;
pub use blockhash_tx_index::*;
pub use empty::*;
pub use height_or_date_param::*;
pub use height_param::*;
pub use next_block_hash_param::*;
pub use pool_slug_param::*;
+160
View File
@@ -0,0 +1,160 @@
use std::{
fmt,
marker::PhantomData,
ops::{Deref, DerefMut},
};
use schemars::{JsonSchema, SchemaGenerator};
use serde::{
Deserialize, Deserializer, Serialize, Serializer,
de::{SeqAccess, Visitor},
};
/// Fixed-length, log-scale bin histogram generic over the per-bin counter type.
/// Instantiated as raw counts (`u32`), the smoothed EMA buffer (`f64`), or the
/// quantized wire projection (`u16`). Serializes as a flat JSON array of `N`
/// values. `Deref` exposes the underlying array for indexing and iteration.
///
/// Backed by a fixed `[T; N]` (not a `Vec`) to keep the always-`N` invariant the
/// callers rely on.
#[derive(Clone, Debug)]
pub struct Histogram<T, const N: usize>([T; N]);
impl<T: Copy + Default, const N: usize> Histogram<T, N> {
#[inline]
pub fn zeros() -> Self {
Self([T::default(); N])
}
}
impl<T: Copy + Default, const N: usize> Default for Histogram<T, N> {
fn default() -> Self {
Self::zeros()
}
}
impl<T, const N: usize> Deref for Histogram<T, N> {
type Target = [T; N];
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T, const N: usize> DerefMut for Histogram<T, N> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<const N: usize> Histogram<u32, N> {
/// Bump the count in `bin` by one.
#[inline]
pub fn increment(&mut self, bin: usize) {
self.0[bin] += 1;
}
}
impl<const N: usize> Histogram<f64, N> {
/// Quantize each bin to `u16` (round, then clamp into range) for the wire.
/// Lossy by design: faint sub-0.5 bins vanish, which is invisible on a heatmap.
pub fn to_compact(&self) -> Histogram<u16, N> {
let mut out = [0u16; N];
for (o, &v) in out.iter_mut().zip(self.0.iter()) {
*o = v.round().clamp(0.0, u16::MAX as f64) as u16;
}
Histogram(out)
}
/// Add another floating-point histogram bin-by-bin.
#[inline]
pub fn add_from(&mut self, rhs: &Self) {
self.0
.iter_mut()
.zip(rhs.0.iter())
.for_each(|(a, &b)| *a += b);
}
/// Divide every bin by `rhs`.
#[inline]
pub fn divide_by(&mut self, rhs: f64) {
self.0.iter_mut().for_each(|v| *v /= rhs);
}
}
impl<T: Serialize, const N: usize> Serialize for Histogram<T, N> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.0.as_slice().serialize(serializer)
}
}
impl<'de, T: Deserialize<'de> + Copy + Default, const N: usize> Deserialize<'de>
for Histogram<T, N>
{
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct ArrayVisitor<T, const N: usize>(PhantomData<T>);
impl<'de, T: Deserialize<'de> + Copy + Default, const N: usize> Visitor<'de>
for ArrayVisitor<T, N>
{
type Value = Histogram<T, N>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "an array of {N} values")
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut bins = [T::default(); N];
for (i, bin) in bins.iter_mut().enumerate() {
*bin = seq
.next_element()?
.ok_or_else(|| serde::de::Error::invalid_length(i, &self))?;
}
Ok(Histogram(bins))
}
}
deserializer.deserialize_seq(ArrayVisitor::<T, N>(PhantomData))
}
}
impl<T: JsonSchema, const N: usize> JsonSchema for Histogram<T, N> {
fn schema_name() -> std::borrow::Cow<'static, str> {
format!("Histogram_{}", T::schema_name()).into()
}
fn json_schema(generator: &mut SchemaGenerator) -> schemars::Schema {
Vec::<T>::json_schema(generator)
}
/// Inline as a plain array rather than registering a named `Histogram_uintN`
/// component: the wire shape is just a flat array of counts, and the synthetic
/// generic-mangled name has no real type for the Rust client to resolve to.
fn inline_schema() -> bool {
true
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn float_histogram_add_and_divide_are_binwise() {
let mut a = Histogram::<f64, 3>::zeros();
a[0] = 1.0;
a[1] = 2.0;
a[2] = 3.0;
let mut b = Histogram::<f64, 3>::zeros();
b[0] = 3.0;
b[1] = 4.0;
b[2] = 5.0;
a.add_from(&b);
a.divide_by(2.0);
assert_eq!(*a, [2.0, 3.0, 4.0]);
}
}
+5 -5
View File
@@ -32,6 +32,9 @@ mod block_rewards_entry;
mod block_size_entry;
mod block_sizes_weights;
mod block_status;
mod block_template;
mod block_template_diff;
mod block_template_diff_entry;
mod block_timestamp;
mod block_tx_index;
mod block_weight_entry;
@@ -73,6 +76,7 @@ mod hashrate_summary;
mod health;
mod height;
mod hex;
mod histogram;
mod historical_price;
mod hour1;
mod hour12;
@@ -80,9 +84,6 @@ mod hour4;
mod index;
mod index_info;
mod limit;
mod block_template;
mod block_template_diff;
mod block_template_diff_entry;
mod mempool_block;
mod mempool_entry_info;
mod mempool_info;
@@ -97,7 +98,6 @@ mod next_block_hash;
mod ohlc;
mod op_return_index;
mod option_ext;
mod oracle_bins;
mod outpoint;
mod outpoint_prefix;
mod output;
@@ -273,6 +273,7 @@ pub use hashrate_summary::*;
pub use health::*;
pub use height::*;
pub use hex::*;
pub use histogram::*;
pub use historical_price::*;
pub use hour1::*;
pub use hour4::*;
@@ -294,7 +295,6 @@ pub use next_block_hash::*;
pub use ohlc::*;
pub use op_return_index::*;
pub use option_ext::*;
pub use oracle_bins::*;
pub use outpoint::*;
pub use outpoint_prefix::*;
pub use output::*;
-322
View File
@@ -1,322 +0,0 @@
use std::{fmt::Display, mem::size_of};
use schemars::JsonSchema;
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::SeqAccess, de::Visitor};
use vecdb::{Bytes, Formattable};
use crate::Sats;
/// Number of bins for the phase histogram
pub const PHASE_BINS: usize = 100;
/// Phase histogram: counts per bin for frac(log10(sats))
///
/// Used for on-chain price discovery. Each bin represents 1% of the
/// log10 fractional range [0, 1). Values are u16 (max 65535 per bin).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OracleBins {
pub bins: [u16; PHASE_BINS],
}
impl Default for OracleBins {
fn default() -> Self {
Self::ZERO
}
}
impl Display for OracleBins {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "OracleBins(peak={})", self.peak_bin())
}
}
impl Serialize for OracleBins {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.bins.as_slice().serialize(serializer)
}
}
impl<'de> Deserialize<'de> for OracleBins {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct BinsVisitor;
impl<'de> Visitor<'de> for BinsVisitor {
type Value = OracleBins;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, "an array of {} u16 values", PHASE_BINS)
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut bins = [0u16; PHASE_BINS];
for (i, bin) in bins.iter_mut().enumerate() {
*bin = seq
.next_element()?
.ok_or_else(|| serde::de::Error::invalid_length(i, &self))?;
}
Ok(OracleBins { bins })
}
}
deserializer.deserialize_seq(BinsVisitor)
}
}
impl JsonSchema for OracleBins {
fn schema_name() -> std::borrow::Cow<'static, str> {
"OracleBins".into()
}
fn json_schema(_gen: &mut schemars::SchemaGenerator) -> schemars::Schema {
// Represent as array of u16 values
Vec::<u16>::json_schema(_gen)
}
}
impl OracleBins {
pub const ZERO: Self = Self {
bins: [0; PHASE_BINS],
};
/// Get the bin index for a sats value
/// Filters: min 1k sats, max 100k BTC (matches Python 1e-5 to 1e5 BTC)
#[inline]
pub fn sats_to_bin(sats: Sats) -> Option<usize> {
if sats < Sats::_1K || sats > Sats::_100K_BTC {
return None;
}
let log_sats = f64::from(sats).log10();
let phase = log_sats.fract();
let phase = if phase < 0.0 { phase + 1.0 } else { phase };
Some(((phase * PHASE_BINS as f64) as usize).min(PHASE_BINS - 1))
}
/// Add a count to the bin for this sats value
#[inline]
pub fn add(&mut self, sats: Sats) {
if let Some(bin) = Self::sats_to_bin(sats) {
self.bins[bin] = self.bins[bin].saturating_add(1);
}
}
/// Find the peak bin (index with highest count)
pub fn peak_bin(&self) -> usize {
self.bins
.iter()
.enumerate()
.max_by_key(|(_, count)| *count)
.map(|(idx, _)| idx)
.unwrap_or(0)
}
/// Get total count across all bins
pub fn total_count(&self) -> u32 {
self.bins.iter().map(|&c| c as u32).sum()
}
}
impl Bytes for OracleBins {
type Array = [u8; size_of::<Self>()];
fn to_bytes(&self) -> Self::Array {
let mut arr = [0u8; size_of::<Self>()];
for (i, &count) in self.bins.iter().enumerate() {
let bytes = count.to_le_bytes();
arr[i * 2] = bytes[0];
arr[i * 2 + 1] = bytes[1];
}
arr
}
fn from_bytes(bytes: &[u8]) -> vecdb::Result<Self> {
if bytes.len() < size_of::<Self>() {
return Err(vecdb::Error::WrongLength {
received: bytes.len(),
expected: size_of::<Self>(),
});
}
let mut bins = [0u16; PHASE_BINS];
for (i, bin) in bins.iter_mut().enumerate() {
*bin = u16::from_le_bytes([bytes[i * 2], bytes[i * 2 + 1]]);
}
Ok(Self { bins })
}
}
impl Formattable for OracleBins {
fn write_to(&self, buf: &mut Vec<u8>) {
use std::fmt::Write;
let mut s = String::new();
write!(s, "{}", self).unwrap();
buf.extend_from_slice(s.as_bytes());
}
fn fmt_json(&self, buf: &mut Vec<u8>) {
buf.push(b'"');
self.write_to(buf);
buf.push(b'"');
}
}
// ============================================================================
// OracleBinsV2: 200-bin phase histogram for V2 phase oracle
// ============================================================================
/// Number of bins for V2 phase histogram (0.5% resolution)
pub const PHASE_BINS_V2: usize = 200;
/// V2 Phase histogram: counts per bin for frac(log10(sats))
///
/// Used for phase oracle V2 with round USD template matching.
/// Each bin represents 0.5% of the log10 fractional range [0, 1).
/// Values are u16 (max 65535 per bin).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OracleBinsV2 {
pub bins: [u16; PHASE_BINS_V2],
}
impl Default for OracleBinsV2 {
fn default() -> Self {
Self::ZERO
}
}
impl Display for OracleBinsV2 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "OracleBinsV2(peak={})", self.peak_bin())
}
}
impl Serialize for OracleBinsV2 {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.bins.as_slice().serialize(serializer)
}
}
impl<'de> Deserialize<'de> for OracleBinsV2 {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct BinsVisitor;
impl<'de> Visitor<'de> for BinsVisitor {
type Value = OracleBinsV2;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, "an array of {} u16 values", PHASE_BINS_V2)
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut bins = [0u16; PHASE_BINS_V2];
for (i, bin) in bins.iter_mut().enumerate() {
*bin = seq
.next_element()?
.ok_or_else(|| serde::de::Error::invalid_length(i, &self))?;
}
Ok(OracleBinsV2 { bins })
}
}
deserializer.deserialize_seq(BinsVisitor)
}
}
impl JsonSchema for OracleBinsV2 {
fn schema_name() -> std::borrow::Cow<'static, str> {
"OracleBinsV2".into()
}
fn json_schema(_gen: &mut schemars::SchemaGenerator) -> schemars::Schema {
Vec::<u16>::json_schema(_gen)
}
}
impl OracleBinsV2 {
pub const ZERO: Self = Self {
bins: [0; PHASE_BINS_V2],
};
/// Get the bin index for a sats value
/// Filters: min 1k sats, max 100k BTC
#[inline]
pub fn sats_to_bin(sats: Sats) -> Option<usize> {
if sats < Sats::_1K || sats > Sats::_100K_BTC {
return None;
}
let log_sats = f64::from(sats).log10();
let phase = log_sats.fract();
let phase = if phase < 0.0 { phase + 1.0 } else { phase };
Some(((phase * PHASE_BINS_V2 as f64) as usize).min(PHASE_BINS_V2 - 1))
}
/// Add a count to the bin for this sats value
#[inline]
pub fn add(&mut self, sats: Sats) {
if let Some(bin) = Self::sats_to_bin(sats) {
self.bins[bin] = self.bins[bin].saturating_add(1);
}
}
/// Add another histogram to this one
pub fn add_histogram(&mut self, other: &OracleBinsV2) {
for (i, &count) in other.bins.iter().enumerate() {
self.bins[i] = self.bins[i].saturating_add(count);
}
}
/// Find the peak bin (index with highest count)
pub fn peak_bin(&self) -> usize {
self.bins
.iter()
.enumerate()
.max_by_key(|(_, count)| *count)
.map(|(idx, _)| idx)
.unwrap_or(0)
}
/// Get total count across all bins
pub fn total_count(&self) -> u32 {
self.bins.iter().map(|&c| c as u32).sum()
}
}
impl Bytes for OracleBinsV2 {
type Array = [u8; size_of::<Self>()];
fn to_bytes(&self) -> Self::Array {
let mut arr = [0u8; size_of::<Self>()];
for (i, &count) in self.bins.iter().enumerate() {
let bytes = count.to_le_bytes();
arr[i * 2] = bytes[0];
arr[i * 2 + 1] = bytes[1];
}
arr
}
fn from_bytes(bytes: &[u8]) -> vecdb::Result<Self> {
if bytes.len() < size_of::<Self>() {
return Err(vecdb::Error::WrongLength {
received: bytes.len(),
expected: size_of::<Self>(),
});
}
let mut bins = [0u16; PHASE_BINS_V2];
for (i, bin) in bins.iter_mut().enumerate() {
*bin = u16::from_le_bytes([bytes[i * 2], bytes[i * 2 + 1]]);
}
Ok(Self { bins })
}
}
impl Formattable for OracleBinsV2 {
fn write_to(&self, buf: &mut Vec<u8>) {
use std::fmt::Write;
let mut s = String::new();
write!(s, "{}", self).unwrap();
buf.extend_from_slice(s.as_bytes());
}
fn fmt_json(&self, buf: &mut Vec<u8>) {
buf.push(b'"');
self.write_to(buf);
buf.push(b'"');
}
}
+14 -2
View File
@@ -6,7 +6,7 @@ use crate::Cents;
/// Aggregation strategy for URPD buckets.
/// Options: raw (no aggregation), lin200/lin500/lin1000 (linear $200/$500/$1000),
/// log10/log50/log100/log200 (logarithmic with 10/50/100/200 buckets per decade).
/// log10/log50/log100/log200/log500/log1000/log2000 (logarithmic with 10/50/100/200/500/1000/2000 buckets per decade).
#[derive(
Debug, Display, Clone, Copy, Default, PartialEq, Eq, Deserialize, Serialize, JsonSchema,
)]
@@ -22,6 +22,9 @@ pub enum UrpdAggregation {
Log50,
Log100,
Log200,
Log500,
Log1000,
Log2000,
}
impl UrpdAggregation {
@@ -42,6 +45,9 @@ impl UrpdAggregation {
Self::Log50 => Some(50),
Self::Log100 => Some(100),
Self::Log200 => Some(200),
Self::Log500 => Some(500),
Self::Log1000 => Some(1000),
Self::Log2000 => Some(2000),
_ => None,
}
}
@@ -55,7 +61,13 @@ impl UrpdAggregation {
let size = self.linear_size_cents().unwrap();
(price_cents / size) * size
}
Self::Log10 | Self::Log50 | Self::Log100 | Self::Log200 => {
Self::Log10
| Self::Log50
| Self::Log100
| Self::Log200
| Self::Log500
| Self::Log1000
| Self::Log2000 => {
if price_cents == Cents::ZERO {
return Cents::ZERO;
}
+194
View File
@@ -4,6 +4,200 @@ All notable changes to the Bitcoin Research Kit (BRK) project will be documented
> *This changelog was generated by Claude Code*
## [v0.3.0](https://github.com/bitcoinresearchkit/brk/releases/tag/v0.3.0) - 2026-05-18
### Highlights (v0.2.5 → v0.3.0)
The headlines of the v0.3.0 cycle, written for users rather than as a diff:
- **BRK is now a drop-in mempool.space backend.** Every `/api/...` and `/api/v1/...` route returns the same JSON as mempool.space, so existing tools and dashboards point at a self-hosted BRK without code changes. Address activity, block info, fee estimates, RBF and CPFP trees, raw tx submission, merkle proofs, recent mempool txs, and historical prices are all covered.
- **The projected next block is Bitcoin Core's own template.** Instead of BRK reimplementing block selection, the next-block view is now byte-for-byte what your node would mine via `getblocktemplate`. A new `/api/v1/mempool/block-template/diff/{hash}` endpoint lets clients pull incremental updates by hash, so a live mempool UI does not refetch the whole template every second.
- **UTXO realized-price distribution (URPD).** A new family of endpoints exposes the cost-basis distribution of the live UTXO set, with per-bucket supply, realized cap, and unrealized PnL, per cohort, per date, and at multiple aggregation levels (`raw`, `lin200/500/1000`, `log10/50/100/200`). The older `cost-basis` routes still work but are marked deprecated with a 2027-01-01 sunset.
- **A pure on-chain BTC/USD price oracle, with no external feed.** BRK derives price from output-value clustering, so prices are reproducible from the chain alone. The v2 algorithm extends coverage back to block 525,000 (was 550,000), narrows the excluded-output set to taproot only, and screens out OP_RETURN-carrying transactions for tighter signal.
- **A built-in block explorer ships with the website.** Open BRK in a browser and you get an isometric 3D-cube chain view, dedicated `/block/{...}`, `/tx/{...}`, and `/address/{...}` pages with deep links, infinite scroll in both directions, click-to-select, and a full block-details side pane. Replaces the previous single-page UI.
- **Interactive API docs bundled with the server.** A Scalar viewer ships under `/scalar` so anyone running BRK can browse and try the API without external tooling. The OpenAPI document is served in compact and full variants so the viewer loads instantly.
- **Two new CLI tools ship with the project.** `blk` reads Bitcoin Core's `blk*.dat` files directly and emits NDJSON, TSV, or pretty JSON with field selectors and height ranges, useful for scripting block inspection without an RPC round-trip. `mmpl` is a sidecar that prints live mempool events (tx enter / leave, new tip, new block, fee changes, per-address activity) as an NDJSON stream you can pipe into anything.
- **Reads near the tip are now race-free.** A pipeline-wide "safe lengths" snapshot replaced the previous stamp-then-write window where readers could occasionally see a height that was not yet readable. The same fix removed a stale cached tip hash that could lag across reorgs.
- **Reorg-safe iteration.** `BlockIterator` now yields `Result<Block>` instead of `Option<Block>`, so a reorg in the middle of a scan surfaces as an error instead of a silent end-of-stream. Any tool that walks block ranges can react properly instead of believing the chain ended.
- **Stale-while-revalidate baked into the JS client.** Every generated method now accepts `{ signal, onUpdate }`. You render once from cache, then again with fresh data when it arrives, and you can cancel in-flight requests via the `AbortSignal`. Text and CSV endpoints share the same pipeline that JSON had.
- **Server tunables for self-hosters.** A new `ServerConfig` block (matching `brk_cli` flags) exposes `cdn_cache_mode` (Live vs Aggressive for the CDN-control headers), separate `max_weight` budgets for localhost vs public callers, a `cache_size` knob, and a 5-second default request timeout. Useful if you put BRK behind a CDN or expose it publicly.
- **Cleaner install path.** Pre-built GitHub release binaries are gone. Installation is now `cargo install --locked brk_cli`, and updates are a re-run of the same command (indexed data is reused when the format is unchanged, otherwise resynced automatically).
**Things to know before upgrading:**
- The indexer storage format changed (VERSION 25 → 26). On first run, BRK will rebuild any vecs that moved or were added (new fields include per-block / per-tx blk-file positions, coinbase tags, segwit counts, and per-tx sigop cost).
- The oracle algorithm changed (VERSION 1 → 2). Historical prices below the new 525,000 start height will shift, and the bin tally now drops OP_RETURN transactions, so values across the full history will differ slightly from prior releases.
- Cost-basis API consumers should migrate to the new `/api/urpd/...` routes before 2027-01-01.
### Breaking Changes
#### `release`
- Removed the `cargo-dist`-driven `.github/workflows/release.yml` GitHub Actions pipeline (296 lines). Pre-built binaries for `aarch64-apple-darwin`, `aarch64-unknown-linux-gnu`, and `x86_64-unknown-linux-gnu` are no longer published per release. End users install via `cargo install --locked brk_cli` instead. The `[profile.dist]` and `[workspace.metadata.dist]` blocks in the root `Cargo.toml` and the `[package.metadata.dist]` block in `crates/brk_cli/Cargo.toml` are removed accordingly ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0/Cargo.toml))
### New Features
#### `brk_cli`
- New `Update` section in the README documents that updating is a re-run of `cargo install --locked brk_cli`: the binary is overwritten in place, and on-disk indexed data is reused when the storage format is unchanged or reset and resynced automatically when it is not ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0/crates/brk_cli/README.md))
### Internal Changes
#### `repo`
- Moved `docs/LICENSE.md` to the top-level `LICENSE` so GitHub picks it up as the repository's license file. The copyright holder line in the MIT text was also updated from `bitcoinresearchkit` to `Bitcoin Research Kit` to match the project's display name ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0/LICENSE))
- Deleted the obsolete root `CLAUDE.md` reminder file ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0/Cargo.toml))
#### `deps`
- `fjall` was bumped from the pinned `=3.0.4` to `3.1.4` and unpinned (now a normal caret range), `tower-http` from `0.6.10` to `0.6.11`, and `quickmatch` from `0.4.0` to `0.5.0`. The website search pane was updated to import `quickmatch-js` `0.5.0` alongside the Rust bump ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0/Cargo.toml))
- Workspace and per-crate versions stepped to `0.3.0`. The `brk_client::BrkClient::VERSION` constant was refreshed from `v0.3.0-beta.9` to `v0.3.0-beta.11` in the prep snapshot and then to the final value via the auto-generated client regeneration ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0/crates/brk_client/src/lib.rs))
#### `clients`
- Regenerated the auto-generated `modules/brk-client` (npm) and `packages/brk_client` (PyPI) bindings for the v0.3.0 schema ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0/modules/brk-client/index.js))
[View changes](https://github.com/bitcoinresearchkit/brk/compare/v0.3.0-beta.11...v0.3.0)
## [v0.3.0-beta.11](https://github.com/bitcoinresearchkit/brk/releases/tag/v0.3.0-beta.11) - 2026-05-17
### Bug Fixes
#### `scripts`
- Fixed `scripts/rust-publish.sh` to reflect the v0.3.0-beta.10 crate reorganization. `brk_mempool` was moved to publish after `brk_oracle` (its new dependency ordering), and the new `blk` and `mmpl` binary crates were appended to the publish list so the next `cargo publish` pass uploads them to crates.io ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.11/scripts/rust-publish.sh))
### Internal Changes
#### `clients`
- Regenerated the auto-generated `modules/brk-client` (npm) and `packages/brk_client` (PyPI) bindings against the v0.3.0-beta.11 schema. Pure documentation regeneration with no API surface change beyond the version stamp ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.11/modules/brk-client/docs/classes/BrkClient.md))
#### `deps`
- Workspace and per-crate versions stepped to `0.3.0-beta.11` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.11/Cargo.toml))
[View changes](https://github.com/bitcoinresearchkit/brk/compare/v0.3.0-beta.10...v0.3.0-beta.11)
## [v0.3.0-beta.10](https://github.com/bitcoinresearchkit/brk/releases/tag/v0.3.0-beta.10) - 2026-05-17
### Breaking Changes
#### `brk_rpc`
- Removed the wrapper structs `BlockInfo`, `BlockHeaderInfo`, `TxOutInfo` and `RawTx`. The crate now re-exports `corepc_types::v17::{GetBlockHeaderVerbose, GetBlockVerboseOne, GetTxOut}` directly, so downstream consumers must switch to the upstream shapes. The `RawTx { hex, blockhash }` aggregate is gone: callers fetch the hex and the containing-block hash through `get_raw_transaction(txid)` and `get_block_hash` separately ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_rpc/src/lib.rs))
- `Client::fetch_mempool_state()` now returns `(MempoolState, Vec<BlockTemplateTx>)` from a single batched call that issues `getblocktemplate` + `getrawmempool false` + `getmempoolinfo`. `MempoolState` no longer carries verbose entries: it exposes `live_txids: FxHashSet<Txid>`, `min_fee: FeeRate`, `tip_hash: BlockHash`, `tip_height: Height`. Old consumers that read full `MempoolEntryInfo` per cycle must call the new `fetch_new_pool_data(txids)` batched fetch (`getmempoolentry` + `getrawtransaction` per txid) for the deltas they care about ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_rpc/src/methods.rs))
- `BlockTemplateTx` now carries the full transaction body (`{ txid, fee, weight, depends, tx }`) instead of just an identifier, so the rebuild path can copy Core's projected block into the snapshot without a second RPC pass ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_rpc/src/methods.rs))
#### `brk_oracle`
- `VERSION` bumped to `2`. The pure on-chain BTC/USD oracle algorithm changed in three ways: `START_HEIGHT` lowered from `550_000` to `525_000`, the excluded-output set narrowed from `{P2TR, P2WSH}` to `{P2TR}` only, and per-transaction OP_RETURN screening was added so any tx that contains an OP_RETURN output is dropped from the bin tally entirely. Prior databases must rebuild the price vec; clients reading historical oracle values will see the values shift below the new start height ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_oracle/src/config.rs))
- The input surface was simplified to a single `process_histogram(&Histogram) -> Option<Price>` entry point. The new `Histogram([u32; NUM_BINS])` newtype owns the per-bin counters with `Histogram::zeros()` and `Histogram::increment(bin)`, and the new `default_eligible_bin(sats, output_type) -> Option<u16>` helper carries the eligibility decision (compile-time bitmask over `OutputType`). Configuration constants moved to `config.rs` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_oracle/src/lib.rs))
#### `brk_types`
- `MempoolEntryInfo` was slimmed to match the fields BRK actually consumes: removed `ancestor_count`, `ancestor_size`, `ancestor_fee`, `descendant_size`, `descendant_fee`, `chunk_fee`, `chunk_weight`, and the `chunk_rate()` method. The remaining shape is `{ txid, vsize, weight, fee, first_seen, depends }`. The struct's doc comment now points at Bitcoin Core's `getmempoolentry` as the authoritative source. CPFP/chunk consumers must compute these values themselves via the snapshot's chunk-rate map instead of reading them off the entry ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_types/src/mempool_entry_info.rs))
- Moved the SFL chunking primitives from `brk_mempool` into `brk_types::cpfp`: new `chunk_input.rs` holds the borrowed `ChunkInput<'a>`, new `linearize.rs` holds the Single Fee Linearization implementation, and a new `find_seed_chunk()` helper is exposed in `cluster_chunk.rs`. A new `CPFP_CHAIN_LIMIT: usize = 25` constant is exported. `brk_query::impl::cpfp` and the rebuild pipeline now import from `brk_types` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_types/src/cpfp/linearize.rs))
#### `brk_mempool`
- Crate-level `chunking.rs` (162 lines) and `cpfp.rs` (305 lines) are deleted; both moved into `brk_types::cpfp`. External code that imported `brk_mempool::chunking::linearize` or `brk_mempool::cpfp::CpfpInfo` must switch to the `brk_types::cpfp` re-exports ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_types/src/cpfp/mod.rs))
- `state.rs` was split into a `state/` module (`mod.rs` + `tx_entry.rs`). `TxEntry` now carries `size: u64` and an `rbf: bool` flag in addition to the previous fields, so signal-aware reasoning (BIP-125 trees, eviction policy) reads off the entry instead of re-parsing the body ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_mempool/src/state/tx_entry.rs))
- `Mempool::start_with` now takes a batched prevout resolver `Fn(&[(Txid, Vout)]) -> FxHashMap<(Txid, Vout), TxOut> + Send` instead of a per-input lookup. Callers driving the cycle must adapt: the previous `Box<dyn Fn(&Txid, Vout) -> Option<TxOut>>` signature is gone. `brk_query::indexer_prevout_resolver()` was rewritten to return the batched form ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_mempool/src/driver.rs))
- The `diagnostics` counter set drops the `skip_cleans` field. Consumers reading `MempoolStats` must remove the field reference ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_mempool/src/diagnostics.rs))
### New Features
#### `mmpl` (new crate)
- New `mmpl` CLI binary that streams live mempool events as NDJSON on stdout. The `Event` enum covers `Enter` (tx admitted), `Leave` (tx evicted or mined), `AddrEnter` / `AddrLeave` (per-address presence changes), `Tip` (block tip moved), `Block` (new block connected), `Fees` (recommended fee tiers refreshed), and `Cycle` (full cycle diff summary). Depends on `brk_error`, `brk_mempool`, `brk_rpc`, `brk_types`. Useful as a thin observability sidecar against a running BRK node without polling the HTTP API ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/mmpl/src/event.rs))
#### `brk_types`
- New `BlockTemplate { hash: NextBlockHash, stats: BlockStats, transactions: Vec<Transaction> }` describing the projected next block exactly as Bitcoin Core would mine it ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_types/src/block_template.rs))
- New `BlockTemplateDiff { hash, since, order, removed }` and `BlockTemplateDiffEntry` (untagged JSON enum of `Retained(u32)` index references and `New(Transaction)` bodies) for incremental client updates against a known template hash ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_types/src/block_template_diff.rs))
- New `NextBlockHash(u64)` opaque hash type identifying a specific projected block; clients pass it back via `/diff/{hash}` and receive a `NotFound` when their `since` has aged out of the buffer ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_types/src/next_block_hash.rs))
- New mutator `Transaction::refresh_sigops()` recomputes `total_sigop_cost` after in-place mutation of script witness data, used by the rebuild path when fixing up template-supplied transactions ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_types/src/tx.rs))
#### `brk_mempool`
- New `api/` module surface: `addr.rs`, `block_template.rs`, `fees.rs`, `histogram.rs`, `rbf.rs`, `tx.rs`. New methods include `block_template() -> BlockTemplate`, `block_template_diff(since: NextBlockHash) -> Option<BlockTemplateDiff>`, `live_histogram() -> Histogram`, `live_effective_fee_rate(txid)`, `graveyard_fee_rate(txid)` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_mempool/src/api/block_template.rs))
- New `cycle/` module: `AddedKind` (Fresh / Revived), `AddrTransitions` (with same-cycle enter/leave cancellation so a tx that enters and leaves within one cycle never emits to subscribers), `CycleDiff`, `Cycle` event aggregate, plus `TxAdded` and `TxRemoved` payloads. Drives the `mmpl` event stream ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_mempool/src/cycle/mod.rs))
- New `snapshot/` module: `block_stats.rs` (`CORE_PERCENTILES` 0..=100 for `blocks[0]`, `PROJECTED_PERCENTILES` 5..=95 for `blocks[1..]`), `builder.rs` (per-cluster `refresh_chunk_rates`), `cluster.rs`, `cpfp.rs`, `fees.rs`, `partition.rs`, `rebuilder.rs`, `snap_tx.rs`, `tx_index.rs`. The snapshot now carries `{ txs, blocks, block_stats, fees, next_block_hash, prefix_to_idx }`, with `block0_txids()`, `hash_next_block()`, `chunk_rate_for(txid)` helpers ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_mempool/src/snapshot/builder.rs))
- New `driver.rs` runs a 1-second `PERIOD` cycle loop. `start()` uses the default RPC resolver, `start_with(resolver)` accepts a custom batched resolver. Panics if started twice on the same `Mempool` to surface misuse early ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_mempool/src/driver.rs))
- New `steps/prevouts.rs` backfills `prevout: None` entries from same-cycle in-mempool parents first, then from the caller-supplied resolver for confirmed ancestors ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_mempool/src/steps/prevouts.rs))
#### `brk_rpc`
- New batched `Client::fetch_new_pool_data(txids)` issues `getmempoolentry` + `getrawtransaction` in one round-trip per delta set, replacing the per-tx loop that the apply step used to drive ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_rpc/src/methods.rs))
- New `Client::get_blockchain_info()` and `Client::get_network()` are reintroduced as proper wrappers (after the v0.3.0-beta.9 removal). The wrappers are not behind a `cfg(debug)` gate, per the keep-public-API rule, so external integrations can call them directly ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_rpc/src/lib.rs))
#### `brk_server`
- Added `/api/v1/mempool/block-template` returning the current projected block and `/api/v1/mempool/block-template/diff/{hash}` returning the incremental update since a known template hash. The mempool-hash response type was changed from `u64` to `NextBlockHash` for type safety on the wire ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_server/src/api/mempool.rs))
- New `NextBlockHashParam { hash: NextBlockHash }` axum extractor parses the diff route's path parameter ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_server/src/params/next_block_hash_param.rs))
- New `X-Method` response header derived from a `Method` extension placed on the response by the API layer, so reverse proxies and access logs see which BRK method served a given request without inspecting the URL ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_server/src/lib.rs))
#### `brk_query`
- New `block_template()` and `block_template_diff(since: NextBlockHash) -> Result<BlockTemplateDiff>` query methods. `block_template_diff` returns `Error::NotFound` when the `since` hash has aged out of the in-memory buffer, signalling the client to fall back to a full template fetch ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_query/src/impl/mempool.rs))
#### `brk_logger`
- New `install_panic_hook()` registers a `std::panic::set_hook` that captures the panic message, source location and a `std::backtrace::Backtrace` and routes them through `tracing::error!`, so panics in worker threads land in the same log sink as normal errors instead of being lost on stderr ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_logger/src/lib.rs))
#### `blk`
- New `coinbase_hex` field on the per-block JSON: emits the raw coinbase scriptSig hex, useful for miner-tag extraction without re-deriving from `tx.0.vin.0.script_sig` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/blk/src/main.rs))
- New `BLOCK_FIELDS`, `TX_FIELDS`, `VIN_FIELDS`, `VOUT_FIELDS` constant arrays drive selector validation and bash completion. Args validation now rejects duplicate `--field` flags and unknown long flags, and `Mode::pick` enforces that `--pretty` and `--compact` are mutually exclusive ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/blk/src/args.rs))
- Selectors pre-resolve the chain tip exactly once per invocation, so `tip` and ranges that resolve relative to tip do not issue an RPC call per output row ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/blk/src/main.rs))
- A bare `tx`, `vin`, or `vout` selector now returns the matching sub-object as JSON instead of bailing on the missing leaf; `bits` is formatted as a hex string to match `bitcoin-cli`. `Ctx::new(block, network)` now takes the network alongside the block so address rendering picks the right human-readable prefix ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/blk/src/main.rs))
### Bug Fixes
#### `brk_server`
- The health endpoint no longer round-trips to `bitcoind` to compute its response. It now reports liveness from the local indexer state directly, so a slow or unresponsive Bitcoin Core node does not flap the BRK liveness probe. A separate `/api/server/sync` endpoint exposes the real chain-tip lag for callers that actually need that signal ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_server/src/api/server.rs))
- The axum middleware stack was reordered so `CatchPanic` is layered above `response_time_layer`. A panic in a handler is now converted into a 500 response that still records its timing, instead of bypassing the response-time layer and producing a zero-duration error log line ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_server/src/lib.rs))
#### `brk_indexer`
- Removed the `tip_blockhash: Arc<RwLock<BlockHash>>` field on `Indexer`. The field could lag behind the on-disk `blockhash` vec across reorgs, so a reader observing a fresh `safe_lengths` against a stale cached tip could see a hash from the abandoned branch. `Indexer::tip_blockhash()` now reads `blockhash.collect_one(safe_lengths().height - 1)` directly, eliminating the cache and the `parking_lot::RwLock` import ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_indexer/src/lib.rs))
#### `brk_query`
- `height_by_hash` now clamps its scan to the current `safe_lengths()` snapshot. A reader that races a reorg-and-rewrite no longer hits the stamp-before-write window where the in-flight vec has a stamp but the data for the highest position is not yet readable ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_query/src/impl/block/info.rs))
### Internal Changes
#### `brk_computer`
- `prices/compute.rs` switched to per-transaction grouping: a `tx_starts` array records each tx's output range, and any transaction that contains at least one OP_RETURN output is dropped from the bin tally before counters are summed. Histogram allocation now goes through `brk_oracle::Histogram::zeros()`. `feed_blocks` was unified into a single public function that takes an optional `cap: Option<&Lengths>` for bounded replays, replacing the previous capped/uncapped pair ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_computer/src/prices/compute.rs))
- `distribution/vecs.rs` `VERSION` is now sourced from `brk_oracle::VERSION` so the oracle algorithm bump cascades to the distribution snapshot without a manual version edit ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_computer/src/distribution/vecs.rs))
#### `brk_iterator` / `brk_reader`
- Both crates adapted to the new `get_block_header_info()` return shape, using `(height + 1) as u64` for the next-block hint instead of reading a now-removed field on the wrapper. The change is internal and does not affect public iteration / canonical-read APIs ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_iterator/src/lib.rs))
#### `brk_mempool`
- New `test_support.rs` extracts the test-only helpers (builder fixtures, cluster factories) that used to live inline in test modules, so the unit tests across the new `snapshot/` and `cycle/` submodules share a single fixture surface ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_mempool/src/test_support.rs))
- The lib-doc was rewritten to describe the new 5-step pipeline (Fetcher then Preparer then Applier then Prevouts then Rebuilder) and to drop references to the deleted block-builder ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/crates/brk_mempool/src/lib.rs))
#### `clients`
- Regenerated the auto-generated `modules/brk-client` (npm) and `packages/brk_client` (PyPI) bindings to pick up the new `BlockTemplate`, `BlockTemplateDiff`, `BlockTemplateDiffEntry`, `NextBlockHash` types, the slimmed `MempoolEntryInfo`, and the two new `/api/v1/mempool/block-template*` routes ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/modules/brk-client/index.js))
#### `website`
- Snapshots across `src/explorer/chain`, `src/explorer/mempool`, `src/options/full`, `src/utils/price`, `src/utils/theme`, and `src/explorer/chain/cube` to render the projected block template and consume the new diff endpoint ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/website/src/explorer/mempool))
#### `deps`
- Workspace and per-crate versions stepped to `0.3.0-beta.10` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.3.0-beta.10/Cargo.toml))
[View changes](https://github.com/bitcoinresearchkit/brk/compare/v0.3.0-beta.9...v0.3.0-beta.10)
## [v0.3.0-beta.9](https://github.com/bitcoinresearchkit/brk/releases/tag/v0.3.0-beta.9) - 2026-05-08
### Breaking Changes
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -6,7 +6,7 @@
# Class: BrkError
Defined in: [Developer/brk/modules/brk-client/index.js:1483](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L1483)
Defined in: [Developer/brk/modules/brk-client/index.js:1491](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L1491)
Custom error class for BRK client errors
@@ -20,7 +20,7 @@ Custom error class for BRK client errors
> **new BrkError**(`message`, `status?`): `BrkError`
Defined in: [Developer/brk/modules/brk-client/index.js:1488](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L1488)
Defined in: [Developer/brk/modules/brk-client/index.js:1496](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L1496)
#### Parameters
+1
View File
@@ -162,6 +162,7 @@
- [HashrateEntry](interfaces/HashrateEntry.md)
- [HashrateSummary](interfaces/HashrateSummary.md)
- [Health](interfaces/Health.md)
- [HeightOrDateParam](interfaces/HeightOrDateParam.md)
- [HeightParam](interfaces/HeightParam.md)
- [HistoricalPrice](interfaces/HistoricalPrice.md)
- [HistoricalPriceEntry](interfaces/HistoricalPriceEntry.md)
@@ -6,7 +6,7 @@
# Interface: \_0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdZscorePattern
Defined in: [Developer/brk/modules/brk-client/index.js:2322](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2322)
Defined in: [Developer/brk/modules/brk-client/index.js:2340](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2340)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2322](https://github.com/
> **\_0sd**: [`CentsSatsUsdPattern`](CentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2323](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2323)
Defined in: [Developer/brk/modules/brk-client/index.js:2341](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2341)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2323](https://github.com/
> **m05sd**: [`PriceRatioPattern`](PriceRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2324](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2324)
Defined in: [Developer/brk/modules/brk-client/index.js:2342](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2342)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2324](https://github.com/
> **m15sd**: [`PriceRatioPattern`](PriceRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2325](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2325)
Defined in: [Developer/brk/modules/brk-client/index.js:2343](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2343)
***
@@ -38,7 +38,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2325](https://github.com/
> **m1sd**: [`PriceRatioPattern`](PriceRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2326](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2326)
Defined in: [Developer/brk/modules/brk-client/index.js:2344](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2344)
***
@@ -46,7 +46,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2326](https://github.com/
> **m25sd**: [`PriceRatioPattern`](PriceRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2327](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2327)
Defined in: [Developer/brk/modules/brk-client/index.js:2345](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2345)
***
@@ -54,7 +54,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2327](https://github.com/
> **m2sd**: [`PriceRatioPattern`](PriceRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2328](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2328)
Defined in: [Developer/brk/modules/brk-client/index.js:2346](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2346)
***
@@ -62,7 +62,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2328](https://github.com/
> **m3sd**: [`PriceRatioPattern`](PriceRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2329](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2329)
Defined in: [Developer/brk/modules/brk-client/index.js:2347](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2347)
***
@@ -70,7 +70,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2329](https://github.com/
> **p05sd**: [`PriceRatioPattern`](PriceRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2330](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2330)
Defined in: [Developer/brk/modules/brk-client/index.js:2348](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2348)
***
@@ -78,7 +78,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2330](https://github.com/
> **p15sd**: [`PriceRatioPattern`](PriceRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2331](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2331)
Defined in: [Developer/brk/modules/brk-client/index.js:2349](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2349)
***
@@ -86,7 +86,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2331](https://github.com/
> **p1sd**: [`PriceRatioPattern`](PriceRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2332](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2332)
Defined in: [Developer/brk/modules/brk-client/index.js:2350](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2350)
***
@@ -94,7 +94,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2332](https://github.com/
> **p25sd**: [`PriceRatioPattern`](PriceRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2333](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2333)
Defined in: [Developer/brk/modules/brk-client/index.js:2351](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2351)
***
@@ -102,7 +102,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2333](https://github.com/
> **p2sd**: [`PriceRatioPattern`](PriceRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2334](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2334)
Defined in: [Developer/brk/modules/brk-client/index.js:2352](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2352)
***
@@ -110,7 +110,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2334](https://github.com/
> **p3sd**: [`PriceRatioPattern`](PriceRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2335](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2335)
Defined in: [Developer/brk/modules/brk-client/index.js:2353](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2353)
***
@@ -118,7 +118,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2335](https://github.com/
> **sd**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2336](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2336)
Defined in: [Developer/brk/modules/brk-client/index.js:2354](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2354)
***
@@ -126,4 +126,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2336](https://github.com/
> **zscore**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2337](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2337)
Defined in: [Developer/brk/modules/brk-client/index.js:2355](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2355)
@@ -6,7 +6,7 @@
# Interface: \_10y1m1w1y2y3m3y4y5y6m6y8yPattern2
Defined in: [Developer/brk/modules/brk-client/index.js:2382](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2382)
Defined in: [Developer/brk/modules/brk-client/index.js:2400](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2400)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2382](https://github.com/
> **\_10y**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2383](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2383)
Defined in: [Developer/brk/modules/brk-client/index.js:2401](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2401)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2383](https://github.com/
> **\_1m**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2384](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2384)
Defined in: [Developer/brk/modules/brk-client/index.js:2402](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2402)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2384](https://github.com/
> **\_1w**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2385](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2385)
Defined in: [Developer/brk/modules/brk-client/index.js:2403](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2403)
***
@@ -38,7 +38,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2385](https://github.com/
> **\_1y**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2386](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2386)
Defined in: [Developer/brk/modules/brk-client/index.js:2404](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2404)
***
@@ -46,7 +46,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2386](https://github.com/
> **\_2y**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2387](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2387)
Defined in: [Developer/brk/modules/brk-client/index.js:2405](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2405)
***
@@ -54,7 +54,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2387](https://github.com/
> **\_3m**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2388](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2388)
Defined in: [Developer/brk/modules/brk-client/index.js:2406](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2406)
***
@@ -62,7 +62,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2388](https://github.com/
> **\_3y**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2389](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2389)
Defined in: [Developer/brk/modules/brk-client/index.js:2407](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2407)
***
@@ -70,7 +70,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2389](https://github.com/
> **\_4y**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2390](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2390)
Defined in: [Developer/brk/modules/brk-client/index.js:2408](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2408)
***
@@ -78,7 +78,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2390](https://github.com/
> **\_5y**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2391](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2391)
Defined in: [Developer/brk/modules/brk-client/index.js:2409](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2409)
***
@@ -86,7 +86,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2391](https://github.com/
> **\_6m**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2392](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2392)
Defined in: [Developer/brk/modules/brk-client/index.js:2410](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2410)
***
@@ -94,7 +94,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2392](https://github.com/
> **\_6y**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2393](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2393)
Defined in: [Developer/brk/modules/brk-client/index.js:2411](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2411)
***
@@ -102,4 +102,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2393](https://github.com/
> **\_8y**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2394](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2394)
Defined in: [Developer/brk/modules/brk-client/index.js:2412](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2412)
@@ -6,7 +6,7 @@
# Interface: \_10y1m1w1y2y3m3y4y5y6m6y8yPattern3
Defined in: [Developer/brk/modules/brk-client/index.js:2421](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2421)
Defined in: [Developer/brk/modules/brk-client/index.js:2439](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2439)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2421](https://github.com/
> **\_10y**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2422](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2422)
Defined in: [Developer/brk/modules/brk-client/index.js:2440](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2440)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2422](https://github.com/
> **\_1m**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2423](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2423)
Defined in: [Developer/brk/modules/brk-client/index.js:2441](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2441)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2423](https://github.com/
> **\_1w**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2424](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2424)
Defined in: [Developer/brk/modules/brk-client/index.js:2442](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2442)
***
@@ -38,7 +38,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2424](https://github.com/
> **\_1y**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2425](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2425)
Defined in: [Developer/brk/modules/brk-client/index.js:2443](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2443)
***
@@ -46,7 +46,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2425](https://github.com/
> **\_2y**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2426](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2426)
Defined in: [Developer/brk/modules/brk-client/index.js:2444](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2444)
***
@@ -54,7 +54,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2426](https://github.com/
> **\_3m**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2427](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2427)
Defined in: [Developer/brk/modules/brk-client/index.js:2445](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2445)
***
@@ -62,7 +62,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2427](https://github.com/
> **\_3y**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2428](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2428)
Defined in: [Developer/brk/modules/brk-client/index.js:2446](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2446)
***
@@ -70,7 +70,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2428](https://github.com/
> **\_4y**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2429](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2429)
Defined in: [Developer/brk/modules/brk-client/index.js:2447](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2447)
***
@@ -78,7 +78,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2429](https://github.com/
> **\_5y**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2430](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2430)
Defined in: [Developer/brk/modules/brk-client/index.js:2448](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2448)
***
@@ -86,7 +86,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2430](https://github.com/
> **\_6m**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2431](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2431)
Defined in: [Developer/brk/modules/brk-client/index.js:2449](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2449)
***
@@ -94,7 +94,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2431](https://github.com/
> **\_6y**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2432](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2432)
Defined in: [Developer/brk/modules/brk-client/index.js:2450](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2450)
***
@@ -102,4 +102,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2432](https://github.com/
> **\_8y**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2433](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2433)
Defined in: [Developer/brk/modules/brk-client/index.js:2451](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2451)
@@ -6,7 +6,7 @@
# Interface: \_10y2y3y4y5y6y8yPattern
Defined in: [Developer/brk/modules/brk-client/index.js:2934](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2934)
Defined in: [Developer/brk/modules/brk-client/index.js:2952](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2952)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2934](https://github.com/
> **\_10y**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2935](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2935)
Defined in: [Developer/brk/modules/brk-client/index.js:2953](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2953)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2935](https://github.com/
> **\_2y**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2936](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2936)
Defined in: [Developer/brk/modules/brk-client/index.js:2954](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2954)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2936](https://github.com/
> **\_3y**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2937](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2937)
Defined in: [Developer/brk/modules/brk-client/index.js:2955](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2955)
***
@@ -38,7 +38,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2937](https://github.com/
> **\_4y**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2938](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2938)
Defined in: [Developer/brk/modules/brk-client/index.js:2956](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2956)
***
@@ -46,7 +46,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2938](https://github.com/
> **\_5y**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2939](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2939)
Defined in: [Developer/brk/modules/brk-client/index.js:2957](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2957)
***
@@ -54,7 +54,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2939](https://github.com/
> **\_6y**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2940](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2940)
Defined in: [Developer/brk/modules/brk-client/index.js:2958](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2958)
***
@@ -62,4 +62,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2940](https://github.com/
> **\_8y**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2941](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2941)
Defined in: [Developer/brk/modules/brk-client/index.js:2959](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2959)
@@ -6,7 +6,7 @@
# Interface: \_1m1w1y24hBlockPattern
Defined in: [Developer/brk/modules/brk-client/index.js:3335](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3335)
Defined in: [Developer/brk/modules/brk-client/index.js:3353](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3353)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3335](https://github.com/
> **\_1m**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:3336](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3336)
Defined in: [Developer/brk/modules/brk-client/index.js:3354](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3354)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3336](https://github.com/
> **\_1w**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:3337](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3337)
Defined in: [Developer/brk/modules/brk-client/index.js:3355](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3355)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3337](https://github.com/
> **\_1y**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:3338](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3338)
Defined in: [Developer/brk/modules/brk-client/index.js:3356](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3356)
***
@@ -38,7 +38,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3338](https://github.com/
> **\_24h**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:3339](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3339)
Defined in: [Developer/brk/modules/brk-client/index.js:3357](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3357)
***
@@ -46,4 +46,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3339](https://github.com/
> **block**: [`SeriesPattern18`](../type-aliases/SeriesPattern18.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:3340](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3340)
Defined in: [Developer/brk/modules/brk-client/index.js:3358](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3358)
@@ -6,7 +6,7 @@
# Interface: \_1m1w1y24hBlockPattern2
Defined in: [Developer/brk/modules/brk-client/index.js:3310](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3310)
Defined in: [Developer/brk/modules/brk-client/index.js:3328](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3328)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3310](https://github.com/
> **\_1m**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:3311](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3311)
Defined in: [Developer/brk/modules/brk-client/index.js:3329](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3329)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3311](https://github.com/
> **\_1w**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:3312](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3312)
Defined in: [Developer/brk/modules/brk-client/index.js:3330](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3330)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3312](https://github.com/
> **\_1y**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:3313](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3313)
Defined in: [Developer/brk/modules/brk-client/index.js:3331](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3331)
***
@@ -38,7 +38,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3313](https://github.com/
> **\_24h**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:3314](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3314)
Defined in: [Developer/brk/modules/brk-client/index.js:3332](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3332)
***
@@ -46,4 +46,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3314](https://github.com/
> **block**: [`SeriesPattern18`](../type-aliases/SeriesPattern18.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:3315](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3315)
Defined in: [Developer/brk/modules/brk-client/index.js:3333](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3333)
@@ -6,7 +6,7 @@
# Interface: \_1m1w1y24hBpsPercentRatioPattern
Defined in: [Developer/brk/modules/brk-client/index.js:2963](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2963)
Defined in: [Developer/brk/modules/brk-client/index.js:2981](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2981)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2963](https://github.com/
> **\_1m**: [`BpsPercentRatioPattern2`](BpsPercentRatioPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2964](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2964)
Defined in: [Developer/brk/modules/brk-client/index.js:2982](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2982)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2964](https://github.com/
> **\_1w**: [`BpsPercentRatioPattern2`](BpsPercentRatioPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2965](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2965)
Defined in: [Developer/brk/modules/brk-client/index.js:2983](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2983)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2965](https://github.com/
> **\_1y**: [`BpsPercentRatioPattern2`](BpsPercentRatioPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2966](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2966)
Defined in: [Developer/brk/modules/brk-client/index.js:2984](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2984)
***
@@ -38,7 +38,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2966](https://github.com/
> **\_24h**: [`BpsPercentRatioPattern2`](BpsPercentRatioPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2967](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2967)
Defined in: [Developer/brk/modules/brk-client/index.js:2985](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2985)
***
@@ -46,7 +46,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2967](https://github.com/
> **bps**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2968](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2968)
Defined in: [Developer/brk/modules/brk-client/index.js:2986](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2986)
***
@@ -54,7 +54,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2968](https://github.com/
> **percent**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2969](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2969)
Defined in: [Developer/brk/modules/brk-client/index.js:2987](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2987)
***
@@ -62,4 +62,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2969](https://github.com/
> **ratio**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2970](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2970)
Defined in: [Developer/brk/modules/brk-client/index.js:2988](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2988)
@@ -6,7 +6,7 @@
# Interface: \_1m1w1y24hPattern\<T\>
Defined in: [Developer/brk/modules/brk-client/index.js:4113](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4113)
Defined in: [Developer/brk/modules/brk-client/index.js:4131](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4131)
## Type Parameters
@@ -20,7 +20,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:4113](https://github.com/
> **\_1m**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`T`\>
Defined in: [Developer/brk/modules/brk-client/index.js:4114](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4114)
Defined in: [Developer/brk/modules/brk-client/index.js:4132](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4132)
***
@@ -28,7 +28,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:4114](https://github.com/
> **\_1w**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`T`\>
Defined in: [Developer/brk/modules/brk-client/index.js:4115](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4115)
Defined in: [Developer/brk/modules/brk-client/index.js:4133](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4133)
***
@@ -36,7 +36,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:4115](https://github.com/
> **\_1y**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`T`\>
Defined in: [Developer/brk/modules/brk-client/index.js:4116](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4116)
Defined in: [Developer/brk/modules/brk-client/index.js:4134](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4134)
***
@@ -44,4 +44,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:4116](https://github.com/
> **\_24h**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`T`\>
Defined in: [Developer/brk/modules/brk-client/index.js:4117](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4117)
Defined in: [Developer/brk/modules/brk-client/index.js:4135](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4135)
@@ -6,7 +6,7 @@
# Interface: \_1m1w1y24hPattern2
Defined in: [Developer/brk/modules/brk-client/index.js:3644](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3644)
Defined in: [Developer/brk/modules/brk-client/index.js:3662](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3662)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3644](https://github.com/
> **\_1m**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3645](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3645)
Defined in: [Developer/brk/modules/brk-client/index.js:3663](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3663)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3645](https://github.com/
> **\_1w**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3646](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3646)
Defined in: [Developer/brk/modules/brk-client/index.js:3664](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3664)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3646](https://github.com/
> **\_1y**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3647](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3647)
Defined in: [Developer/brk/modules/brk-client/index.js:3665](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3665)
***
@@ -38,4 +38,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3647](https://github.com/
> **\_24h**: [`BpsPercentRatioPattern`](BpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3648](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3648)
Defined in: [Developer/brk/modules/brk-client/index.js:3666](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3666)
@@ -6,7 +6,7 @@
# Interface: \_1m1w1y24hPattern3
Defined in: [Developer/brk/modules/brk-client/index.js:3713](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3713)
Defined in: [Developer/brk/modules/brk-client/index.js:3731](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3731)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3713](https://github.com/
> **\_1m**: [`BtcCentsSatsUsdPattern2`](BtcCentsSatsUsdPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3714](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3714)
Defined in: [Developer/brk/modules/brk-client/index.js:3732](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3732)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3714](https://github.com/
> **\_1w**: [`BtcCentsSatsUsdPattern2`](BtcCentsSatsUsdPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3715](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3715)
Defined in: [Developer/brk/modules/brk-client/index.js:3733](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3733)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3715](https://github.com/
> **\_1y**: [`BtcCentsSatsUsdPattern2`](BtcCentsSatsUsdPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3716](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3716)
Defined in: [Developer/brk/modules/brk-client/index.js:3734](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3734)
***
@@ -38,4 +38,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3716](https://github.com/
> **\_24h**: [`BtcCentsSatsUsdPattern2`](BtcCentsSatsUsdPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3717](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3717)
Defined in: [Developer/brk/modules/brk-client/index.js:3735](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3735)
@@ -6,7 +6,7 @@
# Interface: \_1m1w1y24hPattern4
Defined in: [Developer/brk/modules/brk-client/index.js:3690](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3690)
Defined in: [Developer/brk/modules/brk-client/index.js:3708](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3708)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3690](https://github.com/
> **\_1m**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3691](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3691)
Defined in: [Developer/brk/modules/brk-client/index.js:3709](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3709)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3691](https://github.com/
> **\_1w**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3692](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3692)
Defined in: [Developer/brk/modules/brk-client/index.js:3710](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3710)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3692](https://github.com/
> **\_1y**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3693](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3693)
Defined in: [Developer/brk/modules/brk-client/index.js:3711](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3711)
***
@@ -38,4 +38,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3693](https://github.com/
> **\_24h**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3694](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3694)
Defined in: [Developer/brk/modules/brk-client/index.js:3712](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3712)
@@ -6,7 +6,7 @@
# Interface: \_1m1w1y24hPattern5
Defined in: [Developer/brk/modules/brk-client/index.js:3782](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3782)
Defined in: [Developer/brk/modules/brk-client/index.js:3800](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3800)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3782](https://github.com/
> **\_1m**: [`CentsUsdPattern`](CentsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3783](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3783)
Defined in: [Developer/brk/modules/brk-client/index.js:3801](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3801)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3783](https://github.com/
> **\_1w**: [`CentsUsdPattern`](CentsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3784](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3784)
Defined in: [Developer/brk/modules/brk-client/index.js:3802](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3802)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3784](https://github.com/
> **\_1y**: [`CentsUsdPattern`](CentsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3785](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3785)
Defined in: [Developer/brk/modules/brk-client/index.js:3803](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3803)
***
@@ -38,4 +38,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3785](https://github.com/
> **\_24h**: [`CentsUsdPattern`](CentsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3786](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3786)
Defined in: [Developer/brk/modules/brk-client/index.js:3804](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3804)
@@ -6,7 +6,7 @@
# Interface: \_1m1w1y24hPattern6
Defined in: [Developer/brk/modules/brk-client/index.js:3805](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3805)
Defined in: [Developer/brk/modules/brk-client/index.js:3823](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3823)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3805](https://github.com/
> **\_1m**: [`CentsUsdPattern3`](CentsUsdPattern3.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3806](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3806)
Defined in: [Developer/brk/modules/brk-client/index.js:3824](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3824)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3806](https://github.com/
> **\_1w**: [`CentsUsdPattern3`](CentsUsdPattern3.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3807](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3807)
Defined in: [Developer/brk/modules/brk-client/index.js:3825](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3825)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3807](https://github.com/
> **\_1y**: [`CentsUsdPattern3`](CentsUsdPattern3.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3808](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3808)
Defined in: [Developer/brk/modules/brk-client/index.js:3826](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3826)
***
@@ -38,4 +38,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3808](https://github.com/
> **\_24h**: [`CentsUsdPattern3`](CentsUsdPattern3.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3809](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3809)
Defined in: [Developer/brk/modules/brk-client/index.js:3827](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3827)
@@ -6,7 +6,7 @@
# Interface: \_1m1w1y24hPattern7
Defined in: [Developer/brk/modules/brk-client/index.js:3736](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3736)
Defined in: [Developer/brk/modules/brk-client/index.js:3754](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3754)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3736](https://github.com/
> **\_1m**: [`BtcSatsPattern`](BtcSatsPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3737](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3737)
Defined in: [Developer/brk/modules/brk-client/index.js:3755](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3755)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3737](https://github.com/
> **\_1w**: [`BtcSatsPattern`](BtcSatsPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3738](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3738)
Defined in: [Developer/brk/modules/brk-client/index.js:3756](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3756)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3738](https://github.com/
> **\_1y**: [`BtcSatsPattern`](BtcSatsPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3739](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3739)
Defined in: [Developer/brk/modules/brk-client/index.js:3757](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3757)
***
@@ -38,4 +38,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3739](https://github.com/
> **\_24h**: [`BtcSatsPattern`](BtcSatsPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3740](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3740)
Defined in: [Developer/brk/modules/brk-client/index.js:3758](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3758)
@@ -6,7 +6,7 @@
# Interface: \_1m1w1y24hPattern8
Defined in: [Developer/brk/modules/brk-client/index.js:3667](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3667)
Defined in: [Developer/brk/modules/brk-client/index.js:3685](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3685)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3667](https://github.com/
> **\_1m**: [`BpsPercentRatioPattern4`](BpsPercentRatioPattern4.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3668](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3668)
Defined in: [Developer/brk/modules/brk-client/index.js:3686](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3686)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3668](https://github.com/
> **\_1w**: [`BpsPercentRatioPattern4`](BpsPercentRatioPattern4.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3669](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3669)
Defined in: [Developer/brk/modules/brk-client/index.js:3687](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3687)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3669](https://github.com/
> **\_1y**: [`BpsPercentRatioPattern4`](BpsPercentRatioPattern4.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3670](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3670)
Defined in: [Developer/brk/modules/brk-client/index.js:3688](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3688)
***
@@ -38,4 +38,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3670](https://github.com/
> **\_24h**: [`BpsPercentRatioPattern4`](BpsPercentRatioPattern4.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3671](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3671)
Defined in: [Developer/brk/modules/brk-client/index.js:3689](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3689)
@@ -6,7 +6,7 @@
# Interface: \_1m1w1y2wPattern
Defined in: [Developer/brk/modules/brk-client/index.js:3759](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3759)
Defined in: [Developer/brk/modules/brk-client/index.js:3777](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3777)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3759](https://github.com/
> **\_1m**: [`CentsSatsUsdPattern`](CentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3760](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3760)
Defined in: [Developer/brk/modules/brk-client/index.js:3778](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3778)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3760](https://github.com/
> **\_1w**: [`CentsSatsUsdPattern`](CentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3761](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3761)
Defined in: [Developer/brk/modules/brk-client/index.js:3779](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3779)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3761](https://github.com/
> **\_1y**: [`CentsSatsUsdPattern`](CentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3762](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3762)
Defined in: [Developer/brk/modules/brk-client/index.js:3780](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3780)
***
@@ -38,4 +38,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3762](https://github.com/
> **\_2w**: [`CentsSatsUsdPattern`](CentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3763](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3763)
Defined in: [Developer/brk/modules/brk-client/index.js:3781](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3781)
@@ -6,7 +6,7 @@
# Interface: \_1m1w1y2y4yAllPattern
Defined in: [Developer/brk/modules/brk-client/index.js:3121](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3121)
Defined in: [Developer/brk/modules/brk-client/index.js:3139](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3139)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3121](https://github.com/
> **\_1m**: [`BpsRatioPattern2`](BpsRatioPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3122](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3122)
Defined in: [Developer/brk/modules/brk-client/index.js:3140](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3140)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3122](https://github.com/
> **\_1w**: [`BpsRatioPattern2`](BpsRatioPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3123](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3123)
Defined in: [Developer/brk/modules/brk-client/index.js:3141](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3141)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3123](https://github.com/
> **\_1y**: [`BpsRatioPattern2`](BpsRatioPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3124](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3124)
Defined in: [Developer/brk/modules/brk-client/index.js:3142](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3142)
***
@@ -38,7 +38,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3124](https://github.com/
> **\_2y**: [`BpsRatioPattern2`](BpsRatioPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3125](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3125)
Defined in: [Developer/brk/modules/brk-client/index.js:3143](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3143)
***
@@ -46,7 +46,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3125](https://github.com/
> **\_4y**: [`BpsRatioPattern2`](BpsRatioPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3126](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3126)
Defined in: [Developer/brk/modules/brk-client/index.js:3144](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3144)
***
@@ -54,4 +54,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3126](https://github.com/
> **all**: [`BpsRatioPattern2`](BpsRatioPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3127](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3127)
Defined in: [Developer/brk/modules/brk-client/index.js:3145](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3145)
@@ -6,7 +6,7 @@
# Interface: \_1y2y4yAllPattern
Defined in: [Developer/brk/modules/brk-client/index.js:3828](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3828)
Defined in: [Developer/brk/modules/brk-client/index.js:3846](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3846)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3828](https://github.com/
> **\_1y**: [`_0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdZscorePattern`](0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdZscorePattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3829](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3829)
Defined in: [Developer/brk/modules/brk-client/index.js:3847](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3847)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3829](https://github.com/
> **\_2y**: [`_0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdZscorePattern`](0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdZscorePattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3830](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3830)
Defined in: [Developer/brk/modules/brk-client/index.js:3848](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3848)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3830](https://github.com/
> **\_4y**: [`_0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdZscorePattern`](0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdZscorePattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3831](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3831)
Defined in: [Developer/brk/modules/brk-client/index.js:3849](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3849)
***
@@ -38,4 +38,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3831](https://github.com/
> **all**: [`_0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdZscorePattern`](0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdZscorePattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3832](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3832)
Defined in: [Developer/brk/modules/brk-client/index.js:3850](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3850)
@@ -6,7 +6,7 @@
# Interface: \_24hPattern
Defined in: [Developer/brk/modules/brk-client/index.js:5076](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L5076)
Defined in: [Developer/brk/modules/brk-client/index.js:5094](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L5094)
## Properties
@@ -14,4 +14,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:5076](https://github.com/
> **\_24h**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:5077](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L5077)
Defined in: [Developer/brk/modules/brk-client/index.js:5095](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L5095)
@@ -6,7 +6,7 @@
# Interface: \_6bBlockTxPattern\<T\>
Defined in: [Developer/brk/modules/brk-client/index.js:4571](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4571)
Defined in: [Developer/brk/modules/brk-client/index.js:4589](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4589)
## Type Parameters
@@ -20,7 +20,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:4571](https://github.com/
> **\_6b**: [`MaxMedianMinPct10Pct25Pct75Pct90Pattern`](MaxMedianMinPct10Pct25Pct75Pct90Pattern.md)\<`T`\>
Defined in: [Developer/brk/modules/brk-client/index.js:4572](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4572)
Defined in: [Developer/brk/modules/brk-client/index.js:4590](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4590)
***
@@ -28,7 +28,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:4572](https://github.com/
> **block**: [`MaxMedianMinPct10Pct25Pct75Pct90Pattern`](MaxMedianMinPct10Pct25Pct75Pct90Pattern.md)\<`T`\>
Defined in: [Developer/brk/modules/brk-client/index.js:4573](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4573)
Defined in: [Developer/brk/modules/brk-client/index.js:4591](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4591)
***
@@ -36,4 +36,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:4573](https://github.com/
> **txIndex**: [`SeriesPattern19`](../type-aliases/SeriesPattern19.md)\<`T`\>
Defined in: [Developer/brk/modules/brk-client/index.js:4574](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4574)
Defined in: [Developer/brk/modules/brk-client/index.js:4592](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4592)
@@ -6,7 +6,7 @@
# Interface: AbsoluteRatePattern
Defined in: [Developer/brk/modules/brk-client/index.js:4593](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4593)
Defined in: [Developer/brk/modules/brk-client/index.js:4611](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4611)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:4593](https://github.com/
> **absolute**: [`_1m1w1y24hPattern`](1m1w1y24hPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:4594](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4594)
Defined in: [Developer/brk/modules/brk-client/index.js:4612](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4612)
***
@@ -22,4 +22,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:4594](https://github.com/
> **rate**: [`_1m1w1y24hPattern2`](1m1w1y24hPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:4595](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4595)
Defined in: [Developer/brk/modules/brk-client/index.js:4613](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4613)
@@ -6,7 +6,7 @@
# Interface: AbsoluteRatePattern2
Defined in: [Developer/brk/modules/brk-client/index.js:4612](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4612)
Defined in: [Developer/brk/modules/brk-client/index.js:4630](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4630)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:4612](https://github.com/
> **absolute**: [`_1m1w1y24hPattern5`](1m1w1y24hPattern5.md)
Defined in: [Developer/brk/modules/brk-client/index.js:4613](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4613)
Defined in: [Developer/brk/modules/brk-client/index.js:4631](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4631)
***
@@ -22,4 +22,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:4613](https://github.com/
> **rate**: [`_1m1w1y24hPattern2`](1m1w1y24hPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:4614](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4614)
Defined in: [Developer/brk/modules/brk-client/index.js:4632](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4632)
@@ -6,7 +6,7 @@
# Interface: AbsoluteRatePattern3
Defined in: [Developer/brk/modules/brk-client/index.js:4631](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4631)
Defined in: [Developer/brk/modules/brk-client/index.js:4649](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4649)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:4631](https://github.com/
> **absolute**: [`_1m1w1y24hPattern7`](1m1w1y24hPattern7.md)
Defined in: [Developer/brk/modules/brk-client/index.js:4632](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4632)
Defined in: [Developer/brk/modules/brk-client/index.js:4650](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4650)
***
@@ -22,4 +22,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:4632](https://github.com/
> **rate**: [`_1m1w1y24hPattern2`](1m1w1y24hPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:4633](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4633)
Defined in: [Developer/brk/modules/brk-client/index.js:4651](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4651)
@@ -6,7 +6,7 @@
# Interface: ActiveBidirectionalReactivatedReceivingSendingPattern
Defined in: [Developer/brk/modules/brk-client/index.js:3360](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3360)
Defined in: [Developer/brk/modules/brk-client/index.js:3378](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3378)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3360](https://github.com/
> **active**: [`_1m1w1y24hBlockPattern`](1m1w1y24hBlockPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3361](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3361)
Defined in: [Developer/brk/modules/brk-client/index.js:3379](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3379)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3361](https://github.com/
> **bidirectional**: [`_1m1w1y24hBlockPattern`](1m1w1y24hBlockPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3362](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3362)
Defined in: [Developer/brk/modules/brk-client/index.js:3380](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3380)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3362](https://github.com/
> **reactivated**: [`_1m1w1y24hBlockPattern`](1m1w1y24hBlockPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3363](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3363)
Defined in: [Developer/brk/modules/brk-client/index.js:3381](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3381)
***
@@ -38,7 +38,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3363](https://github.com/
> **receiving**: [`_1m1w1y24hBlockPattern`](1m1w1y24hBlockPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3364](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3364)
Defined in: [Developer/brk/modules/brk-client/index.js:3382](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3382)
***
@@ -46,4 +46,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3364](https://github.com/
> **sending**: [`_1m1w1y24hBlockPattern`](1m1w1y24hBlockPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3365](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3365)
Defined in: [Developer/brk/modules/brk-client/index.js:3383](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3383)
@@ -6,7 +6,7 @@
# Interface: ActiveInputOutputSpendablePattern
Defined in: [Developer/brk/modules/brk-client/index.js:2992](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2992)
Defined in: [Developer/brk/modules/brk-client/index.js:3010](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3010)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2992](https://github.com/
> **activeReusedAddrCount**: [`_1m1w1y24hBlockPattern`](1m1w1y24hBlockPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2993](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2993)
Defined in: [Developer/brk/modules/brk-client/index.js:3011](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3011)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2993](https://github.com/
> **activeReusedAddrShare**: [`_1m1w1y24hBlockPattern2`](1m1w1y24hBlockPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2994](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2994)
Defined in: [Developer/brk/modules/brk-client/index.js:3012](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3012)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2994](https://github.com/
> **inputFromReusedAddrCount**: [`AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6`](AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2995](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2995)
Defined in: [Developer/brk/modules/brk-client/index.js:3013](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3013)
***
@@ -38,7 +38,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2995](https://github.com/
> **inputFromReusedAddrShare**: [`AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7`](AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2996](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2996)
Defined in: [Developer/brk/modules/brk-client/index.js:3014](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3014)
***
@@ -46,7 +46,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2996](https://github.com/
> **outputToReusedAddrCount**: [`AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6`](AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2997](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2997)
Defined in: [Developer/brk/modules/brk-client/index.js:3015](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3015)
***
@@ -54,7 +54,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2997](https://github.com/
> **outputToReusedAddrShare**: [`AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7`](AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2998](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2998)
Defined in: [Developer/brk/modules/brk-client/index.js:3016](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3016)
***
@@ -62,4 +62,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2998](https://github.com/
> **spendableOutputToReusedAddrShare**: [`_1m1w1y24hBpsPercentRatioPattern`](1m1w1y24hBpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2999](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2999)
Defined in: [Developer/brk/modules/brk-client/index.js:3017](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3017)
@@ -6,7 +6,7 @@
# Interface: ActivityAddrOutputsRealizedSupplyUnrealizedPattern
Defined in: [Developer/brk/modules/brk-client/index.js:3148](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3148)
Defined in: [Developer/brk/modules/brk-client/index.js:3166](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3166)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3148](https://github.com/
> **activity**: [`TransferPattern`](TransferPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3149](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3149)
Defined in: [Developer/brk/modules/brk-client/index.js:3167](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3167)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3149](https://github.com/
> **addrCount**: [`BaseDeltaPattern`](BaseDeltaPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3150](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3150)
Defined in: [Developer/brk/modules/brk-client/index.js:3168](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3168)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3150](https://github.com/
> **outputs**: [`SpendingSpentUnspentPattern`](SpendingSpentUnspentPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3151](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3151)
Defined in: [Developer/brk/modules/brk-client/index.js:3169](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3169)
***
@@ -38,7 +38,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3151](https://github.com/
> **realized**: [`CapLossMvrvPriceProfitPattern`](CapLossMvrvPriceProfitPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3152](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3152)
Defined in: [Developer/brk/modules/brk-client/index.js:3170](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3170)
***
@@ -46,7 +46,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3152](https://github.com/
> **supply**: [`DeltaDominanceTotalPattern`](DeltaDominanceTotalPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3153](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3153)
Defined in: [Developer/brk/modules/brk-client/index.js:3171](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3171)
***
@@ -54,4 +54,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3153](https://github.com/
> **unrealized**: [`NuplPattern`](NuplPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3154](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3154)
Defined in: [Developer/brk/modules/brk-client/index.js:3172](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3172)
@@ -6,7 +6,7 @@
# Interface: ActivityOutputsRealizedSupplyUnrealizedPattern
Defined in: [Developer/brk/modules/brk-client/index.js:3385](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3385)
Defined in: [Developer/brk/modules/brk-client/index.js:3403](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3403)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3385](https://github.com/
> **activity**: [`CoindaysTransferPattern`](CoindaysTransferPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3386](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3386)
Defined in: [Developer/brk/modules/brk-client/index.js:3404](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3404)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3386](https://github.com/
> **outputs**: [`SpendingSpentUnspentPattern`](SpendingSpentUnspentPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3387](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3387)
Defined in: [Developer/brk/modules/brk-client/index.js:3405](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3405)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3387](https://github.com/
> **realized**: [`CapLossMvrvNetPriceProfitSoprPattern`](CapLossMvrvNetPriceProfitSoprPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3388](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3388)
Defined in: [Developer/brk/modules/brk-client/index.js:3406](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3406)
***
@@ -38,7 +38,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3388](https://github.com/
> **supply**: [`DeltaDominanceHalfInTotalPattern`](DeltaDominanceHalfInTotalPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3389](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3389)
Defined in: [Developer/brk/modules/brk-client/index.js:3407](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3407)
***
@@ -46,4 +46,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3389](https://github.com/
> **unrealized**: [`LossNetNuplProfitPattern`](LossNetNuplProfitPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3390](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3390)
Defined in: [Developer/brk/modules/brk-client/index.js:3408](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3408)
@@ -6,7 +6,7 @@
# Interface: ActivityOutputsRealizedSupplyUnrealizedPattern2
Defined in: [Developer/brk/modules/brk-client/index.js:3435](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3435)
Defined in: [Developer/brk/modules/brk-client/index.js:3453](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3453)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3435](https://github.com/
> **activity**: [`TransferPattern`](TransferPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3436](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3436)
Defined in: [Developer/brk/modules/brk-client/index.js:3454](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3454)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3436](https://github.com/
> **outputs**: [`SpendingSpentUnspentPattern`](SpendingSpentUnspentPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3437](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3437)
Defined in: [Developer/brk/modules/brk-client/index.js:3455](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3455)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3437](https://github.com/
> **realized**: [`CapLossMvrvPriceProfitPattern`](CapLossMvrvPriceProfitPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3438](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3438)
Defined in: [Developer/brk/modules/brk-client/index.js:3456](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3456)
***
@@ -38,7 +38,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3438](https://github.com/
> **supply**: [`DeltaDominanceTotalPattern`](DeltaDominanceTotalPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3439](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3439)
Defined in: [Developer/brk/modules/brk-client/index.js:3457](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3457)
***
@@ -46,4 +46,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3439](https://github.com/
> **unrealized**: [`NuplPattern`](NuplPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3440](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3440)
Defined in: [Developer/brk/modules/brk-client/index.js:3458](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3458)
@@ -6,7 +6,7 @@
# Interface: ActivityOutputsRealizedSupplyUnrealizedPattern3
Defined in: [Developer/brk/modules/brk-client/index.js:3410](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3410)
Defined in: [Developer/brk/modules/brk-client/index.js:3428](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3428)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3410](https://github.com/
> **activity**: [`TransferPattern`](TransferPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3411](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3411)
Defined in: [Developer/brk/modules/brk-client/index.js:3429](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3429)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3411](https://github.com/
> **outputs**: [`SpendingSpentUnspentPattern`](SpendingSpentUnspentPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3412](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3412)
Defined in: [Developer/brk/modules/brk-client/index.js:3430](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3430)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3412](https://github.com/
> **realized**: [`CapLossMvrvPriceProfitPattern`](CapLossMvrvPriceProfitPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3413](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3413)
Defined in: [Developer/brk/modules/brk-client/index.js:3431](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3431)
***
@@ -38,7 +38,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3413](https://github.com/
> **supply**: [`DeltaDominanceHalfInTotalPattern`](DeltaDominanceHalfInTotalPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3414](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3414)
Defined in: [Developer/brk/modules/brk-client/index.js:3432](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3432)
***
@@ -46,4 +46,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:3414](https://github.com/
> **unrealized**: [`LossNuplProfitPattern`](LossNuplProfitPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:3415](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L3415)
Defined in: [Developer/brk/modules/brk-client/index.js:3433](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L3433)
@@ -6,7 +6,7 @@
# Interface: AddrAfterTxidParam
Defined in: [Developer/brk/modules/brk-client/index.js:14](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L14)
Defined in: [Developer/brk/modules/brk-client/index.js:14](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L14)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:14](https://github.com/bi
> **address**: `string`
Defined in: [Developer/brk/modules/brk-client/index.js:15](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L15)
Defined in: [Developer/brk/modules/brk-client/index.js:15](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L15)
***
@@ -22,6 +22,6 @@ Defined in: [Developer/brk/modules/brk-client/index.js:15](https://github.com/bi
> **afterTxid**: `string`
Defined in: [Developer/brk/modules/brk-client/index.js:16](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L16)
Defined in: [Developer/brk/modules/brk-client/index.js:16](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L16)
Last txid from the previous page (return transactions strictly older than this)
@@ -6,7 +6,7 @@
# Interface: AddrChainStats
Defined in: [Developer/brk/modules/brk-client/index.js:23](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L23)
Defined in: [Developer/brk/modules/brk-client/index.js:23](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L23)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:23](https://github.com/bi
> **fundedTxoCount**: `number`
Defined in: [Developer/brk/modules/brk-client/index.js:24](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L24)
Defined in: [Developer/brk/modules/brk-client/index.js:24](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L24)
Total number of transaction outputs that funded this address
@@ -24,7 +24,7 @@ Total number of transaction outputs that funded this address
> **fundedTxoSum**: `number`
Defined in: [Developer/brk/modules/brk-client/index.js:25](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L25)
Defined in: [Developer/brk/modules/brk-client/index.js:25](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L25)
Total amount in satoshis received by this address across all funded outputs
@@ -34,7 +34,7 @@ Total amount in satoshis received by this address across all funded outputs
> **realizedPrice**: `number`
Defined in: [Developer/brk/modules/brk-client/index.js:30](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L30)
Defined in: [Developer/brk/modules/brk-client/index.js:30](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L30)
Realized price (average cost basis) in USD
@@ -44,7 +44,7 @@ Realized price (average cost basis) in USD
> **spentTxoCount**: `number`
Defined in: [Developer/brk/modules/brk-client/index.js:26](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L26)
Defined in: [Developer/brk/modules/brk-client/index.js:26](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L26)
Total number of transaction outputs spent from this address
@@ -54,7 +54,7 @@ Total number of transaction outputs spent from this address
> **spentTxoSum**: `number`
Defined in: [Developer/brk/modules/brk-client/index.js:27](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L27)
Defined in: [Developer/brk/modules/brk-client/index.js:27](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L27)
Total amount in satoshis spent from this address
@@ -64,7 +64,7 @@ Total amount in satoshis spent from this address
> **txCount**: `number`
Defined in: [Developer/brk/modules/brk-client/index.js:28](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L28)
Defined in: [Developer/brk/modules/brk-client/index.js:28](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L28)
Total number of confirmed transactions involving this address
@@ -74,6 +74,6 @@ Total number of confirmed transactions involving this address
> **typeIndex**: `number`
Defined in: [Developer/brk/modules/brk-client/index.js:29](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L29)
Defined in: [Developer/brk/modules/brk-client/index.js:29](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L29)
Index of this address within its type on the blockchain
@@ -6,7 +6,7 @@
# Interface: AddrMempoolStats
Defined in: [Developer/brk/modules/brk-client/index.js:37](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L37)
Defined in: [Developer/brk/modules/brk-client/index.js:37](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L37)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:37](https://github.com/bi
> **fundedTxoCount**: `number`
Defined in: [Developer/brk/modules/brk-client/index.js:38](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L38)
Defined in: [Developer/brk/modules/brk-client/index.js:38](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L38)
Number of unconfirmed transaction outputs funding this address
@@ -24,7 +24,7 @@ Number of unconfirmed transaction outputs funding this address
> **fundedTxoSum**: `number`
Defined in: [Developer/brk/modules/brk-client/index.js:39](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L39)
Defined in: [Developer/brk/modules/brk-client/index.js:39](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L39)
Total amount in satoshis being received in unconfirmed transactions
@@ -34,7 +34,7 @@ Total amount in satoshis being received in unconfirmed transactions
> **spentTxoCount**: `number`
Defined in: [Developer/brk/modules/brk-client/index.js:40](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L40)
Defined in: [Developer/brk/modules/brk-client/index.js:40](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L40)
Number of unconfirmed transaction inputs spending from this address
@@ -44,7 +44,7 @@ Number of unconfirmed transaction inputs spending from this address
> **spentTxoSum**: `number`
Defined in: [Developer/brk/modules/brk-client/index.js:41](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L41)
Defined in: [Developer/brk/modules/brk-client/index.js:41](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L41)
Total amount in satoshis being spent in unconfirmed transactions
@@ -54,6 +54,6 @@ Total amount in satoshis being spent in unconfirmed transactions
> **txCount**: `number`
Defined in: [Developer/brk/modules/brk-client/index.js:42](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L42)
Defined in: [Developer/brk/modules/brk-client/index.js:42](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L42)
Number of unconfirmed transactions involving this address
@@ -6,7 +6,7 @@
# Interface: AddrParam
Defined in: [Developer/brk/modules/brk-client/index.js:47](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L47)
Defined in: [Developer/brk/modules/brk-client/index.js:47](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L47)
## Properties
@@ -14,4 +14,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:47](https://github.com/bi
> **address**: `string`
Defined in: [Developer/brk/modules/brk-client/index.js:48](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L48)
Defined in: [Developer/brk/modules/brk-client/index.js:48](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L48)
@@ -6,7 +6,7 @@
# Interface: AddrStats
Defined in: [Developer/brk/modules/brk-client/index.js:53](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L53)
Defined in: [Developer/brk/modules/brk-client/index.js:53](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L53)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:53](https://github.com/bi
> **address**: `string`
Defined in: [Developer/brk/modules/brk-client/index.js:54](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L54)
Defined in: [Developer/brk/modules/brk-client/index.js:54](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L54)
Bitcoin address string
@@ -24,7 +24,7 @@ Bitcoin address string
> **addrType**: [`OutputType`](../type-aliases/OutputType.md)
Defined in: [Developer/brk/modules/brk-client/index.js:55](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L55)
Defined in: [Developer/brk/modules/brk-client/index.js:55](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L55)
Address type (p2pkh, p2sh, v0_p2wpkh, v0_p2wsh, v1_p2tr, etc.)
@@ -34,7 +34,7 @@ Address type (p2pkh, p2sh, v0_p2wpkh, v0_p2wsh, v1_p2tr, etc.)
> **chainStats**: [`AddrChainStats`](AddrChainStats.md)
Defined in: [Developer/brk/modules/brk-client/index.js:56](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L56)
Defined in: [Developer/brk/modules/brk-client/index.js:56](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L56)
Statistics for confirmed transactions on the blockchain
@@ -44,6 +44,6 @@ Statistics for confirmed transactions on the blockchain
> **mempoolStats**: [`AddrMempoolStats`](AddrMempoolStats.md)
Defined in: [Developer/brk/modules/brk-client/index.js:57](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L57)
Defined in: [Developer/brk/modules/brk-client/index.js:57](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L57)
Statistics for unconfirmed transactions in the mempool
@@ -6,7 +6,7 @@
# Interface: AddrUtxoPattern
Defined in: [Developer/brk/modules/brk-client/index.js:4650](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4650)
Defined in: [Developer/brk/modules/brk-client/index.js:4668](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4668)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:4650](https://github.com/
> **addr**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:4651](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4651)
Defined in: [Developer/brk/modules/brk-client/index.js:4669](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4669)
***
@@ -22,4 +22,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:4651](https://github.com/
> **utxo**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:4652](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4652)
Defined in: [Developer/brk/modules/brk-client/index.js:4670](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4670)
@@ -6,7 +6,7 @@
# Interface: AddrValidation
Defined in: [Developer/brk/modules/brk-client/index.js:62](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L62)
Defined in: [Developer/brk/modules/brk-client/index.js:62](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L62)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:62](https://github.com/bi
> `optional` **address?**: `string` \| `null`
Defined in: [Developer/brk/modules/brk-client/index.js:64](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L64)
Defined in: [Developer/brk/modules/brk-client/index.js:64](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L64)
The validated address
@@ -24,7 +24,7 @@ The validated address
> `optional` **error?**: `string` \| `null`
Defined in: [Developer/brk/modules/brk-client/index.js:71](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L71)
Defined in: [Developer/brk/modules/brk-client/index.js:71](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L71)
Error message for invalid addresses
@@ -34,7 +34,7 @@ Error message for invalid addresses
> `optional` **errorLocations?**: `number`[] \| `null`
Defined in: [Developer/brk/modules/brk-client/index.js:70](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L70)
Defined in: [Developer/brk/modules/brk-client/index.js:70](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L70)
Error locations (empty array for most errors)
@@ -44,7 +44,7 @@ Error locations (empty array for most errors)
> `optional` **isscript?**: `boolean` \| `null`
Defined in: [Developer/brk/modules/brk-client/index.js:66](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L66)
Defined in: [Developer/brk/modules/brk-client/index.js:66](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L66)
Whether this is a script address (P2SH)
@@ -54,7 +54,7 @@ Whether this is a script address (P2SH)
> **isvalid**: `boolean`
Defined in: [Developer/brk/modules/brk-client/index.js:63](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L63)
Defined in: [Developer/brk/modules/brk-client/index.js:63](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L63)
Whether the address is valid
@@ -64,7 +64,7 @@ Whether the address is valid
> `optional` **iswitness?**: `boolean` \| `null`
Defined in: [Developer/brk/modules/brk-client/index.js:67](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L67)
Defined in: [Developer/brk/modules/brk-client/index.js:67](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L67)
Whether this is a witness address
@@ -74,7 +74,7 @@ Whether this is a witness address
> `optional` **scriptPubKey?**: `string` \| `null`
Defined in: [Developer/brk/modules/brk-client/index.js:65](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L65)
Defined in: [Developer/brk/modules/brk-client/index.js:65](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L65)
The scriptPubKey in hex
@@ -84,7 +84,7 @@ The scriptPubKey in hex
> `optional` **witnessProgram?**: `string` \| `null`
Defined in: [Developer/brk/modules/brk-client/index.js:69](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L69)
Defined in: [Developer/brk/modules/brk-client/index.js:69](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L69)
Witness program in hex
@@ -94,6 +94,6 @@ Witness program in hex
> `optional` **witnessVersion?**: `number` \| `null`
Defined in: [Developer/brk/modules/brk-client/index.js:68](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L68)
Defined in: [Developer/brk/modules/brk-client/index.js:68](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L68)
Witness version (0 for P2WPKH/P2WSH, 1 for P2TR)
@@ -6,7 +6,7 @@
# Interface: AdjustedRatioValuePattern
Defined in: [Developer/brk/modules/brk-client/index.js:4162](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4162)
Defined in: [Developer/brk/modules/brk-client/index.js:4180](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4180)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:4162](https://github.com/
> **adjusted**: [`RatioTransferValuePattern`](RatioTransferValuePattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:4163](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4163)
Defined in: [Developer/brk/modules/brk-client/index.js:4181](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4181)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:4163](https://github.com/
> **ratio**: [`_1m1w1y24hPattern`](1m1w1y24hPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:4164](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4164)
Defined in: [Developer/brk/modules/brk-client/index.js:4182](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4182)
***
@@ -30,4 +30,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:4164](https://github.com/
> **valueDestroyed**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:4165](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4165)
Defined in: [Developer/brk/modules/brk-client/index.js:4183](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4183)
@@ -6,7 +6,7 @@
# Interface: AllEmptyOpP2aP2msP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshUnknownPattern
Defined in: [Developer/brk/modules/brk-client/index.js:2341](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2341)
Defined in: [Developer/brk/modules/brk-client/index.js:2359](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2359)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2341](https://github.com/
> **all**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2342](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2342)
Defined in: [Developer/brk/modules/brk-client/index.js:2360](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2360)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2342](https://github.com/
> **empty**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2343](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2343)
Defined in: [Developer/brk/modules/brk-client/index.js:2361](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2361)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2343](https://github.com/
> **opReturn**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2344](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2344)
Defined in: [Developer/brk/modules/brk-client/index.js:2362](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2362)
***
@@ -38,7 +38,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2344](https://github.com/
> **p2a**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2345](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2345)
Defined in: [Developer/brk/modules/brk-client/index.js:2363](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2363)
***
@@ -46,7 +46,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2345](https://github.com/
> **p2ms**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2346](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2346)
Defined in: [Developer/brk/modules/brk-client/index.js:2364](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2364)
***
@@ -54,7 +54,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2346](https://github.com/
> **p2pk33**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2347](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2347)
Defined in: [Developer/brk/modules/brk-client/index.js:2365](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2365)
***
@@ -62,7 +62,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2347](https://github.com/
> **p2pk65**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2348](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2348)
Defined in: [Developer/brk/modules/brk-client/index.js:2366](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2366)
***
@@ -70,7 +70,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2348](https://github.com/
> **p2pkh**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2349](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2349)
Defined in: [Developer/brk/modules/brk-client/index.js:2367](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2367)
***
@@ -78,7 +78,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2349](https://github.com/
> **p2sh**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2350](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2350)
Defined in: [Developer/brk/modules/brk-client/index.js:2368](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2368)
***
@@ -86,7 +86,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2350](https://github.com/
> **p2tr**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2351](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2351)
Defined in: [Developer/brk/modules/brk-client/index.js:2369](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2369)
***
@@ -94,7 +94,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2351](https://github.com/
> **p2wpkh**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2352](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2352)
Defined in: [Developer/brk/modules/brk-client/index.js:2370](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2370)
***
@@ -102,7 +102,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2352](https://github.com/
> **p2wsh**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2353](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2353)
Defined in: [Developer/brk/modules/brk-client/index.js:2371](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2371)
***
@@ -110,4 +110,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2353](https://github.com/
> **unknown**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2354](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2354)
Defined in: [Developer/brk/modules/brk-client/index.js:2372](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2372)
@@ -6,7 +6,7 @@
# Interface: AllEmptyP2aP2msP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshUnknownPattern
Defined in: [Developer/brk/modules/brk-client/index.js:2460](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2460)
Defined in: [Developer/brk/modules/brk-client/index.js:2478](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2478)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2460](https://github.com/
> **all**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2461](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2461)
Defined in: [Developer/brk/modules/brk-client/index.js:2479](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2479)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2461](https://github.com/
> **empty**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2462](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2462)
Defined in: [Developer/brk/modules/brk-client/index.js:2480](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2480)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2462](https://github.com/
> **p2a**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2463](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2463)
Defined in: [Developer/brk/modules/brk-client/index.js:2481](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2481)
***
@@ -38,7 +38,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2463](https://github.com/
> **p2ms**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2464](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2464)
Defined in: [Developer/brk/modules/brk-client/index.js:2482](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2482)
***
@@ -46,7 +46,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2464](https://github.com/
> **p2pk33**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2465](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2465)
Defined in: [Developer/brk/modules/brk-client/index.js:2483](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2483)
***
@@ -54,7 +54,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2465](https://github.com/
> **p2pk65**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2466](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2466)
Defined in: [Developer/brk/modules/brk-client/index.js:2484](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2484)
***
@@ -62,7 +62,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2466](https://github.com/
> **p2pkh**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2467](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2467)
Defined in: [Developer/brk/modules/brk-client/index.js:2485](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2485)
***
@@ -70,7 +70,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2467](https://github.com/
> **p2sh**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2468](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2468)
Defined in: [Developer/brk/modules/brk-client/index.js:2486](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2486)
***
@@ -78,7 +78,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2468](https://github.com/
> **p2tr**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2469](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2469)
Defined in: [Developer/brk/modules/brk-client/index.js:2487](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2487)
***
@@ -86,7 +86,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2469](https://github.com/
> **p2wpkh**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2470](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2470)
Defined in: [Developer/brk/modules/brk-client/index.js:2488](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2488)
***
@@ -94,7 +94,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2470](https://github.com/
> **p2wsh**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2471](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2471)
Defined in: [Developer/brk/modules/brk-client/index.js:2489](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2489)
***
@@ -102,4 +102,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2471](https://github.com/
> **unknown**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2472](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2472)
Defined in: [Developer/brk/modules/brk-client/index.js:2490](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2490)
@@ -6,7 +6,7 @@
# Interface: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern4
Defined in: [Developer/brk/modules/brk-client/index.js:2759](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2759)
Defined in: [Developer/brk/modules/brk-client/index.js:2777](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2777)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2759](https://github.com/
> **all**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2760](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2760)
Defined in: [Developer/brk/modules/brk-client/index.js:2778](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2778)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2760](https://github.com/
> **p2a**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2761](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2761)
Defined in: [Developer/brk/modules/brk-client/index.js:2779](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2779)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2761](https://github.com/
> **p2pk33**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2762](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2762)
Defined in: [Developer/brk/modules/brk-client/index.js:2780](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2780)
***
@@ -38,7 +38,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2762](https://github.com/
> **p2pk65**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2763](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2763)
Defined in: [Developer/brk/modules/brk-client/index.js:2781](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2781)
***
@@ -46,7 +46,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2763](https://github.com/
> **p2pkh**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2764](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2764)
Defined in: [Developer/brk/modules/brk-client/index.js:2782](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2782)
***
@@ -54,7 +54,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2764](https://github.com/
> **p2sh**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2765](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2765)
Defined in: [Developer/brk/modules/brk-client/index.js:2783](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2783)
***
@@ -62,7 +62,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2765](https://github.com/
> **p2tr**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2766](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2766)
Defined in: [Developer/brk/modules/brk-client/index.js:2784](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2784)
***
@@ -70,7 +70,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2766](https://github.com/
> **p2wpkh**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2767](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2767)
Defined in: [Developer/brk/modules/brk-client/index.js:2785](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2785)
***
@@ -78,4 +78,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2767](https://github.com/
> **p2wsh**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2768](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2768)
Defined in: [Developer/brk/modules/brk-client/index.js:2786](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2786)
@@ -6,7 +6,7 @@
# Interface: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5
Defined in: [Developer/brk/modules/brk-client/index.js:2726](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2726)
Defined in: [Developer/brk/modules/brk-client/index.js:2744](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2744)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2726](https://github.com/
> **all**: [`BpsPercentRatioPattern2`](BpsPercentRatioPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2727](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2727)
Defined in: [Developer/brk/modules/brk-client/index.js:2745](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2745)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2727](https://github.com/
> **p2a**: [`BpsPercentRatioPattern2`](BpsPercentRatioPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2728](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2728)
Defined in: [Developer/brk/modules/brk-client/index.js:2746](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2746)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2728](https://github.com/
> **p2pk33**: [`BpsPercentRatioPattern2`](BpsPercentRatioPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2729](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2729)
Defined in: [Developer/brk/modules/brk-client/index.js:2747](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2747)
***
@@ -38,7 +38,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2729](https://github.com/
> **p2pk65**: [`BpsPercentRatioPattern2`](BpsPercentRatioPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2730](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2730)
Defined in: [Developer/brk/modules/brk-client/index.js:2748](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2748)
***
@@ -46,7 +46,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2730](https://github.com/
> **p2pkh**: [`BpsPercentRatioPattern2`](BpsPercentRatioPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2731](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2731)
Defined in: [Developer/brk/modules/brk-client/index.js:2749](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2749)
***
@@ -54,7 +54,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2731](https://github.com/
> **p2sh**: [`BpsPercentRatioPattern2`](BpsPercentRatioPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2732](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2732)
Defined in: [Developer/brk/modules/brk-client/index.js:2750](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2750)
***
@@ -62,7 +62,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2732](https://github.com/
> **p2tr**: [`BpsPercentRatioPattern2`](BpsPercentRatioPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2733](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2733)
Defined in: [Developer/brk/modules/brk-client/index.js:2751](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2751)
***
@@ -70,7 +70,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2733](https://github.com/
> **p2wpkh**: [`BpsPercentRatioPattern2`](BpsPercentRatioPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2734](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2734)
Defined in: [Developer/brk/modules/brk-client/index.js:2752](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2752)
***
@@ -78,4 +78,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2734](https://github.com/
> **p2wsh**: [`BpsPercentRatioPattern2`](BpsPercentRatioPattern2.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2735](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2735)
Defined in: [Developer/brk/modules/brk-client/index.js:2753](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2753)
@@ -6,7 +6,7 @@
# Interface: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern6
Defined in: [Developer/brk/modules/brk-client/index.js:2693](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2693)
Defined in: [Developer/brk/modules/brk-client/index.js:2711](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2711)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2693](https://github.com/
> **all**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2694](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2694)
Defined in: [Developer/brk/modules/brk-client/index.js:2712](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2712)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2694](https://github.com/
> **p2a**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2695](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2695)
Defined in: [Developer/brk/modules/brk-client/index.js:2713](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2713)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2695](https://github.com/
> **p2pk33**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2696](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2696)
Defined in: [Developer/brk/modules/brk-client/index.js:2714](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2714)
***
@@ -38,7 +38,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2696](https://github.com/
> **p2pk65**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2697](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2697)
Defined in: [Developer/brk/modules/brk-client/index.js:2715](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2715)
***
@@ -46,7 +46,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2697](https://github.com/
> **p2pkh**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2698](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2698)
Defined in: [Developer/brk/modules/brk-client/index.js:2716](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2716)
***
@@ -54,7 +54,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2698](https://github.com/
> **p2sh**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2699](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2699)
Defined in: [Developer/brk/modules/brk-client/index.js:2717](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2717)
***
@@ -62,7 +62,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2699](https://github.com/
> **p2tr**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2700](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2700)
Defined in: [Developer/brk/modules/brk-client/index.js:2718](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2718)
***
@@ -70,7 +70,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2700](https://github.com/
> **p2wpkh**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2701](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2701)
Defined in: [Developer/brk/modules/brk-client/index.js:2719](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2719)
***
@@ -78,4 +78,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2701](https://github.com/
> **p2wsh**: [`AverageBlockCumulativeSumPattern`](AverageBlockCumulativeSumPattern.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2702](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2702)
Defined in: [Developer/brk/modules/brk-client/index.js:2720](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2720)
@@ -6,7 +6,7 @@
# Interface: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern7
Defined in: [Developer/brk/modules/brk-client/index.js:2792](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2792)
Defined in: [Developer/brk/modules/brk-client/index.js:2810](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2810)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2792](https://github.com/
> **all**: [`_1m1w1y24hBpsPercentRatioPattern`](1m1w1y24hBpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2793](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2793)
Defined in: [Developer/brk/modules/brk-client/index.js:2811](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2811)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2793](https://github.com/
> **p2a**: [`_1m1w1y24hBpsPercentRatioPattern`](1m1w1y24hBpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2794](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2794)
Defined in: [Developer/brk/modules/brk-client/index.js:2812](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2812)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2794](https://github.com/
> **p2pk33**: [`_1m1w1y24hBpsPercentRatioPattern`](1m1w1y24hBpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2795](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2795)
Defined in: [Developer/brk/modules/brk-client/index.js:2813](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2813)
***
@@ -38,7 +38,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2795](https://github.com/
> **p2pk65**: [`_1m1w1y24hBpsPercentRatioPattern`](1m1w1y24hBpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2796](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2796)
Defined in: [Developer/brk/modules/brk-client/index.js:2814](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2814)
***
@@ -46,7 +46,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2796](https://github.com/
> **p2pkh**: [`_1m1w1y24hBpsPercentRatioPattern`](1m1w1y24hBpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2797](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2797)
Defined in: [Developer/brk/modules/brk-client/index.js:2815](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2815)
***
@@ -54,7 +54,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2797](https://github.com/
> **p2sh**: [`_1m1w1y24hBpsPercentRatioPattern`](1m1w1y24hBpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2798](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2798)
Defined in: [Developer/brk/modules/brk-client/index.js:2816](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2816)
***
@@ -62,7 +62,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2798](https://github.com/
> **p2tr**: [`_1m1w1y24hBpsPercentRatioPattern`](1m1w1y24hBpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2799](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2799)
Defined in: [Developer/brk/modules/brk-client/index.js:2817](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2817)
***
@@ -70,7 +70,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2799](https://github.com/
> **p2wpkh**: [`_1m1w1y24hBpsPercentRatioPattern`](1m1w1y24hBpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2800](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2800)
Defined in: [Developer/brk/modules/brk-client/index.js:2818](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2818)
***
@@ -78,4 +78,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2800](https://github.com/
> **p2wsh**: [`_1m1w1y24hBpsPercentRatioPattern`](1m1w1y24hBpsPercentRatioPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2801](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2801)
Defined in: [Developer/brk/modules/brk-client/index.js:2819](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2819)
@@ -6,7 +6,7 @@
# Interface: AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshSharePattern
Defined in: [Developer/brk/modules/brk-client/index.js:2644](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2644)
Defined in: [Developer/brk/modules/brk-client/index.js:2662](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2662)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2644](https://github.com/
> **all**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2645](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2645)
Defined in: [Developer/brk/modules/brk-client/index.js:2663](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2663)
***
@@ -22,7 +22,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2645](https://github.com/
> **p2a**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2646](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2646)
Defined in: [Developer/brk/modules/brk-client/index.js:2664](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2664)
***
@@ -30,7 +30,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2646](https://github.com/
> **p2pk33**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2647](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2647)
Defined in: [Developer/brk/modules/brk-client/index.js:2665](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2665)
***
@@ -38,7 +38,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2647](https://github.com/
> **p2pk65**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2648](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2648)
Defined in: [Developer/brk/modules/brk-client/index.js:2666](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2666)
***
@@ -46,7 +46,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2648](https://github.com/
> **p2pkh**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2649](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2649)
Defined in: [Developer/brk/modules/brk-client/index.js:2667](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2667)
***
@@ -54,7 +54,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2649](https://github.com/
> **p2sh**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2650](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2650)
Defined in: [Developer/brk/modules/brk-client/index.js:2668](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2668)
***
@@ -62,7 +62,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2650](https://github.com/
> **p2tr**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2651](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2651)
Defined in: [Developer/brk/modules/brk-client/index.js:2669](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2669)
***
@@ -70,7 +70,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2651](https://github.com/
> **p2wpkh**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2652](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2652)
Defined in: [Developer/brk/modules/brk-client/index.js:2670](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2670)
***
@@ -78,7 +78,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2652](https://github.com/
> **p2wsh**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2653](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2653)
Defined in: [Developer/brk/modules/brk-client/index.js:2671](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2671)
***
@@ -86,4 +86,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2653](https://github.com/
> **share**: [`AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5`](AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern5.md)
Defined in: [Developer/brk/modules/brk-client/index.js:2654](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2654)
Defined in: [Developer/brk/modules/brk-client/index.js:2672](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2672)
@@ -6,7 +6,7 @@
# Interface: AllSthPattern
Defined in: [Developer/brk/modules/brk-client/index.js:4688](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4688)
Defined in: [Developer/brk/modules/brk-client/index.js:4706](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4706)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:4688](https://github.com/
> **all**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:4689](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4689)
Defined in: [Developer/brk/modules/brk-client/index.js:4707](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4707)
***
@@ -22,4 +22,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:4689](https://github.com/
> **sth**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`number`\>
Defined in: [Developer/brk/modules/brk-client/index.js:4690](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4690)
Defined in: [Developer/brk/modules/brk-client/index.js:4708](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4708)
@@ -6,7 +6,7 @@
# Interface: AllSthPattern2
Defined in: [Developer/brk/modules/brk-client/index.js:4669](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4669)
Defined in: [Developer/brk/modules/brk-client/index.js:4687](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4687)
## Properties
@@ -14,7 +14,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:4669](https://github.com/
> **all**: [`BtcCentsDeltaSatsUsdPattern`](BtcCentsDeltaSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:4670](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4670)
Defined in: [Developer/brk/modules/brk-client/index.js:4688](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4688)
***
@@ -22,4 +22,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:4670](https://github.com/
> **sth**: [`BtcCentsSatsUsdPattern`](BtcCentsSatsUsdPattern.md)
Defined in: [Developer/brk/modules/brk-client/index.js:4671](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L4671)
Defined in: [Developer/brk/modules/brk-client/index.js:4689](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L4689)
@@ -6,7 +6,7 @@
# Interface: AverageBaseCumulativeMaxMedianMinPct10Pct25Pct75Pct90SumPattern\<T\>
Defined in: [Developer/brk/modules/brk-client/index.js:2606](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2606)
Defined in: [Developer/brk/modules/brk-client/index.js:2624](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2624)
## Type Parameters
@@ -20,7 +20,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2606](https://github.com/
> **average**: [`_1m1w1y24hPattern`](1m1w1y24hPattern.md)\<`T`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2607](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2607)
Defined in: [Developer/brk/modules/brk-client/index.js:2625](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2625)
***
@@ -28,7 +28,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2607](https://github.com/
> **base**: [`SeriesPattern18`](../type-aliases/SeriesPattern18.md)\<`T`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2608](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2608)
Defined in: [Developer/brk/modules/brk-client/index.js:2626](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2626)
***
@@ -36,7 +36,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2608](https://github.com/
> **cumulative**: [`SeriesPattern1`](../type-aliases/SeriesPattern1.md)\<`T`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2609](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2609)
Defined in: [Developer/brk/modules/brk-client/index.js:2627](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2627)
***
@@ -44,7 +44,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2609](https://github.com/
> **max**: [`_1m1w1y24hPattern`](1m1w1y24hPattern.md)\<`T`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2610](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2610)
Defined in: [Developer/brk/modules/brk-client/index.js:2628](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2628)
***
@@ -52,7 +52,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2610](https://github.com/
> **median**: [`_1m1w1y24hPattern`](1m1w1y24hPattern.md)\<`T`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2611](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2611)
Defined in: [Developer/brk/modules/brk-client/index.js:2629](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2629)
***
@@ -60,7 +60,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2611](https://github.com/
> **min**: [`_1m1w1y24hPattern`](1m1w1y24hPattern.md)\<`T`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2612](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2612)
Defined in: [Developer/brk/modules/brk-client/index.js:2630](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2630)
***
@@ -68,7 +68,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2612](https://github.com/
> **pct10**: [`_1m1w1y24hPattern`](1m1w1y24hPattern.md)\<`T`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2613](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2613)
Defined in: [Developer/brk/modules/brk-client/index.js:2631](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2631)
***
@@ -76,7 +76,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2613](https://github.com/
> **pct25**: [`_1m1w1y24hPattern`](1m1w1y24hPattern.md)\<`T`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2614](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2614)
Defined in: [Developer/brk/modules/brk-client/index.js:2632](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2632)
***
@@ -84,7 +84,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2614](https://github.com/
> **pct75**: [`_1m1w1y24hPattern`](1m1w1y24hPattern.md)\<`T`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2615](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2615)
Defined in: [Developer/brk/modules/brk-client/index.js:2633](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2633)
***
@@ -92,7 +92,7 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2615](https://github.com/
> **pct90**: [`_1m1w1y24hPattern`](1m1w1y24hPattern.md)\<`T`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2616](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2616)
Defined in: [Developer/brk/modules/brk-client/index.js:2634](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2634)
***
@@ -100,4 +100,4 @@ Defined in: [Developer/brk/modules/brk-client/index.js:2616](https://github.com/
> **sum**: [`_1m1w1y24hPattern`](1m1w1y24hPattern.md)\<`T`\>
Defined in: [Developer/brk/modules/brk-client/index.js:2617](https://github.com/bitcoinresearchkit/brk/blob/0b871e86004ed9dd0c54dd9336049531d6fe4d23/modules/brk-client/index.js#L2617)
Defined in: [Developer/brk/modules/brk-client/index.js:2635](https://github.com/bitcoinresearchkit/brk/blob/d161462137a58a76f972f5e15b0029af02a165ca/modules/brk-client/index.js#L2635)

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