mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-24 06:39:58 -07:00
global: address -> addr rename
This commit is contained in:
152
Cargo.lock
generated
152
Cargo.lock
generated
@@ -799,9 +799,9 @@ checksum = "1c53ba0f290bfc610084c05582d9c5d421662128fc69f4bf236707af6fd321b9"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.56"
|
version = "1.2.57"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2"
|
checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"find-msvc-tools",
|
"find-msvc-tools",
|
||||||
"jobserver",
|
"jobserver",
|
||||||
@@ -1292,9 +1292,9 @@ checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fjall"
|
name = "fjall"
|
||||||
version = "3.1.0"
|
version = "3.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "40cb1eb0cef3792900897b32c8282f6417bc978f6af46400a2f14bf0e649ae30"
|
checksum = "48cf071a6f6090e99f3e095aaca9d38f78ad6fcf40bca736dc4cf7cbe15e4438"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder-lite",
|
"byteorder-lite",
|
||||||
"byteview",
|
"byteview",
|
||||||
@@ -1302,7 +1302,7 @@ dependencies = [
|
|||||||
"flume",
|
"flume",
|
||||||
"log",
|
"log",
|
||||||
"lsm-tree",
|
"lsm-tree",
|
||||||
"lz4_flex 0.11.5",
|
"lz4_flex 0.11.6",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"xxhash-rust",
|
"xxhash-rust",
|
||||||
]
|
]
|
||||||
@@ -2000,9 +2000,9 @@ checksum = "803ec87c9cfb29b9d2633f20cba1f488db3fd53f2158b1024cbefb47ba05d413"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.182"
|
version = "0.2.183"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
|
checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libloading"
|
name = "libloading"
|
||||||
@@ -2080,9 +2080,9 @@ checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lsm-tree"
|
name = "lsm-tree"
|
||||||
version = "3.1.0"
|
version = "3.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc5fa40c207eed45c811085aaa1b0a25fead22e298e286081cd4b98785fe759b"
|
checksum = "e97484b43ad0b232eaaeb83ee6edbf5d2e3602a389eee4205997b4ad3f6d3ace"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder-lite",
|
"byteorder-lite",
|
||||||
"byteview",
|
"byteview",
|
||||||
@@ -2090,7 +2090,7 @@ dependencies = [
|
|||||||
"enum_dispatch",
|
"enum_dispatch",
|
||||||
"interval-heap",
|
"interval-heap",
|
||||||
"log",
|
"log",
|
||||||
"lz4_flex 0.11.5",
|
"lz4_flex 0.11.6",
|
||||||
"quick_cache",
|
"quick_cache",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"self_cell",
|
"self_cell",
|
||||||
@@ -2102,18 +2102,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lz4_flex"
|
name = "lz4_flex"
|
||||||
version = "0.11.5"
|
version = "0.11.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08ab2867e3eeeca90e844d1940eab391c9dc5228783db2ed999acbc0a9ed375a"
|
checksum = "373f5eceeeab7925e0c1098212f2fbc4d416adec9d35051a6ab251e824c1854a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"twox-hash",
|
"twox-hash",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lz4_flex"
|
name = "lz4_flex"
|
||||||
version = "0.12.0"
|
version = "0.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ab6473172471198271ff72e9379150e9dfd70d8e533e0752a27e515b48dd375e"
|
checksum = "db9a0d582c2874f68138a16ce1867e0ffde6c0bb0a0df85e1f36d04146db488a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matchit"
|
name = "matchit"
|
||||||
@@ -2241,9 +2241,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.21.3"
|
version = "1.21.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "option-ext"
|
name = "option-ext"
|
||||||
@@ -2402,9 +2402,9 @@ checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "portable-atomic-util"
|
name = "portable-atomic-util"
|
||||||
version = "0.2.5"
|
version = "0.2.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5"
|
checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"portable-atomic",
|
"portable-atomic",
|
||||||
]
|
]
|
||||||
@@ -2976,12 +2976,12 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.6.2"
|
version = "0.6.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0"
|
checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.60.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3056,9 +3056,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.26.0"
|
version = "3.27.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0"
|
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"getrandom 0.4.2",
|
"getrandom 0.4.2",
|
||||||
@@ -3318,9 +3318,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-subscriber"
|
name = "tracing-subscriber"
|
||||||
version = "0.3.22"
|
version = "0.3.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
|
checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"sharded-slab",
|
"sharded-slab",
|
||||||
"thread_local",
|
"thread_local",
|
||||||
@@ -3439,7 +3439,7 @@ dependencies = [
|
|||||||
"itoa",
|
"itoa",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"lz4_flex 0.12.0",
|
"lz4_flex 0.13.0",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"pco",
|
"pco",
|
||||||
"rawdb",
|
"rawdb",
|
||||||
@@ -3701,16 +3701,7 @@ version = "0.52.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets 0.52.6",
|
"windows-targets",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.60.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets 0.53.5",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3728,31 +3719,14 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_gnullvm 0.52.6",
|
"windows_aarch64_gnullvm",
|
||||||
"windows_aarch64_msvc 0.52.6",
|
"windows_aarch64_msvc",
|
||||||
"windows_i686_gnu 0.52.6",
|
"windows_i686_gnu",
|
||||||
"windows_i686_gnullvm 0.52.6",
|
"windows_i686_gnullvm",
|
||||||
"windows_i686_msvc 0.52.6",
|
"windows_i686_msvc",
|
||||||
"windows_x86_64_gnu 0.52.6",
|
"windows_x86_64_gnu",
|
||||||
"windows_x86_64_gnullvm 0.52.6",
|
"windows_x86_64_gnullvm",
|
||||||
"windows_x86_64_msvc 0.52.6",
|
"windows_x86_64_msvc",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-targets"
|
|
||||||
version = "0.53.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
|
|
||||||
dependencies = [
|
|
||||||
"windows-link",
|
|
||||||
"windows_aarch64_gnullvm 0.53.1",
|
|
||||||
"windows_aarch64_msvc 0.53.1",
|
|
||||||
"windows_i686_gnu 0.53.1",
|
|
||||||
"windows_i686_gnullvm 0.53.1",
|
|
||||||
"windows_i686_msvc 0.53.1",
|
|
||||||
"windows_x86_64_gnu 0.53.1",
|
|
||||||
"windows_x86_64_gnullvm 0.53.1",
|
|
||||||
"windows_x86_64_msvc 0.53.1",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3761,96 +3735,48 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_gnullvm"
|
|
||||||
version = "0.53.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_msvc"
|
|
||||||
version = "0.53.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnu"
|
|
||||||
version = "0.53.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnullvm"
|
name = "windows_i686_gnullvm"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnullvm"
|
|
||||||
version = "0.53.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_msvc"
|
|
||||||
version = "0.53.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnu"
|
|
||||||
version = "0.53.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnullvm"
|
|
||||||
version = "0.53.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_msvc"
|
|
||||||
version = "0.53.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.7.15"
|
version = "0.7.15"
|
||||||
@@ -4002,18 +3928,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.8.40"
|
version = "0.8.42"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5"
|
checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy-derive",
|
"zerocopy-derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy-derive"
|
name = "zerocopy-derive"
|
||||||
version = "0.8.40"
|
version = "0.8.42"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953"
|
checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ color-eyre = "0.6.5"
|
|||||||
corepc-client = { path = "/Users/k/Developer/corepc/client", features = ["client-sync"] }
|
corepc-client = { path = "/Users/k/Developer/corepc/client", features = ["client-sync"] }
|
||||||
corepc-jsonrpc = { package = "jsonrpc", path = "/Users/k/Developer/corepc/jsonrpc", features = ["simple_http"], default-features = false }
|
corepc-jsonrpc = { package = "jsonrpc", path = "/Users/k/Developer/corepc/jsonrpc", features = ["simple_http"], default-features = false }
|
||||||
derive_more = { version = "2.1.1", features = ["deref", "deref_mut"] }
|
derive_more = { version = "2.1.1", features = ["deref", "deref_mut"] }
|
||||||
fjall = "3.1.0"
|
fjall = "3.1.1"
|
||||||
indexmap = { version = "2.13.0", features = ["serde"] }
|
indexmap = { version = "2.13.0", features = ["serde"] }
|
||||||
jiff = { version = "0.2.23", features = ["perf-inline", "tz-system"], default-features = false }
|
jiff = { version = "0.2.23", features = ["perf-inline", "tz-system"], default-features = false }
|
||||||
owo-colors = "4.3.0"
|
owo-colors = "4.3.0"
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ fn main() -> brk_client::Result<()> {
|
|||||||
let client = BrkClient::new("http://localhost:3110");
|
let client = BrkClient::new("http://localhost:3110");
|
||||||
|
|
||||||
// Get the metrics catalog tree
|
// Get the metrics catalog tree
|
||||||
let tree = client.get_metrics_tree()?;
|
let tree = client.get_series_tree()?;
|
||||||
|
|
||||||
// Recursively collect all metrics
|
// Recursively collect all metrics
|
||||||
let metrics = collect_metrics(&tree, "");
|
let metrics = collect_metrics(&tree, "");
|
||||||
@@ -58,7 +58,7 @@ fn main() -> brk_client::Result<()> {
|
|||||||
let index_str = index.name();
|
let index_str = index.name();
|
||||||
let full_path = format!("{}.by.{}", metric.path, index_str);
|
let full_path = format!("{}.by.{}", metric.path, index_str);
|
||||||
|
|
||||||
match client.get_metric(
|
match client.get_series(
|
||||||
metric.name.as_str().into(),
|
metric.name.as_str().into(),
|
||||||
*index,
|
*index,
|
||||||
None,
|
None,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -6,13 +6,13 @@ use crate::Filter;
|
|||||||
use super::{AmountRange, OverAmount, UnderAmount};
|
use super::{AmountRange, OverAmount, UnderAmount};
|
||||||
|
|
||||||
#[derive(Default, Clone, Traversable)]
|
#[derive(Default, Clone, Traversable)]
|
||||||
pub struct AddressGroups<T> {
|
pub struct AddrGroups<T> {
|
||||||
pub over_amount: OverAmount<T>,
|
pub over_amount: OverAmount<T>,
|
||||||
pub amount_range: AmountRange<T>,
|
pub amount_range: AmountRange<T>,
|
||||||
pub under_amount: UnderAmount<T>,
|
pub under_amount: UnderAmount<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AddressGroups<T> {
|
impl<T> AddrGroups<T> {
|
||||||
pub fn new<F>(mut create: F) -> Self
|
pub fn new<F>(mut create: F) -> Self
|
||||||
where
|
where
|
||||||
F: FnMut(Filter, &'static str) -> T,
|
F: FnMut(Filter, &'static str) -> T,
|
||||||
@@ -17,7 +17,7 @@ pub const P2TR: &str = "p2tr";
|
|||||||
pub const P2A: &str = "p2a";
|
pub const P2A: &str = "p2a";
|
||||||
|
|
||||||
#[derive(Default, Clone, Debug, Traversable)]
|
#[derive(Default, Clone, Debug, Traversable)]
|
||||||
pub struct ByAddressType<T> {
|
pub struct ByAddrType<T> {
|
||||||
pub p2pk65: T,
|
pub p2pk65: T,
|
||||||
pub p2pk33: T,
|
pub p2pk33: T,
|
||||||
pub p2pkh: T,
|
pub p2pkh: T,
|
||||||
@@ -28,7 +28,7 @@ pub struct ByAddressType<T> {
|
|||||||
pub p2a: T,
|
pub p2a: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ByAddressType<T> {
|
impl<T> ByAddrType<T> {
|
||||||
pub fn new<F>(mut create: F) -> Self
|
pub fn new<F>(mut create: F) -> Self
|
||||||
where
|
where
|
||||||
F: FnMut(Filter) -> T,
|
F: FnMut(Filter) -> T,
|
||||||
@@ -61,8 +61,8 @@ impl<T> ByAddressType<T> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_with_name<U>(&self, f: impl Fn(&'static str, &T) -> U) -> ByAddressType<U> {
|
pub fn map_with_name<U>(&self, f: impl Fn(&'static str, &T) -> U) -> ByAddrType<U> {
|
||||||
ByAddressType {
|
ByAddrType {
|
||||||
p2pk65: f(P2PK65, &self.p2pk65),
|
p2pk65: f(P2PK65, &self.p2pk65),
|
||||||
p2pk33: f(P2PK33, &self.p2pk33),
|
p2pk33: f(P2PK33, &self.p2pk33),
|
||||||
p2pkh: f(P2PKH, &self.p2pkh),
|
p2pkh: f(P2PKH, &self.p2pkh),
|
||||||
@@ -91,13 +91,13 @@ impl<T> ByAddressType<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_unwrap(&self, addresstype: OutputType) -> &T {
|
pub fn get_unwrap(&self, addr_type: OutputType) -> &T {
|
||||||
self.get(addresstype).unwrap()
|
self.get(addr_type).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get(&self, address_type: OutputType) -> Option<&T> {
|
pub fn get(&self, addr_type: OutputType) -> Option<&T> {
|
||||||
match address_type {
|
match addr_type {
|
||||||
OutputType::P2PK65 => Some(&self.p2pk65),
|
OutputType::P2PK65 => Some(&self.p2pk65),
|
||||||
OutputType::P2PK33 => Some(&self.p2pk33),
|
OutputType::P2PK33 => Some(&self.p2pk33),
|
||||||
OutputType::P2PKH => Some(&self.p2pkh),
|
OutputType::P2PKH => Some(&self.p2pkh),
|
||||||
@@ -111,13 +111,13 @@ impl<T> ByAddressType<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_mut_unwrap(&mut self, addresstype: OutputType) -> &mut T {
|
pub fn get_mut_unwrap(&mut self, addr_type: OutputType) -> &mut T {
|
||||||
self.get_mut(addresstype).unwrap()
|
self.get_mut(addr_type).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_mut(&mut self, address_type: OutputType) -> Option<&mut T> {
|
pub fn get_mut(&mut self, addr_type: OutputType) -> Option<&mut T> {
|
||||||
match address_type {
|
match addr_type {
|
||||||
OutputType::P2PK65 => Some(&mut self.p2pk65),
|
OutputType::P2PK65 => Some(&mut self.p2pk65),
|
||||||
OutputType::P2PK33 => Some(&mut self.p2pk33),
|
OutputType::P2PK33 => Some(&mut self.p2pk33),
|
||||||
OutputType::P2PKH => Some(&mut self.p2pkh),
|
OutputType::P2PKH => Some(&mut self.p2pkh),
|
||||||
@@ -243,7 +243,7 @@ impl<T> ByAddressType<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Add for ByAddressType<T>
|
impl<T> Add for ByAddrType<T>
|
||||||
where
|
where
|
||||||
T: Add<Output = T>,
|
T: Add<Output = T>,
|
||||||
{
|
{
|
||||||
@@ -262,7 +262,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AddAssign for ByAddressType<T>
|
impl<T> AddAssign for ByAddrType<T>
|
||||||
where
|
where
|
||||||
T: AddAssign,
|
T: AddAssign,
|
||||||
{
|
{
|
||||||
@@ -278,7 +278,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ByAddressType<Option<T>> {
|
impl<T> ByAddrType<Option<T>> {
|
||||||
pub fn take(&mut self) {
|
pub fn take(&mut self) {
|
||||||
self.values_mut().for_each(|opt| {
|
self.values_mut().for_each(|opt| {
|
||||||
opt.take();
|
opt.take();
|
||||||
@@ -286,12 +286,12 @@ impl<T> ByAddressType<Option<T>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Zip one ByAddressType with a function, producing a new ByAddressType.
|
/// Zip one ByAddrType with a function, producing a new ByAddrType.
|
||||||
pub fn zip_by_addresstype<S, R, F>(source: &ByAddressType<S>, f: F) -> Result<ByAddressType<R>>
|
pub fn zip_by_addr_type<S, R, F>(source: &ByAddrType<S>, f: F) -> Result<ByAddrType<R>>
|
||||||
where
|
where
|
||||||
F: Fn(&'static str, &S) -> Result<R>,
|
F: Fn(&'static str, &S) -> Result<R>,
|
||||||
{
|
{
|
||||||
Ok(ByAddressType {
|
Ok(ByAddrType {
|
||||||
p2pk65: f(P2PK65, &source.p2pk65)?,
|
p2pk65: f(P2PK65, &source.p2pk65)?,
|
||||||
p2pk33: f(P2PK33, &source.p2pk33)?,
|
p2pk33: f(P2PK33, &source.p2pk33)?,
|
||||||
p2pkh: f(P2PKH, &source.p2pkh)?,
|
p2pkh: f(P2PKH, &source.p2pkh)?,
|
||||||
@@ -303,16 +303,16 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Zip two ByAddressTypes with a function, producing a new ByAddressType.
|
/// Zip two ByAddrTypes with a function, producing a new ByAddrType.
|
||||||
pub fn zip2_by_addresstype<S1, S2, R, F>(
|
pub fn zip2_by_addr_type<S1, S2, R, F>(
|
||||||
a: &ByAddressType<S1>,
|
a: &ByAddrType<S1>,
|
||||||
b: &ByAddressType<S2>,
|
b: &ByAddrType<S2>,
|
||||||
f: F,
|
f: F,
|
||||||
) -> Result<ByAddressType<R>>
|
) -> Result<ByAddrType<R>>
|
||||||
where
|
where
|
||||||
F: Fn(&'static str, &S1, &S2) -> Result<R>,
|
F: Fn(&'static str, &S1, &S2) -> Result<R>,
|
||||||
{
|
{
|
||||||
Ok(ByAddressType {
|
Ok(ByAddrType {
|
||||||
p2pk65: f(P2PK65, &a.p2pk65, &b.p2pk65)?,
|
p2pk65: f(P2PK65, &a.p2pk65, &b.p2pk65)?,
|
||||||
p2pk33: f(P2PK33, &a.p2pk33, &b.p2pk33)?,
|
p2pk33: f(P2PK33, &a.p2pk33, &b.p2pk33)?,
|
||||||
p2pkh: f(P2PKH, &a.p2pkh, &b.p2pkh)?,
|
p2pkh: f(P2PKH, &a.p2pkh, &b.p2pkh)?,
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
use brk_traversable::Traversable;
|
use brk_traversable::Traversable;
|
||||||
|
|
||||||
#[derive(Debug, Default, Traversable)]
|
#[derive(Debug, Default, Traversable)]
|
||||||
pub struct ByAnyAddress<T> {
|
pub struct ByAnyAddr<T> {
|
||||||
pub funded: T,
|
pub funded: T,
|
||||||
pub empty: T,
|
pub empty: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ByAnyAddress<Option<T>> {
|
impl<T> ByAnyAddr<Option<T>> {
|
||||||
pub fn take(&mut self) {
|
pub fn take(&mut self) {
|
||||||
self.funded.take();
|
self.funded.take();
|
||||||
self.empty.take();
|
self.empty.take();
|
||||||
@@ -6,14 +6,14 @@ pub enum CohortContext {
|
|||||||
/// UTXO-based cohorts: uses "utxos_" prefix for Time/Amount filters
|
/// UTXO-based cohorts: uses "utxos_" prefix for Time/Amount filters
|
||||||
Utxo,
|
Utxo,
|
||||||
/// Address-based cohorts: uses "addrs_" prefix for Amount filters
|
/// Address-based cohorts: uses "addrs_" prefix for Amount filters
|
||||||
Address,
|
Addr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CohortContext {
|
impl CohortContext {
|
||||||
pub fn prefix(&self) -> &'static str {
|
pub fn prefix(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
CohortContext::Utxo => "utxos",
|
CohortContext::Utxo => "utxos",
|
||||||
CohortContext::Address => "addrs",
|
CohortContext::Addr => "addrs",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,10 +69,10 @@ impl Filter {
|
|||||||
|
|
||||||
/// Whether to compute extended metrics (realized cap ratios, profit/loss ratios, percentiles)
|
/// Whether to compute extended metrics (realized cap ratios, profit/loss ratios, percentiles)
|
||||||
/// For UTXO context: true only for age range cohorts (Range) and aggregate cohorts (All, Term)
|
/// For UTXO context: true only for age range cohorts (Range) and aggregate cohorts (All, Term)
|
||||||
/// For Address context: always false
|
/// For address context: always false
|
||||||
pub fn is_extended(&self, context: CohortContext) -> bool {
|
pub fn is_extended(&self, context: CohortContext) -> bool {
|
||||||
match context {
|
match context {
|
||||||
CohortContext::Address => false,
|
CohortContext::Addr => false,
|
||||||
CohortContext::Utxo => {
|
CohortContext::Utxo => {
|
||||||
matches!(
|
matches!(
|
||||||
self,
|
self,
|
||||||
@@ -90,12 +90,12 @@ impl Filter {
|
|||||||
|
|
||||||
/// Whether to compute adjusted metrics (adjusted SOPR, adjusted value created/destroyed)
|
/// Whether to compute adjusted metrics (adjusted SOPR, adjusted value created/destroyed)
|
||||||
/// For UTXO context: true for All, STH, and under_age (LowerThan)
|
/// For UTXO context: true for All, STH, and under_age (LowerThan)
|
||||||
/// For Address context: always false
|
/// For address context: always false
|
||||||
/// Note: LTH doesn't need adjusted (everything >= 5 months is already > 1 hour)
|
/// Note: LTH doesn't need adjusted (everything >= 5 months is already > 1 hour)
|
||||||
/// Note: age ranges don't need adjusted (0-1h data lives in its own cohort)
|
/// Note: age ranges don't need adjusted (0-1h data lives in its own cohort)
|
||||||
pub fn compute_adjusted(&self, context: CohortContext) -> bool {
|
pub fn compute_adjusted(&self, context: CohortContext) -> bool {
|
||||||
match context {
|
match context {
|
||||||
CohortContext::Address => false,
|
CohortContext::Addr => false,
|
||||||
CohortContext::Utxo => matches!(
|
CohortContext::Utxo => matches!(
|
||||||
self,
|
self,
|
||||||
Filter::All | Filter::Term(Term::Sth) | Filter::Time(TimeFilter::LowerThan(_))
|
Filter::All | Filter::Term(Term::Sth) | Filter::Time(TimeFilter::LowerThan(_))
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#![doc = include_str!("../README.md")]
|
#![doc = include_str!("../README.md")]
|
||||||
|
|
||||||
mod address;
|
mod addr;
|
||||||
mod amount_filter;
|
mod amount_filter;
|
||||||
mod age_range;
|
mod age_range;
|
||||||
mod amount_range;
|
mod amount_range;
|
||||||
mod by_address_type;
|
mod by_addr_type;
|
||||||
mod by_any_address;
|
mod by_any_addr;
|
||||||
mod by_epoch;
|
mod by_epoch;
|
||||||
mod by_term;
|
mod by_term;
|
||||||
mod by_type;
|
mod by_type;
|
||||||
@@ -29,12 +29,12 @@ mod utxo;
|
|||||||
|
|
||||||
pub use brk_types::{Age, Term};
|
pub use brk_types::{Age, Term};
|
||||||
|
|
||||||
pub use address::*;
|
pub use addr::*;
|
||||||
pub use amount_filter::*;
|
pub use amount_filter::*;
|
||||||
pub use age_range::*;
|
pub use age_range::*;
|
||||||
pub use amount_range::*;
|
pub use amount_range::*;
|
||||||
pub use by_address_type::*;
|
pub use by_addr_type::*;
|
||||||
pub use by_any_address::*;
|
pub use by_any_addr::*;
|
||||||
pub use by_epoch::*;
|
pub use by_epoch::*;
|
||||||
pub use by_term::*;
|
pub use by_term::*;
|
||||||
pub use by_type::*;
|
pub use by_type::*;
|
||||||
|
|||||||
@@ -14,23 +14,23 @@ pub fn main() -> Result<()> {
|
|||||||
|
|
||||||
let computer = Computer::forced_import(&outputs_dir, &indexer)?;
|
let computer = Computer::forced_import(&outputs_dir, &indexer)?;
|
||||||
|
|
||||||
// Test empty_address_data (underlying BytesVec) - direct access
|
// Test empty_addr_data (underlying BytesVec) - direct access
|
||||||
let empty_data = &computer.distribution.addresses_data.empty;
|
let empty_data = &computer.distribution.addrs_data.empty;
|
||||||
println!("empty_address_data (BytesVec) len: {}", empty_data.len());
|
println!("empty_addr_data (BytesVec) len: {}", empty_data.len());
|
||||||
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
empty_data.write_json(Some(empty_data.len() - 1), Some(empty_data.len()), &mut buf)?;
|
empty_data.write_json(Some(empty_data.len() - 1), Some(empty_data.len()), &mut buf)?;
|
||||||
println!(
|
println!(
|
||||||
"empty_address_data last item JSON: {}",
|
"empty_addr_data last item JSON: {}",
|
||||||
String::from_utf8_lossy(&buf)
|
String::from_utf8_lossy(&buf)
|
||||||
);
|
);
|
||||||
println!("Time for BytesVec write_json: {:?}", start.elapsed());
|
println!("Time for BytesVec write_json: {:?}", start.elapsed());
|
||||||
|
|
||||||
// Test empty_address_index (LazyVecFrom1 wrapper) - computed access
|
// Test empty_addr_index (LazyVecFrom1 wrapper) - computed access
|
||||||
let empty_index = &computer.distribution.addresses.empty_index;
|
let empty_index = &computer.distribution.addrs.empty_index;
|
||||||
println!(
|
println!(
|
||||||
"\nempty_address_index (LazyVecFrom1) len: {}",
|
"\nempty_addr_index (LazyVecFrom1) len: {}",
|
||||||
empty_index.len()
|
empty_index.len()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -42,14 +42,14 @@ pub fn main() -> Result<()> {
|
|||||||
&mut buf,
|
&mut buf,
|
||||||
)?;
|
)?;
|
||||||
println!(
|
println!(
|
||||||
"empty_address_index last item JSON: {}",
|
"empty_addr_index last item JSON: {}",
|
||||||
String::from_utf8_lossy(&buf)
|
String::from_utf8_lossy(&buf)
|
||||||
);
|
);
|
||||||
println!("Time for LazyVecFrom1 write_json: {:?}", start.elapsed());
|
println!("Time for LazyVecFrom1 write_json: {:?}", start.elapsed());
|
||||||
|
|
||||||
// Compare with funded versions
|
// Compare with funded versions
|
||||||
let funded_data = &computer.distribution.addresses_data.funded;
|
let funded_data = &computer.distribution.addrs_data.funded;
|
||||||
println!("\nfunded_address_data (BytesVec) len: {}", funded_data.len());
|
println!("\nfunded_addr_data (BytesVec) len: {}", funded_data.len());
|
||||||
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
@@ -59,7 +59,7 @@ pub fn main() -> Result<()> {
|
|||||||
&mut buf,
|
&mut buf,
|
||||||
)?;
|
)?;
|
||||||
println!(
|
println!(
|
||||||
"funded_address_data last item JSON: {}",
|
"funded_addr_data last item JSON: {}",
|
||||||
String::from_utf8_lossy(&buf)
|
String::from_utf8_lossy(&buf)
|
||||||
);
|
);
|
||||||
println!("Time for BytesVec write_json: {:?}", start.elapsed());
|
println!("Time for BytesVec write_json: {:?}", start.elapsed());
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
//! | `reactivated` | Addresses that were empty and now have funds |
|
//! | `reactivated` | Addresses that were empty and now have funds |
|
||||||
//! | `both` | Addresses that both sent AND received same block |
|
//! | `both` | Addresses that both sent AND received same block |
|
||||||
|
|
||||||
use brk_cohort::ByAddressType;
|
use brk_cohort::ByAddrType;
|
||||||
use brk_error::Result;
|
use brk_error::Result;
|
||||||
use brk_traversable::Traversable;
|
use brk_traversable::Traversable;
|
||||||
use brk_types::{Height, StoredU32, Version};
|
use brk_types::{Height, StoredU32, Version};
|
||||||
@@ -41,9 +41,9 @@ impl BlockActivityCounts {
|
|||||||
|
|
||||||
/// Per-address-type activity counts - aggregated during block processing.
|
/// Per-address-type activity counts - aggregated during block processing.
|
||||||
#[derive(Debug, Default, Deref, DerefMut)]
|
#[derive(Debug, Default, Deref, DerefMut)]
|
||||||
pub struct AddressTypeToActivityCounts(pub ByAddressType<BlockActivityCounts>);
|
pub struct AddrTypeToActivityCounts(pub ByAddrType<BlockActivityCounts>);
|
||||||
|
|
||||||
impl AddressTypeToActivityCounts {
|
impl AddrTypeToActivityCounts {
|
||||||
/// Reset all per-type counts.
|
/// Reset all per-type counts.
|
||||||
pub(crate) fn reset(&mut self) {
|
pub(crate) fn reset(&mut self) {
|
||||||
self.0.values_mut().for_each(|v| v.reset());
|
self.0.values_mut().for_each(|v| v.reset());
|
||||||
@@ -163,16 +163,16 @@ impl ActivityCountVecs {
|
|||||||
|
|
||||||
/// Per-address-type activity count vecs.
|
/// Per-address-type activity count vecs.
|
||||||
#[derive(Deref, DerefMut, Traversable)]
|
#[derive(Deref, DerefMut, Traversable)]
|
||||||
pub struct AddressTypeToActivityCountVecs<M: StorageMode = Rw>(ByAddressType<ActivityCountVecs<M>>);
|
pub struct AddrTypeToActivityCountVecs<M: StorageMode = Rw>(ByAddrType<ActivityCountVecs<M>>);
|
||||||
|
|
||||||
impl From<ByAddressType<ActivityCountVecs>> for AddressTypeToActivityCountVecs {
|
impl From<ByAddrType<ActivityCountVecs>> for AddrTypeToActivityCountVecs {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: ByAddressType<ActivityCountVecs>) -> Self {
|
fn from(value: ByAddrType<ActivityCountVecs>) -> Self {
|
||||||
Self(value)
|
Self(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddressTypeToActivityCountVecs {
|
impl AddrTypeToActivityCountVecs {
|
||||||
pub(crate) fn forced_import(
|
pub(crate) fn forced_import(
|
||||||
db: &Database,
|
db: &Database,
|
||||||
name: &str,
|
name: &str,
|
||||||
@@ -181,7 +181,7 @@ impl AddressTypeToActivityCountVecs {
|
|||||||
cached_starts: &CachedWindowStarts,
|
cached_starts: &CachedWindowStarts,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
Ok(Self::from(
|
Ok(Self::from(
|
||||||
ByAddressType::<ActivityCountVecs>::new_with_name(|type_name| {
|
ByAddrType::<ActivityCountVecs>::new_with_name(|type_name| {
|
||||||
ActivityCountVecs::forced_import(
|
ActivityCountVecs::forced_import(
|
||||||
db,
|
db,
|
||||||
&format!("{type_name}_{name}"),
|
&format!("{type_name}_{name}"),
|
||||||
@@ -233,7 +233,7 @@ impl AddressTypeToActivityCountVecs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn push_height(&mut self, counts: &AddressTypeToActivityCounts) {
|
pub(crate) fn push_height(&mut self, counts: &AddrTypeToActivityCounts) {
|
||||||
for (vecs, c) in self.0.values_mut().zip(counts.0.values()) {
|
for (vecs, c) in self.0.values_mut().zip(counts.0.values()) {
|
||||||
vecs.push_height(c);
|
vecs.push_height(c);
|
||||||
}
|
}
|
||||||
@@ -242,13 +242,13 @@ impl AddressTypeToActivityCountVecs {
|
|||||||
|
|
||||||
/// Storage for activity metrics (global + per type).
|
/// Storage for activity metrics (global + per type).
|
||||||
#[derive(Traversable)]
|
#[derive(Traversable)]
|
||||||
pub struct AddressActivityVecs<M: StorageMode = Rw> {
|
pub struct AddrActivityVecs<M: StorageMode = Rw> {
|
||||||
pub all: ActivityCountVecs<M>,
|
pub all: ActivityCountVecs<M>,
|
||||||
#[traversable(flatten)]
|
#[traversable(flatten)]
|
||||||
pub by_address_type: AddressTypeToActivityCountVecs<M>,
|
pub by_addr_type: AddrTypeToActivityCountVecs<M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddressActivityVecs {
|
impl AddrActivityVecs {
|
||||||
pub(crate) fn forced_import(
|
pub(crate) fn forced_import(
|
||||||
db: &Database,
|
db: &Database,
|
||||||
name: &str,
|
name: &str,
|
||||||
@@ -258,7 +258,7 @@ impl AddressActivityVecs {
|
|||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
all: ActivityCountVecs::forced_import(db, name, version, indexes, cached_starts)?,
|
all: ActivityCountVecs::forced_import(db, name, version, indexes, cached_starts)?,
|
||||||
by_address_type: AddressTypeToActivityCountVecs::forced_import(
|
by_addr_type: AddrTypeToActivityCountVecs::forced_import(
|
||||||
db, name, version, indexes, cached_starts,
|
db, name, version, indexes, cached_starts,
|
||||||
)?,
|
)?,
|
||||||
})
|
})
|
||||||
@@ -267,7 +267,7 @@ impl AddressActivityVecs {
|
|||||||
pub(crate) fn min_stateful_len(&self) -> usize {
|
pub(crate) fn min_stateful_len(&self) -> usize {
|
||||||
self.all
|
self.all
|
||||||
.min_stateful_len()
|
.min_stateful_len()
|
||||||
.min(self.by_address_type.min_stateful_len())
|
.min(self.by_addr_type.min_stateful_len())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn par_iter_height_mut(
|
pub(crate) fn par_iter_height_mut(
|
||||||
@@ -275,12 +275,12 @@ impl AddressActivityVecs {
|
|||||||
) -> impl ParallelIterator<Item = &mut dyn AnyStoredVec> {
|
) -> impl ParallelIterator<Item = &mut dyn AnyStoredVec> {
|
||||||
self.all
|
self.all
|
||||||
.par_iter_height_mut()
|
.par_iter_height_mut()
|
||||||
.chain(self.by_address_type.par_iter_height_mut())
|
.chain(self.by_addr_type.par_iter_height_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn reset_height(&mut self) -> Result<()> {
|
pub(crate) fn reset_height(&mut self) -> Result<()> {
|
||||||
self.all.reset_height()?;
|
self.all.reset_height()?;
|
||||||
self.by_address_type.reset_height()?;
|
self.by_addr_type.reset_height()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,14 +290,14 @@ impl AddressActivityVecs {
|
|||||||
exit: &Exit,
|
exit: &Exit,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
self.all.compute_rest(max_from, exit)?;
|
self.all.compute_rest(max_from, exit)?;
|
||||||
self.by_address_type.compute_rest(max_from, exit)?;
|
self.by_addr_type.compute_rest(max_from, exit)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn push_height(&mut self, counts: &AddressTypeToActivityCounts) {
|
pub(crate) fn push_height(&mut self, counts: &AddrTypeToActivityCounts) {
|
||||||
let totals = counts.totals();
|
let totals = counts.totals();
|
||||||
self.all.push_height(&totals);
|
self.all.push_height(&totals);
|
||||||
self.by_address_type.push_height(counts);
|
self.by_addr_type.push_height(counts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use brk_cohort::ByAddressType;
|
use brk_cohort::ByAddrType;
|
||||||
use brk_error::Result;
|
use brk_error::Result;
|
||||||
use brk_traversable::Traversable;
|
use brk_traversable::Traversable;
|
||||||
use brk_types::{Height, Indexes, StoredU64, Version};
|
use brk_types::{Height, Indexes, StoredU64, Version};
|
||||||
@@ -12,11 +12,11 @@ use vecdb::{
|
|||||||
use crate::{indexes, internal::PerBlock};
|
use crate::{indexes, internal::PerBlock};
|
||||||
|
|
||||||
#[derive(Deref, DerefMut, Traversable)]
|
#[derive(Deref, DerefMut, Traversable)]
|
||||||
pub struct AddressCountVecs<M: StorageMode = Rw>(
|
pub struct AddrCountVecs<M: StorageMode = Rw>(
|
||||||
#[traversable(flatten)] pub PerBlock<StoredU64, M>,
|
#[traversable(flatten)] pub PerBlock<StoredU64, M>,
|
||||||
);
|
);
|
||||||
|
|
||||||
impl AddressCountVecs {
|
impl AddrCountVecs {
|
||||||
pub(crate) fn forced_import(
|
pub(crate) fn forced_import(
|
||||||
db: &Database,
|
db: &Database,
|
||||||
name: &str,
|
name: &str,
|
||||||
@@ -31,20 +31,20 @@ impl AddressCountVecs {
|
|||||||
|
|
||||||
/// Address count per address type (runtime state).
|
/// Address count per address type (runtime state).
|
||||||
#[derive(Debug, Default, Deref, DerefMut)]
|
#[derive(Debug, Default, Deref, DerefMut)]
|
||||||
pub struct AddressTypeToAddressCount(ByAddressType<u64>);
|
pub struct AddrTypeToAddrCount(ByAddrType<u64>);
|
||||||
|
|
||||||
impl AddressTypeToAddressCount {
|
impl AddrTypeToAddrCount {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn sum(&self) -> u64 {
|
pub(crate) fn sum(&self) -> u64 {
|
||||||
self.0.values().sum()
|
self.0.values().sum()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<(&AddressTypeToAddressCountVecs, Height)> for AddressTypeToAddressCount {
|
impl From<(&AddrTypeToAddrCountVecs, Height)> for AddrTypeToAddrCount {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from((groups, starting_height): (&AddressTypeToAddressCountVecs, Height)) -> Self {
|
fn from((groups, starting_height): (&AddrTypeToAddrCountVecs, Height)) -> Self {
|
||||||
if let Some(prev_height) = starting_height.decremented() {
|
if let Some(prev_height) = starting_height.decremented() {
|
||||||
Self(ByAddressType {
|
Self(ByAddrType {
|
||||||
p2pk65: groups
|
p2pk65: groups
|
||||||
.p2pk65
|
.p2pk65
|
||||||
.height
|
.height
|
||||||
@@ -102,25 +102,25 @@ impl From<(&AddressTypeToAddressCountVecs, Height)> for AddressTypeToAddressCoun
|
|||||||
|
|
||||||
/// Address count per address type, with height + derived indexes.
|
/// Address count per address type, with height + derived indexes.
|
||||||
#[derive(Deref, DerefMut, Traversable)]
|
#[derive(Deref, DerefMut, Traversable)]
|
||||||
pub struct AddressTypeToAddressCountVecs<M: StorageMode = Rw>(ByAddressType<AddressCountVecs<M>>);
|
pub struct AddrTypeToAddrCountVecs<M: StorageMode = Rw>(ByAddrType<AddrCountVecs<M>>);
|
||||||
|
|
||||||
impl From<ByAddressType<AddressCountVecs>> for AddressTypeToAddressCountVecs {
|
impl From<ByAddrType<AddrCountVecs>> for AddrTypeToAddrCountVecs {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: ByAddressType<AddressCountVecs>) -> Self {
|
fn from(value: ByAddrType<AddrCountVecs>) -> Self {
|
||||||
Self(value)
|
Self(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddressTypeToAddressCountVecs {
|
impl AddrTypeToAddrCountVecs {
|
||||||
pub(crate) fn forced_import(
|
pub(crate) fn forced_import(
|
||||||
db: &Database,
|
db: &Database,
|
||||||
name: &str,
|
name: &str,
|
||||||
version: Version,
|
version: Version,
|
||||||
indexes: &indexes::Vecs,
|
indexes: &indexes::Vecs,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
Ok(Self::from(ByAddressType::<AddressCountVecs>::new_with_name(
|
Ok(Self::from(ByAddrType::<AddrCountVecs>::new_with_name(
|
||||||
|type_name| {
|
|type_name| {
|
||||||
AddressCountVecs::forced_import(db, &format!("{type_name}_{name}"), version, indexes)
|
AddrCountVecs::forced_import(db, &format!("{type_name}_{name}"), version, indexes)
|
||||||
},
|
},
|
||||||
)?))
|
)?))
|
||||||
}
|
}
|
||||||
@@ -138,8 +138,8 @@ impl AddressTypeToAddressCountVecs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn push_height(&mut self, address_counts: &AddressTypeToAddressCount) {
|
pub(crate) fn push_height(&mut self, addr_counts: &AddrTypeToAddrCount) {
|
||||||
for (vecs, &count) in self.0.values_mut().zip(address_counts.values()) {
|
for (vecs, &count) in self.0.values_mut().zip(addr_counts.values()) {
|
||||||
vecs.height.push(count.into());
|
vecs.height.push(count.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -157,13 +157,13 @@ impl AddressTypeToAddressCountVecs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Traversable)]
|
#[derive(Traversable)]
|
||||||
pub struct AddressCountsVecs<M: StorageMode = Rw> {
|
pub struct AddrCountsVecs<M: StorageMode = Rw> {
|
||||||
pub all: AddressCountVecs<M>,
|
pub all: AddrCountVecs<M>,
|
||||||
#[traversable(flatten)]
|
#[traversable(flatten)]
|
||||||
pub by_address_type: AddressTypeToAddressCountVecs<M>,
|
pub by_addr_type: AddrTypeToAddrCountVecs<M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddressCountsVecs {
|
impl AddrCountsVecs {
|
||||||
pub(crate) fn forced_import(
|
pub(crate) fn forced_import(
|
||||||
db: &Database,
|
db: &Database,
|
||||||
name: &str,
|
name: &str,
|
||||||
@@ -171,32 +171,32 @@ impl AddressCountsVecs {
|
|||||||
indexes: &indexes::Vecs,
|
indexes: &indexes::Vecs,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
all: AddressCountVecs::forced_import(db, name, version, indexes)?,
|
all: AddrCountVecs::forced_import(db, name, version, indexes)?,
|
||||||
by_address_type: AddressTypeToAddressCountVecs::forced_import(db, name, version, indexes)?,
|
by_addr_type: AddrTypeToAddrCountVecs::forced_import(db, name, version, indexes)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn min_stateful_len(&self) -> usize {
|
pub(crate) fn min_stateful_len(&self) -> usize {
|
||||||
self.all.height.len().min(self.by_address_type.min_stateful_len())
|
self.all.height.len().min(self.by_addr_type.min_stateful_len())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn par_iter_height_mut(
|
pub(crate) fn par_iter_height_mut(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> impl ParallelIterator<Item = &mut dyn AnyStoredVec> {
|
) -> impl ParallelIterator<Item = &mut dyn AnyStoredVec> {
|
||||||
rayon::iter::once(&mut self.all.height as &mut dyn AnyStoredVec)
|
rayon::iter::once(&mut self.all.height as &mut dyn AnyStoredVec)
|
||||||
.chain(self.by_address_type.par_iter_height_mut())
|
.chain(self.by_addr_type.par_iter_height_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn reset_height(&mut self) -> Result<()> {
|
pub(crate) fn reset_height(&mut self) -> Result<()> {
|
||||||
self.all.height.reset()?;
|
self.all.height.reset()?;
|
||||||
self.by_address_type.reset_height()?;
|
self.by_addr_type.reset_height()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn push_height(&mut self, total: u64, address_counts: &AddressTypeToAddressCount) {
|
pub(crate) fn push_height(&mut self, total: u64, addr_counts: &AddrTypeToAddrCount) {
|
||||||
self.all.height.push(total.into());
|
self.all.height.push(total.into());
|
||||||
self.by_address_type.push_height(address_counts);
|
self.by_addr_type.push_height(addr_counts);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn compute_rest(
|
pub(crate) fn compute_rest(
|
||||||
@@ -204,7 +204,7 @@ impl AddressCountsVecs {
|
|||||||
starting_indexes: &Indexes,
|
starting_indexes: &Indexes,
|
||||||
exit: &Exit,
|
exit: &Exit,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let sources = self.by_address_type.by_height();
|
let sources = self.by_addr_type.by_height();
|
||||||
self.all
|
self.all
|
||||||
.height
|
.height
|
||||||
.compute_sum_of_others(starting_indexes.height, &sources, exit)?;
|
.compute_sum_of_others(starting_indexes.height, &sources, exit)?;
|
||||||
@@ -1,19 +1,19 @@
|
|||||||
use brk_error::Result;
|
use brk_error::Result;
|
||||||
use brk_traversable::Traversable;
|
use brk_traversable::Traversable;
|
||||||
use brk_types::{
|
use brk_types::{
|
||||||
EmptyAddressData, EmptyAddressIndex, FundedAddressData, FundedAddressIndex, Height,
|
EmptyAddrData, EmptyAddrIndex, FundedAddrData, FundedAddrIndex, Height,
|
||||||
};
|
};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use vecdb::{AnyStoredVec, BytesVec, Rw, Stamp, StorageMode, WritableVec};
|
use vecdb::{AnyStoredVec, BytesVec, Rw, Stamp, StorageMode, WritableVec};
|
||||||
|
|
||||||
/// Storage for both funded and empty address data.
|
/// Storage for both funded and empty address data.
|
||||||
#[derive(Traversable)]
|
#[derive(Traversable)]
|
||||||
pub struct AddressesDataVecs<M: StorageMode = Rw> {
|
pub struct AddrsDataVecs<M: StorageMode = Rw> {
|
||||||
pub funded: M::Stored<BytesVec<FundedAddressIndex, FundedAddressData>>,
|
pub funded: M::Stored<BytesVec<FundedAddrIndex, FundedAddrData>>,
|
||||||
pub empty: M::Stored<BytesVec<EmptyAddressIndex, EmptyAddressData>>,
|
pub empty: M::Stored<BytesVec<EmptyAddrIndex, EmptyAddrData>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddressesDataVecs {
|
impl AddrsDataVecs {
|
||||||
/// Get minimum stamped height across funded and empty data.
|
/// Get minimum stamped height across funded and empty data.
|
||||||
pub(crate) fn min_stamped_len(&self) -> Height {
|
pub(crate) fn min_stamped_len(&self) -> Height {
|
||||||
Height::from(self.funded.stamp())
|
Height::from(self.funded.stamp())
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use brk_cohort::ByAddressType;
|
use brk_cohort::ByAddrType;
|
||||||
use brk_traversable::Traversable;
|
use brk_traversable::Traversable;
|
||||||
use brk_types::{BasisPointsSigned32, StoredI64, StoredU64, Version};
|
use brk_types::{BasisPointsSigned32, StoredI64, StoredU64, Version};
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@ use crate::{
|
|||||||
internal::{CachedWindowStarts, LazyRollingDeltasFromHeight},
|
internal::{CachedWindowStarts, LazyRollingDeltasFromHeight},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::AddressCountsVecs;
|
use super::AddrCountsVecs;
|
||||||
|
|
||||||
type AddrDelta = LazyRollingDeltasFromHeight<StoredU64, StoredI64, BasisPointsSigned32>;
|
type AddrDelta = LazyRollingDeltasFromHeight<StoredU64, StoredI64, BasisPointsSigned32>;
|
||||||
|
|
||||||
@@ -15,29 +15,29 @@ type AddrDelta = LazyRollingDeltasFromHeight<StoredU64, StoredI64, BasisPointsSi
|
|||||||
pub struct DeltaVecs {
|
pub struct DeltaVecs {
|
||||||
pub all: AddrDelta,
|
pub all: AddrDelta,
|
||||||
#[traversable(flatten)]
|
#[traversable(flatten)]
|
||||||
pub by_address_type: ByAddressType<AddrDelta>,
|
pub by_addr_type: ByAddrType<AddrDelta>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeltaVecs {
|
impl DeltaVecs {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
version: Version,
|
version: Version,
|
||||||
address_count: &AddressCountsVecs,
|
addr_count: &AddrCountsVecs,
|
||||||
cached_starts: &CachedWindowStarts,
|
cached_starts: &CachedWindowStarts,
|
||||||
indexes: &indexes::Vecs,
|
indexes: &indexes::Vecs,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let version = version + Version::TWO;
|
let version = version + Version::TWO;
|
||||||
|
|
||||||
let all = LazyRollingDeltasFromHeight::new(
|
let all = LazyRollingDeltasFromHeight::new(
|
||||||
"address_count",
|
"addr_count",
|
||||||
version,
|
version,
|
||||||
&address_count.all.0.height,
|
&addr_count.all.0.height,
|
||||||
cached_starts,
|
cached_starts,
|
||||||
indexes,
|
indexes,
|
||||||
);
|
);
|
||||||
|
|
||||||
let by_address_type = address_count.by_address_type.map_with_name(|name, addr| {
|
let by_addr_type = addr_count.by_addr_type.map_with_name(|name, addr| {
|
||||||
LazyRollingDeltasFromHeight::new(
|
LazyRollingDeltasFromHeight::new(
|
||||||
&format!("{name}_address_count"),
|
&format!("{name}_addr_count"),
|
||||||
version,
|
version,
|
||||||
&addr.0.height,
|
&addr.0.height,
|
||||||
cached_starts,
|
cached_starts,
|
||||||
@@ -47,7 +47,7 @@ impl DeltaVecs {
|
|||||||
|
|
||||||
Self {
|
Self {
|
||||||
all,
|
all,
|
||||||
by_address_type,
|
by_addr_type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
use brk_cohort::ByAddressType;
|
use brk_cohort::ByAddrType;
|
||||||
use brk_error::{Error, Result};
|
use brk_error::{Error, Result};
|
||||||
use brk_traversable::Traversable;
|
use brk_traversable::Traversable;
|
||||||
use brk_types::{
|
use brk_types::{
|
||||||
AnyAddressIndex, Height, OutputType, P2AAddressIndex, P2PK33AddressIndex, P2PK65AddressIndex,
|
AnyAddrIndex, Height, OutputType, P2AAddrIndex, P2PK33AddrIndex, P2PK65AddrIndex,
|
||||||
P2PKHAddressIndex, P2SHAddressIndex, P2TRAddressIndex, P2WPKHAddressIndex, P2WSHAddressIndex,
|
P2PKHAddrIndex, P2SHAddrIndex, P2TRAddrIndex, P2WPKHAddrIndex, P2WSHAddrIndex,
|
||||||
TypeIndex, Version,
|
TypeIndex, Version,
|
||||||
};
|
};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
@@ -15,24 +15,24 @@ use vecdb::{
|
|||||||
Rw, Stamp, StorageMode, WritableVec,
|
Rw, Stamp, StorageMode, WritableVec,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::super::AddressTypeToTypeIndexMap;
|
use super::super::AddrTypeToTypeIndexMap;
|
||||||
|
|
||||||
const SAVED_STAMPED_CHANGES: u16 = 10;
|
const SAVED_STAMPED_CHANGES: u16 = 10;
|
||||||
|
|
||||||
/// Macro to define AnyAddressIndexesVecs and its methods.
|
/// Macro to define AnyAddrIndexesVecs and its methods.
|
||||||
macro_rules! define_any_address_indexes_vecs {
|
macro_rules! define_any_addr_indexes_vecs {
|
||||||
($(($field:ident, $variant:ident, $index:ty)),* $(,)?) => {
|
($(($field:ident, $variant:ident, $index:ty)),* $(,)?) => {
|
||||||
#[derive(Traversable)]
|
#[derive(Traversable)]
|
||||||
pub struct AnyAddressIndexesVecs<M: StorageMode = Rw> {
|
pub struct AnyAddrIndexesVecs<M: StorageMode = Rw> {
|
||||||
$(pub $field: M::Stored<BytesVec<$index, AnyAddressIndex>>,)*
|
$(pub $field: M::Stored<BytesVec<$index, AnyAddrIndex>>,)*
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AnyAddressIndexesVecs {
|
impl AnyAddrIndexesVecs {
|
||||||
/// Import from database.
|
/// Import from database.
|
||||||
pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
$($field: BytesVec::forced_import_with(
|
$($field: BytesVec::forced_import_with(
|
||||||
ImportOptions::new(db, "any_address_index", version)
|
ImportOptions::new(db, "any_addr_index", version)
|
||||||
.with_saved_stamped_changes(SAVED_STAMPED_CHANGES),
|
.with_saved_stamped_changes(SAVED_STAMPED_CHANGES),
|
||||||
)?,)*
|
)?,)*
|
||||||
})
|
})
|
||||||
@@ -59,10 +59,10 @@ macro_rules! define_any_address_indexes_vecs {
|
|||||||
|
|
||||||
/// Get address index for a given type and type_index.
|
/// Get address index for a given type and type_index.
|
||||||
/// Uses get_any_or_read_at to check updated layer (needed after rollback).
|
/// Uses get_any_or_read_at to check updated layer (needed after rollback).
|
||||||
pub(crate) fn get(&self, address_type: OutputType, type_index: TypeIndex, reader: &Reader) -> Result<AnyAddressIndex> {
|
pub(crate) fn get(&self, addr_type: OutputType, type_index: TypeIndex, reader: &Reader) -> Result<AnyAddrIndex> {
|
||||||
match address_type {
|
match addr_type {
|
||||||
$(OutputType::$variant => Ok(self.$field.get_any_or_read_at(type_index.into(), reader)?.unwrap()),)*
|
$(OutputType::$variant => Ok(self.$field.get_any_or_read_at(type_index.into(), reader)?.unwrap()),)*
|
||||||
_ => unreachable!("Invalid address type: {:?}", address_type),
|
_ => unreachable!("Invalid addr type: {:?}", addr_type),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,14 +72,14 @@ macro_rules! define_any_address_indexes_vecs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: StorageMode> AnyAddressIndexesVecs<M> {
|
impl<M: StorageMode> AnyAddrIndexesVecs<M> {
|
||||||
/// Get address index with single read (no caching).
|
/// Get address index with single read (no caching).
|
||||||
pub fn get_once(&self, address_type: OutputType, type_index: TypeIndex) -> Result<AnyAddressIndex> {
|
pub fn get_once(&self, addr_type: OutputType, type_index: TypeIndex) -> Result<AnyAddrIndex> {
|
||||||
match address_type {
|
match addr_type {
|
||||||
$(OutputType::$variant => self.$field
|
$(OutputType::$variant => self.$field
|
||||||
.collect_one(<$index>::from(usize::from(type_index)))
|
.collect_one(<$index>::from(usize::from(type_index)))
|
||||||
.ok_or_else(|| Error::UnsupportedType(address_type.to_string())),)*
|
.ok_or_else(|| Error::UnsupportedType(addr_type.to_string())),)*
|
||||||
_ => Err(Error::UnsupportedType(address_type.to_string())),
|
_ => Err(Error::UnsupportedType(addr_type.to_string())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,28 +87,28 @@ macro_rules! define_any_address_indexes_vecs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate the struct and methods
|
// Generate the struct and methods
|
||||||
define_any_address_indexes_vecs!(
|
define_any_addr_indexes_vecs!(
|
||||||
(p2a, P2A, P2AAddressIndex),
|
(p2a, P2A, P2AAddrIndex),
|
||||||
(p2pk33, P2PK33, P2PK33AddressIndex),
|
(p2pk33, P2PK33, P2PK33AddrIndex),
|
||||||
(p2pk65, P2PK65, P2PK65AddressIndex),
|
(p2pk65, P2PK65, P2PK65AddrIndex),
|
||||||
(p2pkh, P2PKH, P2PKHAddressIndex),
|
(p2pkh, P2PKH, P2PKHAddrIndex),
|
||||||
(p2sh, P2SH, P2SHAddressIndex),
|
(p2sh, P2SH, P2SHAddrIndex),
|
||||||
(p2tr, P2TR, P2TRAddressIndex),
|
(p2tr, P2TR, P2TRAddrIndex),
|
||||||
(p2wpkh, P2WPKH, P2WPKHAddressIndex),
|
(p2wpkh, P2WPKH, P2WPKHAddrIndex),
|
||||||
(p2wsh, P2WSH, P2WSHAddressIndex),
|
(p2wsh, P2WSH, P2WSHAddrIndex),
|
||||||
);
|
);
|
||||||
|
|
||||||
impl AnyAddressIndexesVecs {
|
impl AnyAddrIndexesVecs {
|
||||||
/// Process index updates in parallel by address type.
|
/// Process index updates in parallel by address type.
|
||||||
/// Accepts two maps (e.g. from empty and funded processing) and merges per-thread.
|
/// Accepts two maps (e.g. from empty and funded processing) and merges per-thread.
|
||||||
/// Updates existing entries and pushes new ones (sorted).
|
/// Updates existing entries and pushes new ones (sorted).
|
||||||
/// Returns (update_count, push_count).
|
/// Returns (update_count, push_count).
|
||||||
pub(crate) fn par_batch_update(
|
pub(crate) fn par_batch_update(
|
||||||
&mut self,
|
&mut self,
|
||||||
updates1: AddressTypeToTypeIndexMap<AnyAddressIndex>,
|
updates1: AddrTypeToTypeIndexMap<AnyAddrIndex>,
|
||||||
updates2: AddressTypeToTypeIndexMap<AnyAddressIndex>,
|
updates2: AddrTypeToTypeIndexMap<AnyAddrIndex>,
|
||||||
) -> Result<(usize, usize)> {
|
) -> Result<(usize, usize)> {
|
||||||
let ByAddressType {
|
let ByAddrType {
|
||||||
p2a: u1_p2a,
|
p2a: u1_p2a,
|
||||||
p2pk33: u1_p2pk33,
|
p2pk33: u1_p2pk33,
|
||||||
p2pk65: u1_p2pk65,
|
p2pk65: u1_p2pk65,
|
||||||
@@ -119,7 +119,7 @@ impl AnyAddressIndexesVecs {
|
|||||||
p2wsh: u1_p2wsh,
|
p2wsh: u1_p2wsh,
|
||||||
} = updates1.into_inner();
|
} = updates1.into_inner();
|
||||||
|
|
||||||
let ByAddressType {
|
let ByAddrType {
|
||||||
p2a: u2_p2a,
|
p2a: u2_p2a,
|
||||||
p2pk33: u2_p2pk33,
|
p2pk33: u2_p2pk33,
|
||||||
p2pk65: u2_p2pk65,
|
p2pk65: u2_p2pk65,
|
||||||
@@ -169,9 +169,9 @@ impl AnyAddressIndexesVecs {
|
|||||||
|
|
||||||
/// Process updates for a single address type's BytesVec, merging two maps.
|
/// Process updates for a single address type's BytesVec, merging two maps.
|
||||||
fn process_single_type_merged<I: vecdb::VecIndex>(
|
fn process_single_type_merged<I: vecdb::VecIndex>(
|
||||||
vec: &mut BytesVec<I, AnyAddressIndex>,
|
vec: &mut BytesVec<I, AnyAddrIndex>,
|
||||||
map1: FxHashMap<TypeIndex, AnyAddressIndex>,
|
map1: FxHashMap<TypeIndex, AnyAddrIndex>,
|
||||||
map2: FxHashMap<TypeIndex, AnyAddressIndex>,
|
map2: FxHashMap<TypeIndex, AnyAddrIndex>,
|
||||||
) -> Result<(usize, usize)> {
|
) -> Result<(usize, usize)> {
|
||||||
let current_len = vec.len();
|
let current_len = vec.len();
|
||||||
let mut pushes = Vec::with_capacity(map1.len() + map2.len());
|
let mut pushes = Vec::with_capacity(map1.len() + map2.len());
|
||||||
17
crates/brk_computer/src/distribution/addr/mod.rs
Normal file
17
crates/brk_computer/src/distribution/addr/mod.rs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
mod activity;
|
||||||
|
mod addr_count;
|
||||||
|
mod data;
|
||||||
|
mod delta;
|
||||||
|
mod indexes;
|
||||||
|
mod new_addr_count;
|
||||||
|
mod total_addr_count;
|
||||||
|
mod type_map;
|
||||||
|
|
||||||
|
pub use activity::{AddrActivityVecs, AddrTypeToActivityCounts};
|
||||||
|
pub use addr_count::{AddrCountsVecs, AddrTypeToAddrCount};
|
||||||
|
pub use data::AddrsDataVecs;
|
||||||
|
pub use delta::DeltaVecs;
|
||||||
|
pub use indexes::AnyAddrIndexesVecs;
|
||||||
|
pub use new_addr_count::NewAddrCountVecs;
|
||||||
|
pub use total_addr_count::TotalAddrCountVecs;
|
||||||
|
pub use type_map::{AddrTypeToTypeIndexMap, AddrTypeToVec, HeightToAddrTypeToVec};
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use brk_cohort::ByAddressType;
|
use brk_cohort::ByAddrType;
|
||||||
use brk_error::Result;
|
use brk_error::Result;
|
||||||
use brk_traversable::Traversable;
|
use brk_traversable::Traversable;
|
||||||
use brk_types::{Height, StoredU64, Version};
|
use brk_types::{Height, StoredU64, Version};
|
||||||
@@ -9,17 +9,17 @@ use crate::{
|
|||||||
internal::{CachedWindowStarts, PerBlockCumulativeWithSums},
|
internal::{CachedWindowStarts, PerBlockCumulativeWithSums},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::TotalAddressCountVecs;
|
use super::TotalAddrCountVecs;
|
||||||
|
|
||||||
/// New address count per block (global + per-type)
|
/// New address count per block (global + per-type)
|
||||||
#[derive(Traversable)]
|
#[derive(Traversable)]
|
||||||
pub struct NewAddressCountVecs<M: StorageMode = Rw> {
|
pub struct NewAddrCountVecs<M: StorageMode = Rw> {
|
||||||
pub all: PerBlockCumulativeWithSums<StoredU64, StoredU64, M>,
|
pub all: PerBlockCumulativeWithSums<StoredU64, StoredU64, M>,
|
||||||
#[traversable(flatten)]
|
#[traversable(flatten)]
|
||||||
pub by_address_type: ByAddressType<PerBlockCumulativeWithSums<StoredU64, StoredU64, M>>,
|
pub by_addr_type: ByAddrType<PerBlockCumulativeWithSums<StoredU64, StoredU64, M>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NewAddressCountVecs {
|
impl NewAddrCountVecs {
|
||||||
pub(crate) fn forced_import(
|
pub(crate) fn forced_import(
|
||||||
db: &Database,
|
db: &Database,
|
||||||
version: Version,
|
version: Version,
|
||||||
@@ -28,16 +28,16 @@ impl NewAddressCountVecs {
|
|||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let all = PerBlockCumulativeWithSums::forced_import(
|
let all = PerBlockCumulativeWithSums::forced_import(
|
||||||
db,
|
db,
|
||||||
"new_address_count",
|
"new_addr_count",
|
||||||
version,
|
version,
|
||||||
indexes,
|
indexes,
|
||||||
cached_starts,
|
cached_starts,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let by_address_type = ByAddressType::new_with_name(|name| {
|
let by_addr_type = ByAddrType::new_with_name(|name| {
|
||||||
PerBlockCumulativeWithSums::forced_import(
|
PerBlockCumulativeWithSums::forced_import(
|
||||||
db,
|
db,
|
||||||
&format!("{name}_new_address_count"),
|
&format!("{name}_new_addr_count"),
|
||||||
version,
|
version,
|
||||||
indexes,
|
indexes,
|
||||||
cached_starts,
|
cached_starts,
|
||||||
@@ -46,24 +46,24 @@ impl NewAddressCountVecs {
|
|||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
all,
|
all,
|
||||||
by_address_type,
|
by_addr_type,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn compute(
|
pub(crate) fn compute(
|
||||||
&mut self,
|
&mut self,
|
||||||
max_from: Height,
|
max_from: Height,
|
||||||
total_address_count: &TotalAddressCountVecs,
|
total_addr_count: &TotalAddrCountVecs,
|
||||||
exit: &Exit,
|
exit: &Exit,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
self.all.compute(max_from, exit, |height_vec| {
|
self.all.compute(max_from, exit, |height_vec| {
|
||||||
Ok(height_vec.compute_change(max_from, &total_address_count.all.height, 1, exit)?)
|
Ok(height_vec.compute_change(max_from, &total_addr_count.all.height, 1, exit)?)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
for ((_, new), (_, total)) in self
|
for ((_, new), (_, total)) in self
|
||||||
.by_address_type
|
.by_addr_type
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.zip(total_address_count.by_address_type.iter())
|
.zip(total_addr_count.by_addr_type.iter())
|
||||||
{
|
{
|
||||||
new.compute(max_from, exit, |height_vec| {
|
new.compute(max_from, exit, |height_vec| {
|
||||||
Ok(height_vec.compute_change(max_from, &total.height, 1, exit)?)
|
Ok(height_vec.compute_change(max_from, &total.height, 1, exit)?)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use brk_cohort::ByAddressType;
|
use brk_cohort::ByAddrType;
|
||||||
use brk_error::Result;
|
use brk_error::Result;
|
||||||
use brk_traversable::Traversable;
|
use brk_traversable::Traversable;
|
||||||
use brk_types::{Height, StoredU64, Version};
|
use brk_types::{Height, StoredU64, Version};
|
||||||
@@ -6,29 +6,29 @@ use vecdb::{Database, Exit, Rw, StorageMode};
|
|||||||
|
|
||||||
use crate::{indexes, internal::PerBlock};
|
use crate::{indexes, internal::PerBlock};
|
||||||
|
|
||||||
use super::AddressCountsVecs;
|
use super::AddrCountsVecs;
|
||||||
|
|
||||||
/// Total address count (global + per-type) with all derived indexes
|
/// Total address count (global + per-type) with all derived indexes
|
||||||
#[derive(Traversable)]
|
#[derive(Traversable)]
|
||||||
pub struct TotalAddressCountVecs<M: StorageMode = Rw> {
|
pub struct TotalAddrCountVecs<M: StorageMode = Rw> {
|
||||||
pub all: PerBlock<StoredU64, M>,
|
pub all: PerBlock<StoredU64, M>,
|
||||||
#[traversable(flatten)]
|
#[traversable(flatten)]
|
||||||
pub by_address_type: ByAddressType<PerBlock<StoredU64, M>>,
|
pub by_addr_type: ByAddrType<PerBlock<StoredU64, M>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TotalAddressCountVecs {
|
impl TotalAddrCountVecs {
|
||||||
pub(crate) fn forced_import(
|
pub(crate) fn forced_import(
|
||||||
db: &Database,
|
db: &Database,
|
||||||
version: Version,
|
version: Version,
|
||||||
indexes: &indexes::Vecs,
|
indexes: &indexes::Vecs,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let all = PerBlock::forced_import(db, "total_address_count", version, indexes)?;
|
let all = PerBlock::forced_import(db, "total_addr_count", version, indexes)?;
|
||||||
|
|
||||||
let by_address_type: ByAddressType<PerBlock<StoredU64>> =
|
let by_addr_type: ByAddrType<PerBlock<StoredU64>> =
|
||||||
ByAddressType::new_with_name(|name| {
|
ByAddrType::new_with_name(|name| {
|
||||||
PerBlock::forced_import(
|
PerBlock::forced_import(
|
||||||
db,
|
db,
|
||||||
&format!("{name}_total_address_count"),
|
&format!("{name}_total_addr_count"),
|
||||||
version,
|
version,
|
||||||
indexes,
|
indexes,
|
||||||
)
|
)
|
||||||
@@ -36,30 +36,30 @@ impl TotalAddressCountVecs {
|
|||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
all,
|
all,
|
||||||
by_address_type,
|
by_addr_type,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Eagerly compute total = address_count + empty_address_count.
|
/// Eagerly compute total = addr_count + empty_addr_count.
|
||||||
pub(crate) fn compute(
|
pub(crate) fn compute(
|
||||||
&mut self,
|
&mut self,
|
||||||
max_from: Height,
|
max_from: Height,
|
||||||
address_count: &AddressCountsVecs,
|
addr_count: &AddrCountsVecs,
|
||||||
empty_address_count: &AddressCountsVecs,
|
empty_addr_count: &AddrCountsVecs,
|
||||||
exit: &Exit,
|
exit: &Exit,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
self.all.height.compute_add(
|
self.all.height.compute_add(
|
||||||
max_from,
|
max_from,
|
||||||
&address_count.all.height,
|
&addr_count.all.height,
|
||||||
&empty_address_count.all.height,
|
&empty_addr_count.all.height,
|
||||||
exit,
|
exit,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
for ((_, total), ((_, addr), (_, empty))) in self.by_address_type.iter_mut().zip(
|
for ((_, total), ((_, addr), (_, empty))) in self.by_addr_type.iter_mut().zip(
|
||||||
address_count
|
addr_count
|
||||||
.by_address_type
|
.by_addr_type
|
||||||
.iter()
|
.iter()
|
||||||
.zip(empty_address_count.by_address_type.iter()),
|
.zip(empty_addr_count.by_addr_type.iter()),
|
||||||
) {
|
) {
|
||||||
total
|
total
|
||||||
.height
|
.height
|
||||||
@@ -2,13 +2,13 @@ use brk_types::Height;
|
|||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use super::vec::AddressTypeToVec;
|
use super::vec::AddrTypeToVec;
|
||||||
|
|
||||||
/// Hashmap from Height to AddressTypeToVec.
|
/// Hashmap from Height to AddrTypeToVec.
|
||||||
#[derive(Debug, Default, Deref, DerefMut)]
|
#[derive(Debug, Default, Deref, DerefMut)]
|
||||||
pub struct HeightToAddressTypeToVec<T>(FxHashMap<Height, AddressTypeToVec<T>>);
|
pub struct HeightToAddrTypeToVec<T>(FxHashMap<Height, AddrTypeToVec<T>>);
|
||||||
|
|
||||||
impl<T> HeightToAddressTypeToVec<T> {
|
impl<T> HeightToAddrTypeToVec<T> {
|
||||||
/// Create with pre-allocated capacity for unique heights.
|
/// Create with pre-allocated capacity for unique heights.
|
||||||
pub(crate) fn with_capacity(capacity: usize) -> Self {
|
pub(crate) fn with_capacity(capacity: usize) -> Self {
|
||||||
Self(FxHashMap::with_capacity_and_hasher(
|
Self(FxHashMap::with_capacity_and_hasher(
|
||||||
@@ -18,9 +18,9 @@ impl<T> HeightToAddressTypeToVec<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> HeightToAddressTypeToVec<T> {
|
impl<T> HeightToAddrTypeToVec<T> {
|
||||||
/// Consume and iterate over (Height, AddressTypeToVec) pairs.
|
/// Consume and iterate over (Height, AddrTypeToVec) pairs.
|
||||||
pub(crate) fn into_iter(self) -> impl Iterator<Item = (Height, AddressTypeToVec<T>)> {
|
pub(crate) fn into_iter(self) -> impl Iterator<Item = (Height, AddrTypeToVec<T>)> {
|
||||||
self.0.into_iter()
|
self.0.into_iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::{collections::hash_map::Entry, mem};
|
use std::{collections::hash_map::Entry, mem};
|
||||||
|
|
||||||
use brk_cohort::ByAddressType;
|
use brk_cohort::ByAddrType;
|
||||||
use brk_types::{OutputType, TypeIndex};
|
use brk_types::{OutputType, TypeIndex};
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
@@ -8,11 +8,11 @@ use smallvec::{Array, SmallVec};
|
|||||||
|
|
||||||
/// A hashmap for each address type, keyed by TypeIndex.
|
/// A hashmap for each address type, keyed by TypeIndex.
|
||||||
#[derive(Debug, Deref, DerefMut)]
|
#[derive(Debug, Deref, DerefMut)]
|
||||||
pub struct AddressTypeToTypeIndexMap<T>(ByAddressType<FxHashMap<TypeIndex, T>>);
|
pub struct AddrTypeToTypeIndexMap<T>(ByAddrType<FxHashMap<TypeIndex, T>>);
|
||||||
|
|
||||||
impl<T> Default for AddressTypeToTypeIndexMap<T> {
|
impl<T> Default for AddrTypeToTypeIndexMap<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self(ByAddressType {
|
Self(ByAddrType {
|
||||||
p2a: FxHashMap::default(),
|
p2a: FxHashMap::default(),
|
||||||
p2pk33: FxHashMap::default(),
|
p2pk33: FxHashMap::default(),
|
||||||
p2pk65: FxHashMap::default(),
|
p2pk65: FxHashMap::default(),
|
||||||
@@ -25,10 +25,10 @@ impl<T> Default for AddressTypeToTypeIndexMap<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AddressTypeToTypeIndexMap<T> {
|
impl<T> AddrTypeToTypeIndexMap<T> {
|
||||||
/// Create with pre-allocated capacity per address type.
|
/// Create with pre-allocated capacity per address type.
|
||||||
pub(crate) fn with_capacity(capacity: usize) -> Self {
|
pub(crate) fn with_capacity(capacity: usize) -> Self {
|
||||||
Self(ByAddressType {
|
Self(ByAddrType {
|
||||||
p2a: FxHashMap::with_capacity_and_hasher(capacity, Default::default()),
|
p2a: FxHashMap::with_capacity_and_hasher(capacity, Default::default()),
|
||||||
p2pk33: FxHashMap::with_capacity_and_hasher(capacity, Default::default()),
|
p2pk33: FxHashMap::with_capacity_and_hasher(capacity, Default::default()),
|
||||||
p2pk65: FxHashMap::with_capacity_and_hasher(capacity, Default::default()),
|
p2pk65: FxHashMap::with_capacity_and_hasher(capacity, Default::default()),
|
||||||
@@ -62,11 +62,11 @@ impl<T> AddressTypeToTypeIndexMap<T> {
|
|||||||
/// Insert a value for a specific address type and type_index.
|
/// Insert a value for a specific address type and type_index.
|
||||||
pub(crate) fn insert_for_type(
|
pub(crate) fn insert_for_type(
|
||||||
&mut self,
|
&mut self,
|
||||||
address_type: OutputType,
|
addr_type: OutputType,
|
||||||
type_index: TypeIndex,
|
type_index: TypeIndex,
|
||||||
value: T,
|
value: T,
|
||||||
) {
|
) {
|
||||||
self.get_mut(address_type).unwrap().insert(type_index, value);
|
self.get_mut(addr_type).unwrap().insert(type_index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consume and iterate over entries by address type.
|
/// Consume and iterate over entries by address type.
|
||||||
@@ -75,8 +75,8 @@ impl<T> AddressTypeToTypeIndexMap<T> {
|
|||||||
self.0.into_iter()
|
self.0.into_iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consume and return the inner ByAddressType.
|
/// Consume and return the inner ByAddrType.
|
||||||
pub(crate) fn into_inner(self) -> ByAddressType<FxHashMap<TypeIndex, T>> {
|
pub(crate) fn into_inner(self) -> ByAddrType<FxHashMap<TypeIndex, T>> {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,14 +88,14 @@ impl<T> AddressTypeToTypeIndexMap<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AddressTypeToTypeIndexMap<SmallVec<T>>
|
impl<T> AddrTypeToTypeIndexMap<SmallVec<T>>
|
||||||
where
|
where
|
||||||
T: Array,
|
T: Array,
|
||||||
{
|
{
|
||||||
/// Merge two maps of SmallVec values, concatenating vectors.
|
/// Merge two maps of SmallVec values, concatenating vectors.
|
||||||
pub(crate) fn merge_vec(mut self, other: Self) -> Self {
|
pub(crate) fn merge_vec(mut self, other: Self) -> Self {
|
||||||
for (address_type, other_map) in other.0.into_iter() {
|
for (addr_type, other_map) in other.0.into_iter() {
|
||||||
let self_map = self.0.get_mut_unwrap(address_type);
|
let self_map = self.0.get_mut_unwrap(addr_type);
|
||||||
for (type_index, mut other_vec) in other_map {
|
for (type_index, mut other_vec) in other_map {
|
||||||
match self_map.entry(type_index) {
|
match self_map.entry(type_index) {
|
||||||
Entry::Occupied(mut entry) => {
|
Entry::Occupied(mut entry) => {
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
use brk_cohort::ByAddressType;
|
use brk_cohort::ByAddrType;
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
|
|
||||||
/// A vector for each address type.
|
/// A vector for each address type.
|
||||||
#[derive(Debug, Deref, DerefMut)]
|
#[derive(Debug, Deref, DerefMut)]
|
||||||
pub struct AddressTypeToVec<T>(ByAddressType<Vec<T>>);
|
pub struct AddrTypeToVec<T>(ByAddrType<Vec<T>>);
|
||||||
|
|
||||||
impl<T> Default for AddressTypeToVec<T> {
|
impl<T> Default for AddrTypeToVec<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self(ByAddressType {
|
Self(ByAddrType {
|
||||||
p2a: vec![],
|
p2a: vec![],
|
||||||
p2pk33: vec![],
|
p2pk33: vec![],
|
||||||
p2pk65: vec![],
|
p2pk65: vec![],
|
||||||
@@ -20,10 +20,10 @@ impl<T> Default for AddressTypeToVec<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AddressTypeToVec<T> {
|
impl<T> AddrTypeToVec<T> {
|
||||||
/// Create with pre-allocated capacity per address type.
|
/// Create with pre-allocated capacity per address type.
|
||||||
pub(crate) fn with_capacity(capacity: usize) -> Self {
|
pub(crate) fn with_capacity(capacity: usize) -> Self {
|
||||||
Self(ByAddressType {
|
Self(ByAddrType {
|
||||||
p2a: Vec::with_capacity(capacity),
|
p2a: Vec::with_capacity(capacity),
|
||||||
p2pk33: Vec::with_capacity(capacity),
|
p2pk33: Vec::with_capacity(capacity),
|
||||||
p2pk65: Vec::with_capacity(capacity),
|
p2pk65: Vec::with_capacity(capacity),
|
||||||
@@ -36,9 +36,9 @@ impl<T> AddressTypeToVec<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AddressTypeToVec<T> {
|
impl<T> AddrTypeToVec<T> {
|
||||||
/// Unwrap the inner ByAddressType.
|
/// Unwrap the inner ByAddrType.
|
||||||
pub(crate) fn unwrap(self) -> ByAddressType<Vec<T>> {
|
pub(crate) fn unwrap(self) -> ByAddrType<Vec<T>> {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
mod activity;
|
|
||||||
mod address_count;
|
|
||||||
mod data;
|
|
||||||
mod delta;
|
|
||||||
mod indexes;
|
|
||||||
mod new_address_count;
|
|
||||||
mod total_address_count;
|
|
||||||
mod type_map;
|
|
||||||
|
|
||||||
pub use activity::{AddressActivityVecs, AddressTypeToActivityCounts};
|
|
||||||
pub use address_count::{AddressCountsVecs, AddressTypeToAddressCount};
|
|
||||||
pub use data::AddressesDataVecs;
|
|
||||||
pub use delta::DeltaVecs;
|
|
||||||
pub use indexes::AnyAddressIndexesVecs;
|
|
||||||
pub use new_address_count::NewAddressCountVecs;
|
|
||||||
pub use total_address_count::TotalAddressCountVecs;
|
|
||||||
pub use type_map::{AddressTypeToTypeIndexMap, AddressTypeToVec, HeightToAddressTypeToVec};
|
|
||||||
138
crates/brk_computer/src/distribution/block/cache/addr.rs
vendored
Normal file
138
crates/brk_computer/src/distribution/block/cache/addr.rs
vendored
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
use brk_cohort::ByAddrType;
|
||||||
|
use brk_error::Result;
|
||||||
|
use brk_types::{
|
||||||
|
AnyAddrDataIndexEnum, EmptyAddrData, FundedAddrData, OutputType, TxIndex, TypeIndex,
|
||||||
|
};
|
||||||
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
|
use crate::distribution::{
|
||||||
|
addr::{AddrTypeToTypeIndexMap, AddrsDataVecs, AnyAddrIndexesVecs},
|
||||||
|
compute::VecsReaders,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::super::cohort::{WithAddrDataSource, update_tx_counts};
|
||||||
|
use super::lookup::AddrLookup;
|
||||||
|
|
||||||
|
/// Cache for address data within a flush interval.
|
||||||
|
pub struct AddrCache {
|
||||||
|
/// Addrs with non-zero balance
|
||||||
|
funded: AddrTypeToTypeIndexMap<WithAddrDataSource<FundedAddrData>>,
|
||||||
|
/// Addrs that became empty (zero balance)
|
||||||
|
empty: AddrTypeToTypeIndexMap<WithAddrDataSource<EmptyAddrData>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for AddrCache {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddrCache {
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
funded: AddrTypeToTypeIndexMap::default(),
|
||||||
|
empty: AddrTypeToTypeIndexMap::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if address is in cache (either funded or empty).
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn contains(&self, addr_type: OutputType, type_index: TypeIndex) -> bool {
|
||||||
|
self.funded
|
||||||
|
.get(addr_type)
|
||||||
|
.is_some_and(|m| m.contains_key(&type_index))
|
||||||
|
|| self
|
||||||
|
.empty
|
||||||
|
.get(addr_type)
|
||||||
|
.is_some_and(|m| m.contains_key(&type_index))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Merge address data into funded cache.
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn merge_funded(
|
||||||
|
&mut self,
|
||||||
|
data: AddrTypeToTypeIndexMap<WithAddrDataSource<FundedAddrData>>,
|
||||||
|
) {
|
||||||
|
self.funded.merge_mut(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create an AddrLookup view into this cache.
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn as_lookup(&mut self) -> AddrLookup<'_> {
|
||||||
|
AddrLookup {
|
||||||
|
funded: &mut self.funded,
|
||||||
|
empty: &mut self.empty,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update transaction counts for addresses.
|
||||||
|
pub(crate) fn update_tx_counts(
|
||||||
|
&mut self,
|
||||||
|
tx_index_vecs: AddrTypeToTypeIndexMap<SmallVec<[TxIndex; 4]>>,
|
||||||
|
) {
|
||||||
|
update_tx_counts(&mut self.funded, &mut self.empty, tx_index_vecs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Take the cache contents for flushing, leaving empty caches.
|
||||||
|
pub(crate) fn take(
|
||||||
|
&mut self,
|
||||||
|
) -> (
|
||||||
|
AddrTypeToTypeIndexMap<WithAddrDataSource<EmptyAddrData>>,
|
||||||
|
AddrTypeToTypeIndexMap<WithAddrDataSource<FundedAddrData>>,
|
||||||
|
) {
|
||||||
|
(
|
||||||
|
std::mem::take(&mut self.empty),
|
||||||
|
std::mem::take(&mut self.funded),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load address data from storage or create new.
|
||||||
|
///
|
||||||
|
/// Returns None if address is already in cache (funded or empty).
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub(crate) fn load_uncached_addr_data(
|
||||||
|
addr_type: OutputType,
|
||||||
|
type_index: TypeIndex,
|
||||||
|
first_addr_indexes: &ByAddrType<TypeIndex>,
|
||||||
|
cache: &AddrCache,
|
||||||
|
vr: &VecsReaders,
|
||||||
|
any_addr_indexes: &AnyAddrIndexesVecs,
|
||||||
|
addrs_data: &AddrsDataVecs,
|
||||||
|
) -> Result<Option<WithAddrDataSource<FundedAddrData>>> {
|
||||||
|
// Check if this is a new address (type_index >= first for this height)
|
||||||
|
let first = *first_addr_indexes.get(addr_type).unwrap();
|
||||||
|
if first <= type_index {
|
||||||
|
return Ok(Some(WithAddrDataSource::New(
|
||||||
|
FundedAddrData::default(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if already in cache
|
||||||
|
if cache.contains(addr_type, type_index) {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read from storage
|
||||||
|
let reader = vr.addr_reader(addr_type);
|
||||||
|
let any_addr_index = any_addr_indexes.get(addr_type, type_index, reader)?;
|
||||||
|
|
||||||
|
Ok(Some(match any_addr_index.to_enum() {
|
||||||
|
AnyAddrDataIndexEnum::Funded(funded_index) => {
|
||||||
|
let reader = &vr.any_addr_index_to_any_addr_data.funded;
|
||||||
|
let funded_data = addrs_data
|
||||||
|
.funded
|
||||||
|
.get_any_or_read_at(funded_index.into(), reader)?
|
||||||
|
.unwrap();
|
||||||
|
WithAddrDataSource::FromFunded(funded_index, funded_data)
|
||||||
|
}
|
||||||
|
AnyAddrDataIndexEnum::Empty(empty_index) => {
|
||||||
|
let reader = &vr.any_addr_index_to_any_addr_data.empty;
|
||||||
|
let empty_data = addrs_data
|
||||||
|
.empty
|
||||||
|
.get_any_or_read_at(empty_index.into(), reader)?
|
||||||
|
.unwrap();
|
||||||
|
WithAddrDataSource::FromEmpty(empty_index, empty_data.into())
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
use brk_cohort::ByAddressType;
|
|
||||||
use brk_error::Result;
|
|
||||||
use brk_types::{
|
|
||||||
AnyAddressDataIndexEnum, EmptyAddressData, FundedAddressData, OutputType, TxIndex, TypeIndex,
|
|
||||||
};
|
|
||||||
use smallvec::SmallVec;
|
|
||||||
|
|
||||||
use crate::distribution::{
|
|
||||||
address::{AddressTypeToTypeIndexMap, AddressesDataVecs, AnyAddressIndexesVecs},
|
|
||||||
compute::VecsReaders,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::super::cohort::{WithAddressDataSource, update_tx_counts};
|
|
||||||
use super::lookup::AddressLookup;
|
|
||||||
|
|
||||||
/// Cache for address data within a flush interval.
|
|
||||||
pub struct AddressCache {
|
|
||||||
/// Addresses with non-zero balance
|
|
||||||
funded: AddressTypeToTypeIndexMap<WithAddressDataSource<FundedAddressData>>,
|
|
||||||
/// Addresses that became empty (zero balance)
|
|
||||||
empty: AddressTypeToTypeIndexMap<WithAddressDataSource<EmptyAddressData>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for AddressCache {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AddressCache {
|
|
||||||
pub(crate) fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
funded: AddressTypeToTypeIndexMap::default(),
|
|
||||||
empty: AddressTypeToTypeIndexMap::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if address is in cache (either funded or empty).
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn contains(&self, address_type: OutputType, type_index: TypeIndex) -> bool {
|
|
||||||
self.funded
|
|
||||||
.get(address_type)
|
|
||||||
.is_some_and(|m| m.contains_key(&type_index))
|
|
||||||
|| self
|
|
||||||
.empty
|
|
||||||
.get(address_type)
|
|
||||||
.is_some_and(|m| m.contains_key(&type_index))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Merge address data into funded cache.
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn merge_funded(
|
|
||||||
&mut self,
|
|
||||||
data: AddressTypeToTypeIndexMap<WithAddressDataSource<FundedAddressData>>,
|
|
||||||
) {
|
|
||||||
self.funded.merge_mut(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create an AddressLookup view into this cache.
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn as_lookup(&mut self) -> AddressLookup<'_> {
|
|
||||||
AddressLookup {
|
|
||||||
funded: &mut self.funded,
|
|
||||||
empty: &mut self.empty,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Update transaction counts for addresses.
|
|
||||||
pub(crate) fn update_tx_counts(
|
|
||||||
&mut self,
|
|
||||||
tx_index_vecs: AddressTypeToTypeIndexMap<SmallVec<[TxIndex; 4]>>,
|
|
||||||
) {
|
|
||||||
update_tx_counts(&mut self.funded, &mut self.empty, tx_index_vecs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Take the cache contents for flushing, leaving empty caches.
|
|
||||||
pub(crate) fn take(
|
|
||||||
&mut self,
|
|
||||||
) -> (
|
|
||||||
AddressTypeToTypeIndexMap<WithAddressDataSource<EmptyAddressData>>,
|
|
||||||
AddressTypeToTypeIndexMap<WithAddressDataSource<FundedAddressData>>,
|
|
||||||
) {
|
|
||||||
(
|
|
||||||
std::mem::take(&mut self.empty),
|
|
||||||
std::mem::take(&mut self.funded),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Load address data from storage or create new.
|
|
||||||
///
|
|
||||||
/// Returns None if address is already in cache (funded or empty).
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
pub(crate) fn load_uncached_address_data(
|
|
||||||
address_type: OutputType,
|
|
||||||
type_index: TypeIndex,
|
|
||||||
first_address_indexes: &ByAddressType<TypeIndex>,
|
|
||||||
cache: &AddressCache,
|
|
||||||
vr: &VecsReaders,
|
|
||||||
any_address_indexes: &AnyAddressIndexesVecs,
|
|
||||||
addresses_data: &AddressesDataVecs,
|
|
||||||
) -> Result<Option<WithAddressDataSource<FundedAddressData>>> {
|
|
||||||
// Check if this is a new address (type_index >= first for this height)
|
|
||||||
let first = *first_address_indexes.get(address_type).unwrap();
|
|
||||||
if first <= type_index {
|
|
||||||
return Ok(Some(WithAddressDataSource::New(
|
|
||||||
FundedAddressData::default(),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip if already in cache
|
|
||||||
if cache.contains(address_type, type_index) {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read from storage
|
|
||||||
let reader = vr.address_reader(address_type);
|
|
||||||
let any_address_index = any_address_indexes.get(address_type, type_index, reader)?;
|
|
||||||
|
|
||||||
Ok(Some(match any_address_index.to_enum() {
|
|
||||||
AnyAddressDataIndexEnum::Funded(funded_index) => {
|
|
||||||
let reader = &vr.any_address_index_to_any_address_data.funded;
|
|
||||||
let funded_data = addresses_data
|
|
||||||
.funded
|
|
||||||
.get_any_or_read_at(funded_index.into(), reader)?
|
|
||||||
.unwrap();
|
|
||||||
WithAddressDataSource::FromFunded(funded_index, funded_data)
|
|
||||||
}
|
|
||||||
AnyAddressDataIndexEnum::Empty(empty_index) => {
|
|
||||||
let reader = &vr.any_address_index_to_any_address_data.empty;
|
|
||||||
let empty_data = addresses_data
|
|
||||||
.empty
|
|
||||||
.get_any_or_read_at(empty_index.into(), reader)?
|
|
||||||
.unwrap();
|
|
||||||
WithAddressDataSource::FromEmpty(empty_index, empty_data.into())
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
use brk_types::{EmptyAddressData, FundedAddressData, OutputType, TypeIndex};
|
use brk_types::{EmptyAddrData, FundedAddrData, OutputType, TypeIndex};
|
||||||
|
|
||||||
use crate::distribution::address::AddressTypeToTypeIndexMap;
|
use crate::distribution::addr::AddrTypeToTypeIndexMap;
|
||||||
|
|
||||||
use super::super::cohort::WithAddressDataSource;
|
use super::super::cohort::WithAddrDataSource;
|
||||||
|
|
||||||
/// Tracking status of an address - determines cohort update strategy.
|
/// Tracking status of an address - determines cohort update strategy.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
@@ -16,18 +16,18 @@ pub enum TrackingStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Context for looking up and storing address data during block processing.
|
/// Context for looking up and storing address data during block processing.
|
||||||
pub struct AddressLookup<'a> {
|
pub struct AddrLookup<'a> {
|
||||||
pub funded: &'a mut AddressTypeToTypeIndexMap<WithAddressDataSource<FundedAddressData>>,
|
pub funded: &'a mut AddrTypeToTypeIndexMap<WithAddrDataSource<FundedAddrData>>,
|
||||||
pub empty: &'a mut AddressTypeToTypeIndexMap<WithAddressDataSource<EmptyAddressData>>,
|
pub empty: &'a mut AddrTypeToTypeIndexMap<WithAddrDataSource<EmptyAddrData>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> AddressLookup<'a> {
|
impl<'a> AddrLookup<'a> {
|
||||||
pub(crate) fn get_or_create_for_receive(
|
pub(crate) fn get_or_create_for_receive(
|
||||||
&mut self,
|
&mut self,
|
||||||
output_type: OutputType,
|
output_type: OutputType,
|
||||||
type_index: TypeIndex,
|
type_index: TypeIndex,
|
||||||
) -> (
|
) -> (
|
||||||
&mut WithAddressDataSource<FundedAddressData>,
|
&mut WithAddrDataSource<FundedAddrData>,
|
||||||
TrackingStatus,
|
TrackingStatus,
|
||||||
) {
|
) {
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
@@ -36,7 +36,7 @@ impl<'a> AddressLookup<'a> {
|
|||||||
|
|
||||||
match map.entry(type_index) {
|
match map.entry(type_index) {
|
||||||
Entry::Occupied(entry) => {
|
Entry::Occupied(entry) => {
|
||||||
// Address is in cache. Need to determine if it's been processed
|
// Addr is in cache. Need to determine if it's been processed
|
||||||
// by process_received (added to a cohort) or just funded this block.
|
// by process_received (added to a cohort) or just funded this block.
|
||||||
//
|
//
|
||||||
// - If wrapper is New AND funded_txo_count == 0: hasn't received yet,
|
// - If wrapper is New AND funded_txo_count == 0: hasn't received yet,
|
||||||
@@ -47,15 +47,15 @@ impl<'a> AddressLookup<'a> {
|
|||||||
// - If wrapper is FromEmpty AND utxo_count == 0: still empty → WasEmpty
|
// - If wrapper is FromEmpty AND utxo_count == 0: still empty → WasEmpty
|
||||||
// - If wrapper is FromEmpty AND utxo_count > 0: already received → Tracked
|
// - If wrapper is FromEmpty AND utxo_count > 0: already received → Tracked
|
||||||
let status = match entry.get() {
|
let status = match entry.get() {
|
||||||
WithAddressDataSource::New(data) => {
|
WithAddrDataSource::New(data) => {
|
||||||
if data.funded_txo_count == 0 {
|
if data.funded_txo_count == 0 {
|
||||||
TrackingStatus::New
|
TrackingStatus::New
|
||||||
} else {
|
} else {
|
||||||
TrackingStatus::Tracked
|
TrackingStatus::Tracked
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WithAddressDataSource::FromFunded(..) => TrackingStatus::Tracked,
|
WithAddrDataSource::FromFunded(..) => TrackingStatus::Tracked,
|
||||||
WithAddressDataSource::FromEmpty(_, data) => {
|
WithAddrDataSource::FromEmpty(_, data) => {
|
||||||
if data.utxo_count() == 0 {
|
if data.utxo_count() == 0 {
|
||||||
TrackingStatus::WasEmpty
|
TrackingStatus::WasEmpty
|
||||||
} else {
|
} else {
|
||||||
@@ -72,7 +72,7 @@ impl<'a> AddressLookup<'a> {
|
|||||||
return (entry.insert(empty_data.into()), TrackingStatus::WasEmpty);
|
return (entry.insert(empty_data.into()), TrackingStatus::WasEmpty);
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
entry.insert(WithAddressDataSource::New(FundedAddressData::default())),
|
entry.insert(WithAddrDataSource::New(FundedAddrData::default())),
|
||||||
TrackingStatus::New,
|
TrackingStatus::New,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -84,12 +84,12 @@ impl<'a> AddressLookup<'a> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
output_type: OutputType,
|
output_type: OutputType,
|
||||||
type_index: TypeIndex,
|
type_index: TypeIndex,
|
||||||
) -> &mut WithAddressDataSource<FundedAddressData> {
|
) -> &mut WithAddrDataSource<FundedAddrData> {
|
||||||
self.funded
|
self.funded
|
||||||
.get_mut(output_type)
|
.get_mut(output_type)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get_mut(&type_index)
|
.get_mut(&type_index)
|
||||||
.expect("Address must exist for send")
|
.expect("Addr must exist for send")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move address from funded to empty set.
|
/// Move address from funded to empty set.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
mod address;
|
mod addr;
|
||||||
mod lookup;
|
mod lookup;
|
||||||
|
|
||||||
pub use address::*;
|
pub use addr::*;
|
||||||
pub use lookup::*;
|
pub use lookup::*;
|
||||||
|
|||||||
@@ -0,0 +1,152 @@
|
|||||||
|
use brk_error::Result;
|
||||||
|
use brk_types::{
|
||||||
|
AnyAddrIndex, EmptyAddrData, EmptyAddrIndex, FundedAddrData, FundedAddrIndex,
|
||||||
|
OutputType, TypeIndex,
|
||||||
|
};
|
||||||
|
use vecdb::AnyVec;
|
||||||
|
|
||||||
|
use crate::distribution::{AddrTypeToTypeIndexMap, AddrsDataVecs};
|
||||||
|
|
||||||
|
use super::with_source::WithAddrDataSource;
|
||||||
|
|
||||||
|
/// Process funded address data updates.
|
||||||
|
///
|
||||||
|
/// Handles:
|
||||||
|
/// - New funded address: push to funded storage
|
||||||
|
/// - Updated funded address (was funded): update in place
|
||||||
|
/// - Transition empty -> funded: delete from empty, push to funded
|
||||||
|
pub(crate) fn process_funded_addrs(
|
||||||
|
addrs_data: &mut AddrsDataVecs,
|
||||||
|
funded_updates: AddrTypeToTypeIndexMap<WithAddrDataSource<FundedAddrData>>,
|
||||||
|
) -> Result<AddrTypeToTypeIndexMap<AnyAddrIndex>> {
|
||||||
|
let total: usize = funded_updates.iter().map(|(_, m)| m.len()).sum();
|
||||||
|
|
||||||
|
let mut updates: Vec<(FundedAddrIndex, FundedAddrData)> = Vec::with_capacity(total);
|
||||||
|
let mut deletes: Vec<EmptyAddrIndex> = Vec::with_capacity(total);
|
||||||
|
let mut pushes: Vec<(OutputType, TypeIndex, FundedAddrData)> = Vec::with_capacity(total);
|
||||||
|
|
||||||
|
for (addr_type, items) in funded_updates.into_iter() {
|
||||||
|
for (type_index, source) in items {
|
||||||
|
match source {
|
||||||
|
WithAddrDataSource::New(data) => {
|
||||||
|
pushes.push((addr_type, type_index, data));
|
||||||
|
}
|
||||||
|
WithAddrDataSource::FromFunded(index, data) => {
|
||||||
|
updates.push((index, data));
|
||||||
|
}
|
||||||
|
WithAddrDataSource::FromEmpty(empty_index, data) => {
|
||||||
|
deletes.push(empty_index);
|
||||||
|
pushes.push((addr_type, type_index, data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 1: Deletes (creates holes)
|
||||||
|
for empty_index in deletes {
|
||||||
|
addrs_data.empty.delete(empty_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 2: Updates (in-place)
|
||||||
|
for (index, data) in updates {
|
||||||
|
addrs_data.funded.update(index, data)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 3: Pushes (fill holes first, then pure pushes)
|
||||||
|
let mut result = AddrTypeToTypeIndexMap::with_capacity(pushes.len() / 4);
|
||||||
|
let holes_count = addrs_data.funded.holes().len();
|
||||||
|
let mut pushes_iter = pushes.into_iter();
|
||||||
|
|
||||||
|
for (addr_type, type_index, data) in pushes_iter.by_ref().take(holes_count) {
|
||||||
|
let index = addrs_data.funded.fill_first_hole_or_push(data)?;
|
||||||
|
result
|
||||||
|
.get_mut(addr_type)
|
||||||
|
.unwrap()
|
||||||
|
.insert(type_index, AnyAddrIndex::from(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pure pushes - no holes remain
|
||||||
|
addrs_data.funded.reserve_pushed(pushes_iter.len());
|
||||||
|
let mut next_index = addrs_data.funded.len();
|
||||||
|
for (addr_type, type_index, data) in pushes_iter {
|
||||||
|
addrs_data.funded.push(data);
|
||||||
|
result.get_mut(addr_type).unwrap().insert(
|
||||||
|
type_index,
|
||||||
|
AnyAddrIndex::from(FundedAddrIndex::from(next_index)),
|
||||||
|
);
|
||||||
|
next_index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Process empty address data updates.
|
||||||
|
///
|
||||||
|
/// Handles:
|
||||||
|
/// - New empty address: push to empty storage
|
||||||
|
/// - Updated empty address (was empty): update in place
|
||||||
|
/// - Transition funded -> empty: delete from funded, push to empty
|
||||||
|
pub(crate) fn process_empty_addrs(
|
||||||
|
addrs_data: &mut AddrsDataVecs,
|
||||||
|
empty_updates: AddrTypeToTypeIndexMap<WithAddrDataSource<EmptyAddrData>>,
|
||||||
|
) -> Result<AddrTypeToTypeIndexMap<AnyAddrIndex>> {
|
||||||
|
let total: usize = empty_updates.iter().map(|(_, m)| m.len()).sum();
|
||||||
|
|
||||||
|
let mut updates: Vec<(EmptyAddrIndex, EmptyAddrData)> = Vec::with_capacity(total);
|
||||||
|
let mut deletes: Vec<FundedAddrIndex> = Vec::with_capacity(total);
|
||||||
|
let mut pushes: Vec<(OutputType, TypeIndex, EmptyAddrData)> = Vec::with_capacity(total);
|
||||||
|
|
||||||
|
for (addr_type, items) in empty_updates.into_iter() {
|
||||||
|
for (type_index, source) in items {
|
||||||
|
match source {
|
||||||
|
WithAddrDataSource::New(data) => {
|
||||||
|
pushes.push((addr_type, type_index, data));
|
||||||
|
}
|
||||||
|
WithAddrDataSource::FromEmpty(index, data) => {
|
||||||
|
updates.push((index, data));
|
||||||
|
}
|
||||||
|
WithAddrDataSource::FromFunded(funded_index, data) => {
|
||||||
|
deletes.push(funded_index);
|
||||||
|
pushes.push((addr_type, type_index, data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 1: Deletes (creates holes)
|
||||||
|
for funded_index in deletes {
|
||||||
|
addrs_data.funded.delete(funded_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 2: Updates (in-place)
|
||||||
|
for (index, data) in updates {
|
||||||
|
addrs_data.empty.update(index, data)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 3: Pushes (fill holes first, then pure pushes)
|
||||||
|
let mut result = AddrTypeToTypeIndexMap::with_capacity(pushes.len() / 4);
|
||||||
|
let holes_count = addrs_data.empty.holes().len();
|
||||||
|
let mut pushes_iter = pushes.into_iter();
|
||||||
|
|
||||||
|
for (addr_type, type_index, data) in pushes_iter.by_ref().take(holes_count) {
|
||||||
|
let index = addrs_data.empty.fill_first_hole_or_push(data)?;
|
||||||
|
result
|
||||||
|
.get_mut(addr_type)
|
||||||
|
.unwrap()
|
||||||
|
.insert(type_index, AnyAddrIndex::from(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pure pushes - no holes remain
|
||||||
|
addrs_data.empty.reserve_pushed(pushes_iter.len());
|
||||||
|
let mut next_index = addrs_data.empty.len();
|
||||||
|
for (addr_type, type_index, data) in pushes_iter {
|
||||||
|
addrs_data.empty.push(data);
|
||||||
|
result.get_mut(addr_type).unwrap().insert(
|
||||||
|
type_index,
|
||||||
|
AnyAddrIndex::from(EmptyAddrIndex::from(next_index)),
|
||||||
|
);
|
||||||
|
next_index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
use brk_error::Result;
|
|
||||||
use brk_types::{
|
|
||||||
AnyAddressIndex, EmptyAddressData, EmptyAddressIndex, FundedAddressData, FundedAddressIndex,
|
|
||||||
OutputType, TypeIndex,
|
|
||||||
};
|
|
||||||
use vecdb::AnyVec;
|
|
||||||
|
|
||||||
use crate::distribution::{AddressTypeToTypeIndexMap, AddressesDataVecs};
|
|
||||||
|
|
||||||
use super::with_source::WithAddressDataSource;
|
|
||||||
|
|
||||||
/// Process funded address data updates.
|
|
||||||
///
|
|
||||||
/// Handles:
|
|
||||||
/// - New funded address: push to funded storage
|
|
||||||
/// - Updated funded address (was funded): update in place
|
|
||||||
/// - Transition empty -> funded: delete from empty, push to funded
|
|
||||||
pub(crate) fn process_funded_addresses(
|
|
||||||
addresses_data: &mut AddressesDataVecs,
|
|
||||||
funded_updates: AddressTypeToTypeIndexMap<WithAddressDataSource<FundedAddressData>>,
|
|
||||||
) -> Result<AddressTypeToTypeIndexMap<AnyAddressIndex>> {
|
|
||||||
let total: usize = funded_updates.iter().map(|(_, m)| m.len()).sum();
|
|
||||||
|
|
||||||
let mut updates: Vec<(FundedAddressIndex, FundedAddressData)> = Vec::with_capacity(total);
|
|
||||||
let mut deletes: Vec<EmptyAddressIndex> = Vec::with_capacity(total);
|
|
||||||
let mut pushes: Vec<(OutputType, TypeIndex, FundedAddressData)> = Vec::with_capacity(total);
|
|
||||||
|
|
||||||
for (address_type, items) in funded_updates.into_iter() {
|
|
||||||
for (type_index, source) in items {
|
|
||||||
match source {
|
|
||||||
WithAddressDataSource::New(data) => {
|
|
||||||
pushes.push((address_type, type_index, data));
|
|
||||||
}
|
|
||||||
WithAddressDataSource::FromFunded(index, data) => {
|
|
||||||
updates.push((index, data));
|
|
||||||
}
|
|
||||||
WithAddressDataSource::FromEmpty(empty_index, data) => {
|
|
||||||
deletes.push(empty_index);
|
|
||||||
pushes.push((address_type, type_index, data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Phase 1: Deletes (creates holes)
|
|
||||||
for empty_index in deletes {
|
|
||||||
addresses_data.empty.delete(empty_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Phase 2: Updates (in-place)
|
|
||||||
for (index, data) in updates {
|
|
||||||
addresses_data.funded.update(index, data)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Phase 3: Pushes (fill holes first, then pure pushes)
|
|
||||||
let mut result = AddressTypeToTypeIndexMap::with_capacity(pushes.len() / 4);
|
|
||||||
let holes_count = addresses_data.funded.holes().len();
|
|
||||||
let mut pushes_iter = pushes.into_iter();
|
|
||||||
|
|
||||||
for (address_type, type_index, data) in pushes_iter.by_ref().take(holes_count) {
|
|
||||||
let index = addresses_data.funded.fill_first_hole_or_push(data)?;
|
|
||||||
result
|
|
||||||
.get_mut(address_type)
|
|
||||||
.unwrap()
|
|
||||||
.insert(type_index, AnyAddressIndex::from(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pure pushes - no holes remain
|
|
||||||
addresses_data.funded.reserve_pushed(pushes_iter.len());
|
|
||||||
let mut next_index = addresses_data.funded.len();
|
|
||||||
for (address_type, type_index, data) in pushes_iter {
|
|
||||||
addresses_data.funded.push(data);
|
|
||||||
result.get_mut(address_type).unwrap().insert(
|
|
||||||
type_index,
|
|
||||||
AnyAddressIndex::from(FundedAddressIndex::from(next_index)),
|
|
||||||
);
|
|
||||||
next_index += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Process empty address data updates.
|
|
||||||
///
|
|
||||||
/// Handles:
|
|
||||||
/// - New empty address: push to empty storage
|
|
||||||
/// - Updated empty address (was empty): update in place
|
|
||||||
/// - Transition funded -> empty: delete from funded, push to empty
|
|
||||||
pub(crate) fn process_empty_addresses(
|
|
||||||
addresses_data: &mut AddressesDataVecs,
|
|
||||||
empty_updates: AddressTypeToTypeIndexMap<WithAddressDataSource<EmptyAddressData>>,
|
|
||||||
) -> Result<AddressTypeToTypeIndexMap<AnyAddressIndex>> {
|
|
||||||
let total: usize = empty_updates.iter().map(|(_, m)| m.len()).sum();
|
|
||||||
|
|
||||||
let mut updates: Vec<(EmptyAddressIndex, EmptyAddressData)> = Vec::with_capacity(total);
|
|
||||||
let mut deletes: Vec<FundedAddressIndex> = Vec::with_capacity(total);
|
|
||||||
let mut pushes: Vec<(OutputType, TypeIndex, EmptyAddressData)> = Vec::with_capacity(total);
|
|
||||||
|
|
||||||
for (address_type, items) in empty_updates.into_iter() {
|
|
||||||
for (type_index, source) in items {
|
|
||||||
match source {
|
|
||||||
WithAddressDataSource::New(data) => {
|
|
||||||
pushes.push((address_type, type_index, data));
|
|
||||||
}
|
|
||||||
WithAddressDataSource::FromEmpty(index, data) => {
|
|
||||||
updates.push((index, data));
|
|
||||||
}
|
|
||||||
WithAddressDataSource::FromFunded(funded_index, data) => {
|
|
||||||
deletes.push(funded_index);
|
|
||||||
pushes.push((address_type, type_index, data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Phase 1: Deletes (creates holes)
|
|
||||||
for funded_index in deletes {
|
|
||||||
addresses_data.funded.delete(funded_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Phase 2: Updates (in-place)
|
|
||||||
for (index, data) in updates {
|
|
||||||
addresses_data.empty.update(index, data)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Phase 3: Pushes (fill holes first, then pure pushes)
|
|
||||||
let mut result = AddressTypeToTypeIndexMap::with_capacity(pushes.len() / 4);
|
|
||||||
let holes_count = addresses_data.empty.holes().len();
|
|
||||||
let mut pushes_iter = pushes.into_iter();
|
|
||||||
|
|
||||||
for (address_type, type_index, data) in pushes_iter.by_ref().take(holes_count) {
|
|
||||||
let index = addresses_data.empty.fill_first_hole_or_push(data)?;
|
|
||||||
result
|
|
||||||
.get_mut(address_type)
|
|
||||||
.unwrap()
|
|
||||||
.insert(type_index, AnyAddressIndex::from(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pure pushes - no holes remain
|
|
||||||
addresses_data.empty.reserve_pushed(pushes_iter.len());
|
|
||||||
let mut next_index = addresses_data.empty.len();
|
|
||||||
for (address_type, type_index, data) in pushes_iter {
|
|
||||||
addresses_data.empty.push(data);
|
|
||||||
result.get_mut(address_type).unwrap().insert(
|
|
||||||
type_index,
|
|
||||||
AnyAddressIndex::from(EmptyAddressIndex::from(next_index)),
|
|
||||||
);
|
|
||||||
next_index += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
mod address_updates;
|
mod addr_updates;
|
||||||
mod received;
|
mod received;
|
||||||
mod sent;
|
mod sent;
|
||||||
mod tx_counts;
|
mod tx_counts;
|
||||||
mod with_source;
|
mod with_source;
|
||||||
|
|
||||||
pub(crate) use address_updates::*;
|
pub(crate) use addr_updates::*;
|
||||||
pub(crate) use received::*;
|
pub(crate) use received::*;
|
||||||
pub(crate) use sent::*;
|
pub(crate) use sent::*;
|
||||||
pub(crate) use tx_counts::*;
|
pub(crate) use tx_counts::*;
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
use brk_cohort::{AmountBucket, ByAddressType};
|
use brk_cohort::{AmountBucket, ByAddrType};
|
||||||
use brk_types::{Cents, Sats, TypeIndex};
|
use brk_types::{Cents, Sats, TypeIndex};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use crate::distribution::{
|
use crate::distribution::{
|
||||||
address::{AddressTypeToActivityCounts, AddressTypeToVec},
|
addr::{AddrTypeToActivityCounts, AddrTypeToVec},
|
||||||
cohorts::AddressCohorts,
|
cohorts::AddrCohorts,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::super::cache::{AddressLookup, TrackingStatus};
|
use super::super::cache::{AddrLookup, TrackingStatus};
|
||||||
|
|
||||||
/// Aggregated receive data for a single address within a block.
|
/// Aggregated receive data for a single address within a block.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@@ -18,13 +18,13 @@ struct AggregatedReceive {
|
|||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(crate) fn process_received(
|
pub(crate) fn process_received(
|
||||||
received_data: AddressTypeToVec<(TypeIndex, Sats)>,
|
received_data: AddrTypeToVec<(TypeIndex, Sats)>,
|
||||||
cohorts: &mut AddressCohorts,
|
cohorts: &mut AddrCohorts,
|
||||||
lookup: &mut AddressLookup<'_>,
|
lookup: &mut AddrLookup<'_>,
|
||||||
price: Cents,
|
price: Cents,
|
||||||
address_count: &mut ByAddressType<u64>,
|
addr_count: &mut ByAddrType<u64>,
|
||||||
empty_address_count: &mut ByAddressType<u64>,
|
empty_addr_count: &mut ByAddrType<u64>,
|
||||||
activity_counts: &mut AddressTypeToActivityCounts,
|
activity_counts: &mut AddrTypeToActivityCounts,
|
||||||
) {
|
) {
|
||||||
let max_type_len = received_data.iter().map(|(_, v)| v.len()).max().unwrap_or(0);
|
let max_type_len = received_data.iter().map(|(_, v)| v.len()).max().unwrap_or(0);
|
||||||
let mut aggregated: FxHashMap<TypeIndex, AggregatedReceive> =
|
let mut aggregated: FxHashMap<TypeIndex, AggregatedReceive> =
|
||||||
@@ -36,8 +36,8 @@ pub(crate) fn process_received(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cache mutable refs for this address type
|
// Cache mutable refs for this address type
|
||||||
let type_address_count = address_count.get_mut(output_type).unwrap();
|
let type_addr_count = addr_count.get_mut(output_type).unwrap();
|
||||||
let type_empty_count = empty_address_count.get_mut(output_type).unwrap();
|
let type_empty_count = empty_addr_count.get_mut(output_type).unwrap();
|
||||||
let type_activity = activity_counts.get_mut_unwrap(output_type);
|
let type_activity = activity_counts.get_mut_unwrap(output_type);
|
||||||
|
|
||||||
// Aggregate receives by address - each address processed exactly once
|
// Aggregate receives by address - each address processed exactly once
|
||||||
@@ -55,10 +55,10 @@ pub(crate) fn process_received(
|
|||||||
|
|
||||||
match status {
|
match status {
|
||||||
TrackingStatus::New => {
|
TrackingStatus::New => {
|
||||||
*type_address_count += 1;
|
*type_addr_count += 1;
|
||||||
}
|
}
|
||||||
TrackingStatus::WasEmpty => {
|
TrackingStatus::WasEmpty => {
|
||||||
*type_address_count += 1;
|
*type_addr_count += 1;
|
||||||
*type_empty_count -= 1;
|
*type_empty_count -= 1;
|
||||||
// Reactivated - was empty, now has funds
|
// Reactivated - was empty, now has funds
|
||||||
type_activity.reactivated += 1;
|
type_activity.reactivated += 1;
|
||||||
@@ -100,7 +100,7 @@ pub(crate) fn process_received(
|
|||||||
"process_received: cohort underflow detected!\n\
|
"process_received: cohort underflow detected!\n\
|
||||||
output_type={:?}, type_index={:?}\n\
|
output_type={:?}, type_index={:?}\n\
|
||||||
prev_balance={}, new_balance={}, total_value={}\n\
|
prev_balance={}, new_balance={}, total_value={}\n\
|
||||||
Address: {:?}",
|
Addr: {:?}",
|
||||||
output_type,
|
output_type,
|
||||||
type_index,
|
type_index,
|
||||||
prev_balance,
|
prev_balance,
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
use brk_cohort::{AmountBucket, ByAddressType};
|
use brk_cohort::{AmountBucket, ByAddrType};
|
||||||
use brk_error::Result;
|
use brk_error::Result;
|
||||||
use brk_types::{Age, Cents, CheckedSub, Height, Sats, Timestamp, TypeIndex};
|
use brk_types::{Age, Cents, CheckedSub, Height, Sats, Timestamp, TypeIndex};
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
use vecdb::VecIndex;
|
use vecdb::VecIndex;
|
||||||
|
|
||||||
use crate::distribution::{
|
use crate::distribution::{
|
||||||
address::{AddressTypeToActivityCounts, HeightToAddressTypeToVec},
|
addr::{AddrTypeToActivityCounts, HeightToAddrTypeToVec},
|
||||||
cohorts::AddressCohorts,
|
cohorts::AddrCohorts,
|
||||||
compute::PriceRangeMax,
|
compute::PriceRangeMax,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::super::cache::AddressLookup;
|
use super::super::cache::AddrLookup;
|
||||||
|
|
||||||
/// Process sent outputs for address cohorts.
|
/// Process sent outputs for address cohorts.
|
||||||
///
|
///
|
||||||
@@ -27,20 +27,20 @@ use super::super::cache::AddressLookup;
|
|||||||
/// for accurate peak regret calculation.
|
/// for accurate peak regret calculation.
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(crate) fn process_sent(
|
pub(crate) fn process_sent(
|
||||||
sent_data: HeightToAddressTypeToVec<(TypeIndex, Sats)>,
|
sent_data: HeightToAddrTypeToVec<(TypeIndex, Sats)>,
|
||||||
cohorts: &mut AddressCohorts,
|
cohorts: &mut AddrCohorts,
|
||||||
lookup: &mut AddressLookup<'_>,
|
lookup: &mut AddrLookup<'_>,
|
||||||
current_price: Cents,
|
current_price: Cents,
|
||||||
price_range_max: &PriceRangeMax,
|
price_range_max: &PriceRangeMax,
|
||||||
address_count: &mut ByAddressType<u64>,
|
addr_count: &mut ByAddrType<u64>,
|
||||||
empty_address_count: &mut ByAddressType<u64>,
|
empty_addr_count: &mut ByAddrType<u64>,
|
||||||
activity_counts: &mut AddressTypeToActivityCounts,
|
activity_counts: &mut AddrTypeToActivityCounts,
|
||||||
received_addresses: &ByAddressType<FxHashSet<TypeIndex>>,
|
received_addrs: &ByAddrType<FxHashSet<TypeIndex>>,
|
||||||
height_to_price: &[Cents],
|
height_to_price: &[Cents],
|
||||||
height_to_timestamp: &[Timestamp],
|
height_to_timestamp: &[Timestamp],
|
||||||
current_height: Height,
|
current_height: Height,
|
||||||
current_timestamp: Timestamp,
|
current_timestamp: Timestamp,
|
||||||
seen_senders: &mut ByAddressType<FxHashSet<TypeIndex>>,
|
seen_senders: &mut ByAddrType<FxHashSet<TypeIndex>>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
seen_senders.values_mut().for_each(|set| set.clear());
|
seen_senders.values_mut().for_each(|set| set.clear());
|
||||||
|
|
||||||
@@ -54,10 +54,10 @@ pub(crate) fn process_sent(
|
|||||||
|
|
||||||
for (output_type, vec) in by_type.unwrap().into_iter() {
|
for (output_type, vec) in by_type.unwrap().into_iter() {
|
||||||
// Cache mutable refs for this address type
|
// Cache mutable refs for this address type
|
||||||
let type_address_count = address_count.get_mut(output_type).unwrap();
|
let type_addr_count = addr_count.get_mut(output_type).unwrap();
|
||||||
let type_empty_count = empty_address_count.get_mut(output_type).unwrap();
|
let type_empty_count = empty_addr_count.get_mut(output_type).unwrap();
|
||||||
let type_activity = activity_counts.get_mut_unwrap(output_type);
|
let type_activity = activity_counts.get_mut_unwrap(output_type);
|
||||||
let type_received = received_addresses.get(output_type);
|
let type_received = received_addrs.get(output_type);
|
||||||
let type_seen = seen_senders.get_mut_unwrap(output_type);
|
let type_seen = seen_senders.get_mut_unwrap(output_type);
|
||||||
|
|
||||||
for (type_index, value) in vec {
|
for (type_index, value) in vec {
|
||||||
@@ -99,7 +99,7 @@ pub(crate) fn process_sent(
|
|||||||
|
|
||||||
// Migrate address to new bucket or mark as empty
|
// Migrate address to new bucket or mark as empty
|
||||||
if will_be_empty {
|
if will_be_empty {
|
||||||
*type_address_count -= 1;
|
*type_addr_count -= 1;
|
||||||
*type_empty_count += 1;
|
*type_empty_count += 1;
|
||||||
lookup.move_to_empty(output_type, type_index);
|
lookup.move_to_empty(output_type, type_index);
|
||||||
} else if crossing_boundary {
|
} else if crossing_boundary {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use brk_types::{EmptyAddressData, FundedAddressData, TxIndex};
|
use brk_types::{EmptyAddrData, FundedAddrData, TxIndex};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::distribution::address::AddressTypeToTypeIndexMap;
|
use crate::distribution::addr::AddrTypeToTypeIndexMap;
|
||||||
|
|
||||||
use super::with_source::WithAddressDataSource;
|
use super::with_source::WithAddrDataSource;
|
||||||
|
|
||||||
/// Update tx_count for addresses based on unique transactions they participated in.
|
/// Update tx_count for addresses based on unique transactions they participated in.
|
||||||
///
|
///
|
||||||
@@ -14,9 +14,9 @@ use super::with_source::WithAddressDataSource;
|
|||||||
/// Addresses are looked up in funded_cache first, then empty_cache.
|
/// Addresses are looked up in funded_cache first, then empty_cache.
|
||||||
/// NOTE: This should be called AFTER merging parallel-fetched address data into funded_cache.
|
/// NOTE: This should be called AFTER merging parallel-fetched address data into funded_cache.
|
||||||
pub(crate) fn update_tx_counts(
|
pub(crate) fn update_tx_counts(
|
||||||
funded_cache: &mut AddressTypeToTypeIndexMap<WithAddressDataSource<FundedAddressData>>,
|
funded_cache: &mut AddrTypeToTypeIndexMap<WithAddrDataSource<FundedAddrData>>,
|
||||||
empty_cache: &mut AddressTypeToTypeIndexMap<WithAddressDataSource<EmptyAddressData>>,
|
empty_cache: &mut AddrTypeToTypeIndexMap<WithAddrDataSource<EmptyAddrData>>,
|
||||||
mut tx_index_vecs: AddressTypeToTypeIndexMap<SmallVec<[TxIndex; 4]>>,
|
mut tx_index_vecs: AddrTypeToTypeIndexMap<SmallVec<[TxIndex; 4]>>,
|
||||||
) {
|
) {
|
||||||
// First, deduplicate tx_index_vecs for addresses that appear multiple times in a block
|
// First, deduplicate tx_index_vecs for addresses that appear multiple times in a block
|
||||||
for (_, map) in tx_index_vecs.iter_mut() {
|
for (_, map) in tx_index_vecs.iter_mut() {
|
||||||
@@ -29,20 +29,20 @@ pub(crate) fn update_tx_counts(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update tx_count on address data
|
// Update tx_count on address data
|
||||||
for (address_type, type_index, tx_index_vec) in tx_index_vecs
|
for (addr_type, type_index, tx_index_vec) in tx_index_vecs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|(t, m)| m.into_iter().map(move |(i, v)| (t, i, v)))
|
.flat_map(|(t, m)| m.into_iter().map(move |(i, v)| (t, i, v)))
|
||||||
{
|
{
|
||||||
let tx_count = tx_index_vec.len() as u32;
|
let tx_count = tx_index_vec.len() as u32;
|
||||||
|
|
||||||
if let Some(addr_data) = funded_cache
|
if let Some(addr_data) = funded_cache
|
||||||
.get_mut(address_type)
|
.get_mut(addr_type)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get_mut(&type_index)
|
.get_mut(&type_index)
|
||||||
{
|
{
|
||||||
addr_data.tx_count += tx_count;
|
addr_data.tx_count += tx_count;
|
||||||
} else if let Some(addr_data) = empty_cache
|
} else if let Some(addr_data) = empty_cache
|
||||||
.get_mut(address_type)
|
.get_mut(addr_type)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get_mut(&type_index)
|
.get_mut(&type_index)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
use brk_types::{EmptyAddressData, EmptyAddressIndex, FundedAddressData, FundedAddressIndex};
|
use brk_types::{EmptyAddrData, EmptyAddrIndex, FundedAddrData, FundedAddrIndex};
|
||||||
|
|
||||||
/// Address data wrapped with its source location for flush operations.
|
/// Address data wrapped with its source location for flush operations.
|
||||||
///
|
///
|
||||||
/// This enum tracks where the data came from so it can be correctly
|
/// This enum tracks where the data came from so it can be correctly
|
||||||
/// updated or created during the flush phase.
|
/// updated or created during the flush phase.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum WithAddressDataSource<T> {
|
pub enum WithAddrDataSource<T> {
|
||||||
/// Brand new address (never seen before)
|
/// Brand new address (never seen before)
|
||||||
New(T),
|
New(T),
|
||||||
/// Funded from funded address storage (with original index)
|
/// Funded from funded address storage (with original index)
|
||||||
FromFunded(FundedAddressIndex, T),
|
FromFunded(FundedAddrIndex, T),
|
||||||
/// Funded from empty address storage (with original index)
|
/// Funded from empty address storage (with original index)
|
||||||
FromEmpty(EmptyAddressIndex, T),
|
FromEmpty(EmptyAddrIndex, T),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> std::ops::Deref for WithAddressDataSource<T> {
|
impl<T> std::ops::Deref for WithAddrDataSource<T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
@@ -24,7 +24,7 @@ impl<T> std::ops::Deref for WithAddressDataSource<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> std::ops::DerefMut for WithAddressDataSource<T> {
|
impl<T> std::ops::DerefMut for WithAddrDataSource<T> {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
match self {
|
match self {
|
||||||
Self::New(v) | Self::FromFunded(_, v) | Self::FromEmpty(_, v) => v,
|
Self::New(v) | Self::FromFunded(_, v) | Self::FromEmpty(_, v) => v,
|
||||||
@@ -32,24 +32,24 @@ impl<T> std::ops::DerefMut for WithAddressDataSource<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<WithAddressDataSource<EmptyAddressData>> for WithAddressDataSource<FundedAddressData> {
|
impl From<WithAddrDataSource<EmptyAddrData>> for WithAddrDataSource<FundedAddrData> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: WithAddressDataSource<EmptyAddressData>) -> Self {
|
fn from(value: WithAddrDataSource<EmptyAddrData>) -> Self {
|
||||||
match value {
|
match value {
|
||||||
WithAddressDataSource::New(v) => Self::New(v.into()),
|
WithAddrDataSource::New(v) => Self::New(v.into()),
|
||||||
WithAddressDataSource::FromFunded(i, v) => Self::FromFunded(i, v.into()),
|
WithAddrDataSource::FromFunded(i, v) => Self::FromFunded(i, v.into()),
|
||||||
WithAddressDataSource::FromEmpty(i, v) => Self::FromEmpty(i, v.into()),
|
WithAddrDataSource::FromEmpty(i, v) => Self::FromEmpty(i, v.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<WithAddressDataSource<FundedAddressData>> for WithAddressDataSource<EmptyAddressData> {
|
impl From<WithAddrDataSource<FundedAddrData>> for WithAddrDataSource<EmptyAddrData> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: WithAddressDataSource<FundedAddressData>) -> Self {
|
fn from(value: WithAddrDataSource<FundedAddrData>) -> Self {
|
||||||
match value {
|
match value {
|
||||||
WithAddressDataSource::New(v) => Self::New(v.into()),
|
WithAddrDataSource::New(v) => Self::New(v.into()),
|
||||||
WithAddressDataSource::FromFunded(i, v) => Self::FromFunded(i, v.into()),
|
WithAddrDataSource::FromFunded(i, v) => Self::FromFunded(i, v.into()),
|
||||||
WithAddressDataSource::FromEmpty(i, v) => Self::FromEmpty(i, v.into()),
|
WithAddrDataSource::FromEmpty(i, v) => Self::FromEmpty(i, v.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
use brk_cohort::ByAddressType;
|
use brk_cohort::ByAddrType;
|
||||||
use brk_error::Result;
|
use brk_error::Result;
|
||||||
use brk_types::{FundedAddressData, Height, OutputType, Sats, TxIndex, TypeIndex};
|
use brk_types::{FundedAddrData, Height, OutputType, Sats, TxIndex, TypeIndex};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::distribution::{
|
use crate::distribution::{
|
||||||
address::{AddressTypeToTypeIndexMap, AddressesDataVecs, AnyAddressIndexesVecs},
|
addr::{AddrTypeToTypeIndexMap, AddrsDataVecs, AnyAddrIndexesVecs},
|
||||||
compute::VecsReaders,
|
compute::VecsReaders,
|
||||||
state::Transacted,
|
state::Transacted,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::distribution::address::HeightToAddressTypeToVec;
|
use crate::distribution::addr::HeightToAddrTypeToVec;
|
||||||
|
|
||||||
use super::super::{
|
use super::super::{
|
||||||
cache::{AddressCache, load_uncached_address_data},
|
cache::{AddrCache, load_uncached_addr_data},
|
||||||
cohort::WithAddressDataSource,
|
cohort::WithAddrDataSource,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Result of processing inputs for a block.
|
/// Result of processing inputs for a block.
|
||||||
@@ -23,11 +23,11 @@ pub struct InputsResult {
|
|||||||
/// Map from UTXO creation height -> aggregated sent supply.
|
/// Map from UTXO creation height -> aggregated sent supply.
|
||||||
pub height_to_sent: FxHashMap<Height, Transacted>,
|
pub height_to_sent: FxHashMap<Height, Transacted>,
|
||||||
/// Per-height, per-address-type sent data: (type_index, value) for each address.
|
/// Per-height, per-address-type sent data: (type_index, value) for each address.
|
||||||
pub sent_data: HeightToAddressTypeToVec<(TypeIndex, Sats)>,
|
pub sent_data: HeightToAddrTypeToVec<(TypeIndex, Sats)>,
|
||||||
/// Address data looked up during processing, keyed by (address_type, type_index).
|
/// Address data looked up during processing, keyed by (addr_type, type_index).
|
||||||
pub address_data: AddressTypeToTypeIndexMap<WithAddressDataSource<FundedAddressData>>,
|
pub addr_data: AddrTypeToTypeIndexMap<WithAddrDataSource<FundedAddrData>>,
|
||||||
/// Transaction indexes per address for tx_count tracking.
|
/// Transaction indexes per address for tx_count tracking.
|
||||||
pub tx_index_vecs: AddressTypeToTypeIndexMap<SmallVec<[TxIndex; 4]>>,
|
pub tx_index_vecs: AddrTypeToTypeIndexMap<SmallVec<[TxIndex; 4]>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process inputs (spent UTXOs) for a block.
|
/// Process inputs (spent UTXOs) for a block.
|
||||||
@@ -51,11 +51,11 @@ pub(crate) fn process_inputs(
|
|||||||
txin_index_to_output_type: &[OutputType],
|
txin_index_to_output_type: &[OutputType],
|
||||||
txin_index_to_type_index: &[TypeIndex],
|
txin_index_to_type_index: &[TypeIndex],
|
||||||
txin_index_to_prev_height: &[Height],
|
txin_index_to_prev_height: &[Height],
|
||||||
first_address_indexes: &ByAddressType<TypeIndex>,
|
first_addr_indexes: &ByAddrType<TypeIndex>,
|
||||||
cache: &AddressCache,
|
cache: &AddrCache,
|
||||||
vr: &VecsReaders,
|
vr: &VecsReaders,
|
||||||
any_address_indexes: &AnyAddressIndexesVecs,
|
any_addr_indexes: &AnyAddrIndexesVecs,
|
||||||
addresses_data: &AddressesDataVecs,
|
addrs_data: &AddrsDataVecs,
|
||||||
) -> Result<InputsResult> {
|
) -> Result<InputsResult> {
|
||||||
let map_fn = |local_idx: usize| -> Result<_> {
|
let map_fn = |local_idx: usize| -> Result<_> {
|
||||||
let tx_index = txin_index_to_tx_index[local_idx];
|
let tx_index = txin_index_to_tx_index[local_idx];
|
||||||
@@ -64,21 +64,21 @@ pub(crate) fn process_inputs(
|
|||||||
let value = txin_index_to_value[local_idx];
|
let value = txin_index_to_value[local_idx];
|
||||||
let input_type = txin_index_to_output_type[local_idx];
|
let input_type = txin_index_to_output_type[local_idx];
|
||||||
|
|
||||||
if input_type.is_not_address() {
|
if input_type.is_not_addr() {
|
||||||
return Ok((prev_height, value, input_type, None));
|
return Ok((prev_height, value, input_type, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
let type_index = txin_index_to_type_index[local_idx];
|
let type_index = txin_index_to_type_index[local_idx];
|
||||||
|
|
||||||
// Look up address data
|
// Look up address data
|
||||||
let addr_data_opt = load_uncached_address_data(
|
let addr_data_opt = load_uncached_addr_data(
|
||||||
input_type,
|
input_type,
|
||||||
type_index,
|
type_index,
|
||||||
first_address_indexes,
|
first_addr_indexes,
|
||||||
cache,
|
cache,
|
||||||
vr,
|
vr,
|
||||||
any_address_indexes,
|
any_addr_indexes,
|
||||||
addresses_data,
|
addrs_data,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
@@ -108,13 +108,13 @@ pub(crate) fn process_inputs(
|
|||||||
estimated_unique_heights,
|
estimated_unique_heights,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
);
|
);
|
||||||
let mut sent_data = HeightToAddressTypeToVec::with_capacity(estimated_unique_heights);
|
let mut sent_data = HeightToAddrTypeToVec::with_capacity(estimated_unique_heights);
|
||||||
let mut address_data =
|
let mut addr_data =
|
||||||
AddressTypeToTypeIndexMap::<WithAddressDataSource<FundedAddressData>>::with_capacity(
|
AddrTypeToTypeIndexMap::<WithAddrDataSource<FundedAddrData>>::with_capacity(
|
||||||
estimated_per_type,
|
estimated_per_type,
|
||||||
);
|
);
|
||||||
let mut tx_index_vecs =
|
let mut tx_index_vecs =
|
||||||
AddressTypeToTypeIndexMap::<SmallVec<[TxIndex; 4]>>::with_capacity(estimated_per_type);
|
AddrTypeToTypeIndexMap::<SmallVec<[TxIndex; 4]>>::with_capacity(estimated_per_type);
|
||||||
|
|
||||||
for (prev_height, value, output_type, addr_info) in items {
|
for (prev_height, value, output_type, addr_info) in items {
|
||||||
height_to_sent
|
height_to_sent
|
||||||
@@ -130,8 +130,8 @@ pub(crate) fn process_inputs(
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.push((type_index, value));
|
.push((type_index, value));
|
||||||
|
|
||||||
if let Some(addr_data) = addr_data_opt {
|
if let Some(source) = addr_data_opt {
|
||||||
address_data.insert_for_type(output_type, type_index, addr_data);
|
addr_data.insert_for_type(output_type, type_index, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
tx_index_vecs
|
tx_index_vecs
|
||||||
@@ -146,7 +146,7 @@ pub(crate) fn process_inputs(
|
|||||||
Ok(InputsResult {
|
Ok(InputsResult {
|
||||||
height_to_sent,
|
height_to_sent,
|
||||||
sent_data,
|
sent_data,
|
||||||
address_data,
|
addr_data,
|
||||||
tx_index_vecs,
|
tx_index_vecs,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
use brk_cohort::ByAddressType;
|
use brk_cohort::ByAddrType;
|
||||||
use brk_error::Result;
|
use brk_error::Result;
|
||||||
use brk_types::{FundedAddressData, Sats, TxIndex, TypeIndex};
|
use brk_types::{FundedAddrData, Sats, TxIndex, TypeIndex};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::distribution::{
|
use crate::distribution::{
|
||||||
address::{
|
addr::{
|
||||||
AddressTypeToTypeIndexMap, AddressTypeToVec, AddressesDataVecs, AnyAddressIndexesVecs,
|
AddrTypeToTypeIndexMap, AddrTypeToVec, AddrsDataVecs, AnyAddrIndexesVecs,
|
||||||
},
|
},
|
||||||
compute::{TxOutData, VecsReaders},
|
compute::{TxOutData, VecsReaders},
|
||||||
state::Transacted,
|
state::Transacted,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::super::{
|
use super::super::{
|
||||||
cache::{AddressCache, load_uncached_address_data},
|
cache::{AddrCache, load_uncached_addr_data},
|
||||||
cohort::WithAddressDataSource,
|
cohort::WithAddrDataSource,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Result of processing outputs for a block.
|
/// Result of processing outputs for a block.
|
||||||
@@ -22,11 +22,11 @@ pub struct OutputsResult {
|
|||||||
/// Aggregated supply transacted in this block.
|
/// Aggregated supply transacted in this block.
|
||||||
pub transacted: Transacted,
|
pub transacted: Transacted,
|
||||||
/// Per-address-type received data: (type_index, value) for each address.
|
/// Per-address-type received data: (type_index, value) for each address.
|
||||||
pub received_data: AddressTypeToVec<(TypeIndex, Sats)>,
|
pub received_data: AddrTypeToVec<(TypeIndex, Sats)>,
|
||||||
/// Address data looked up during processing, keyed by (address_type, type_index).
|
/// Address data looked up during processing, keyed by (addr_type, type_index).
|
||||||
pub address_data: AddressTypeToTypeIndexMap<WithAddressDataSource<FundedAddressData>>,
|
pub addr_data: AddrTypeToTypeIndexMap<WithAddrDataSource<FundedAddrData>>,
|
||||||
/// Transaction indexes per address for tx_count tracking.
|
/// Transaction indexes per address for tx_count tracking.
|
||||||
pub tx_index_vecs: AddressTypeToTypeIndexMap<SmallVec<[TxIndex; 4]>>,
|
pub tx_index_vecs: AddrTypeToTypeIndexMap<SmallVec<[TxIndex; 4]>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process outputs (new UTXOs) for a block.
|
/// Process outputs (new UTXOs) for a block.
|
||||||
@@ -40,35 +40,35 @@ pub struct OutputsResult {
|
|||||||
pub(crate) fn process_outputs(
|
pub(crate) fn process_outputs(
|
||||||
txout_index_to_tx_index: &[TxIndex],
|
txout_index_to_tx_index: &[TxIndex],
|
||||||
txout_data_vec: &[TxOutData],
|
txout_data_vec: &[TxOutData],
|
||||||
first_address_indexes: &ByAddressType<TypeIndex>,
|
first_addr_indexes: &ByAddrType<TypeIndex>,
|
||||||
cache: &AddressCache,
|
cache: &AddrCache,
|
||||||
vr: &VecsReaders,
|
vr: &VecsReaders,
|
||||||
any_address_indexes: &AnyAddressIndexesVecs,
|
any_addr_indexes: &AnyAddrIndexesVecs,
|
||||||
addresses_data: &AddressesDataVecs,
|
addrs_data: &AddrsDataVecs,
|
||||||
) -> Result<OutputsResult> {
|
) -> Result<OutputsResult> {
|
||||||
let output_count = txout_data_vec.len();
|
let output_count = txout_data_vec.len();
|
||||||
|
|
||||||
// Phase 1: Address lookups (mmap reads) — parallel for large blocks, sequential for small
|
// Phase 1: Addr lookups (mmap reads) — parallel for large blocks, sequential for small
|
||||||
let map_fn = |local_idx: usize| -> Result<_> {
|
let map_fn = |local_idx: usize| -> Result<_> {
|
||||||
let txout_data = &txout_data_vec[local_idx];
|
let txout_data = &txout_data_vec[local_idx];
|
||||||
let value = txout_data.value;
|
let value = txout_data.value;
|
||||||
let output_type = txout_data.output_type;
|
let output_type = txout_data.output_type;
|
||||||
|
|
||||||
if output_type.is_not_address() {
|
if output_type.is_not_addr() {
|
||||||
return Ok((value, output_type, None));
|
return Ok((value, output_type, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
let type_index = txout_data.type_index;
|
let type_index = txout_data.type_index;
|
||||||
let tx_index = txout_index_to_tx_index[local_idx];
|
let tx_index = txout_index_to_tx_index[local_idx];
|
||||||
|
|
||||||
let addr_data_opt = load_uncached_address_data(
|
let addr_data_opt = load_uncached_addr_data(
|
||||||
output_type,
|
output_type,
|
||||||
type_index,
|
type_index,
|
||||||
first_address_indexes,
|
first_addr_indexes,
|
||||||
cache,
|
cache,
|
||||||
vr,
|
vr,
|
||||||
any_address_indexes,
|
any_addr_indexes,
|
||||||
addresses_data,
|
addrs_data,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
@@ -92,13 +92,13 @@ pub(crate) fn process_outputs(
|
|||||||
// Phase 2: Sequential accumulation
|
// Phase 2: Sequential accumulation
|
||||||
let estimated_per_type = (output_count / 8).max(8);
|
let estimated_per_type = (output_count / 8).max(8);
|
||||||
let mut transacted = Transacted::default();
|
let mut transacted = Transacted::default();
|
||||||
let mut received_data = AddressTypeToVec::with_capacity(estimated_per_type);
|
let mut received_data = AddrTypeToVec::with_capacity(estimated_per_type);
|
||||||
let mut address_data =
|
let mut addr_data =
|
||||||
AddressTypeToTypeIndexMap::<WithAddressDataSource<FundedAddressData>>::with_capacity(
|
AddrTypeToTypeIndexMap::<WithAddrDataSource<FundedAddrData>>::with_capacity(
|
||||||
estimated_per_type,
|
estimated_per_type,
|
||||||
);
|
);
|
||||||
let mut tx_index_vecs =
|
let mut tx_index_vecs =
|
||||||
AddressTypeToTypeIndexMap::<SmallVec<[TxIndex; 4]>>::with_capacity(estimated_per_type);
|
AddrTypeToTypeIndexMap::<SmallVec<[TxIndex; 4]>>::with_capacity(estimated_per_type);
|
||||||
|
|
||||||
for (value, output_type, addr_info) in items {
|
for (value, output_type, addr_info) in items {
|
||||||
transacted.iterate(value, output_type);
|
transacted.iterate(value, output_type);
|
||||||
@@ -109,8 +109,8 @@ pub(crate) fn process_outputs(
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.push((type_index, value));
|
.push((type_index, value));
|
||||||
|
|
||||||
if let Some(addr_data) = addr_data_opt {
|
if let Some(source) = addr_data_opt {
|
||||||
address_data.insert_for_type(output_type, type_index, addr_data);
|
addr_data.insert_for_type(output_type, type_index, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
tx_index_vecs
|
tx_index_vecs
|
||||||
@@ -125,7 +125,7 @@ pub(crate) fn process_outputs(
|
|||||||
Ok(OutputsResult {
|
Ok(OutputsResult {
|
||||||
transacted,
|
transacted,
|
||||||
received_data,
|
received_data,
|
||||||
address_data,
|
addr_data,
|
||||||
tx_index_vecs,
|
tx_index_vecs,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use brk_cohort::{
|
use brk_cohort::{
|
||||||
AddressGroups, AmountRange, OverAmount, UnderAmount, Filter, Filtered,
|
AddrGroups, AmountRange, OverAmount, UnderAmount, Filter, Filtered,
|
||||||
};
|
};
|
||||||
use brk_error::Result;
|
use brk_error::Result;
|
||||||
use brk_traversable::Traversable;
|
use brk_traversable::Traversable;
|
||||||
@@ -12,16 +12,16 @@ use vecdb::{AnyStoredVec, Database, Exit, Rw, StorageMode};
|
|||||||
|
|
||||||
use crate::{distribution::DynCohortVecs, indexes, internal::CachedWindowStarts, prices};
|
use crate::{distribution::DynCohortVecs, indexes, internal::CachedWindowStarts, prices};
|
||||||
|
|
||||||
use super::{super::traits::CohortVecs, vecs::AddressCohortVecs};
|
use super::{super::traits::CohortVecs, vecs::AddrCohortVecs};
|
||||||
|
|
||||||
const VERSION: Version = Version::new(0);
|
const VERSION: Version = Version::new(0);
|
||||||
|
|
||||||
/// All Address cohorts organized by filter type.
|
/// All Addr cohorts organized by filter type.
|
||||||
#[derive(Deref, DerefMut, Traversable)]
|
#[derive(Deref, DerefMut, Traversable)]
|
||||||
pub struct AddressCohorts<M: StorageMode = Rw>(AddressGroups<AddressCohortVecs<M>>);
|
pub struct AddrCohorts<M: StorageMode = Rw>(AddrGroups<AddrCohortVecs<M>>);
|
||||||
|
|
||||||
impl AddressCohorts {
|
impl AddrCohorts {
|
||||||
/// Import all Address cohorts from database.
|
/// Import all Addr cohorts from database.
|
||||||
pub(crate) fn forced_import(
|
pub(crate) fn forced_import(
|
||||||
db: &Database,
|
db: &Database,
|
||||||
version: Version,
|
version: Version,
|
||||||
@@ -33,15 +33,15 @@ impl AddressCohorts {
|
|||||||
|
|
||||||
// Helper to create a cohort - only amount_range cohorts have state
|
// Helper to create a cohort - only amount_range cohorts have state
|
||||||
let create =
|
let create =
|
||||||
|filter: Filter, name: &'static str, has_state: bool| -> Result<AddressCohortVecs> {
|
|filter: Filter, name: &'static str, has_state: bool| -> Result<AddrCohortVecs> {
|
||||||
let sp = if has_state { Some(states_path) } else { None };
|
let sp = if has_state { Some(states_path) } else { None };
|
||||||
AddressCohortVecs::forced_import(db, filter, name, v, indexes, sp, cached_starts)
|
AddrCohortVecs::forced_import(db, filter, name, v, indexes, sp, cached_starts)
|
||||||
};
|
};
|
||||||
|
|
||||||
let full = |f: Filter, name: &'static str| create(f, name, true);
|
let full = |f: Filter, name: &'static str| create(f, name, true);
|
||||||
let none = |f: Filter, name: &'static str| create(f, name, false);
|
let none = |f: Filter, name: &'static str| create(f, name, false);
|
||||||
|
|
||||||
Ok(Self(AddressGroups {
|
Ok(Self(AddrGroups {
|
||||||
amount_range: AmountRange::try_new(&full)?,
|
amount_range: AmountRange::try_new(&full)?,
|
||||||
under_amount: UnderAmount::try_new(&none)?,
|
under_amount: UnderAmount::try_new(&none)?,
|
||||||
over_amount: OverAmount::try_new(&none)?,
|
over_amount: OverAmount::try_new(&none)?,
|
||||||
@@ -51,7 +51,7 @@ impl AddressCohorts {
|
|||||||
/// Apply a function to each aggregate cohort with its source cohorts (in parallel).
|
/// Apply a function to each aggregate cohort with its source cohorts (in parallel).
|
||||||
fn for_each_aggregate<F>(&mut self, f: F) -> Result<()>
|
fn for_each_aggregate<F>(&mut self, f: F) -> Result<()>
|
||||||
where
|
where
|
||||||
F: Fn(&mut AddressCohortVecs, Vec<&AddressCohortVecs>) -> Result<()> + Sync,
|
F: Fn(&mut AddrCohortVecs, Vec<&AddrCohortVecs>) -> Result<()> + Sync,
|
||||||
{
|
{
|
||||||
let by_amount_range = &self.0.amount_range;
|
let by_amount_range = &self.0.amount_range;
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ use rayon::prelude::*;
|
|||||||
use vecdb::{AnyStoredVec, AnyVec, Database, Exit, ReadableVec, Rw, StorageMode, WritableVec};
|
use vecdb::{AnyStoredVec, AnyVec, Database, Exit, ReadableVec, Rw, StorageMode, WritableVec};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
distribution::state::{AddressCohortState, MinimalRealizedState},
|
distribution::state::{AddrCohortState, MinimalRealizedState},
|
||||||
indexes,
|
indexes,
|
||||||
internal::{CachedWindowStarts, PerBlockWithDeltas},
|
internal::{CachedWindowStarts, PerBlockWithDeltas},
|
||||||
prices,
|
prices,
|
||||||
@@ -18,19 +18,19 @@ use crate::distribution::metrics::{ImportConfig, MinimalCohortMetrics};
|
|||||||
|
|
||||||
use super::super::traits::{CohortVecs, DynCohortVecs};
|
use super::super::traits::{CohortVecs, DynCohortVecs};
|
||||||
#[derive(Traversable)]
|
#[derive(Traversable)]
|
||||||
pub struct AddressCohortVecs<M: StorageMode = Rw> {
|
pub struct AddrCohortVecs<M: StorageMode = Rw> {
|
||||||
starting_height: Option<Height>,
|
starting_height: Option<Height>,
|
||||||
|
|
||||||
#[traversable(skip)]
|
#[traversable(skip)]
|
||||||
pub state: Option<Box<AddressCohortState<MinimalRealizedState>>>,
|
pub state: Option<Box<AddrCohortState<MinimalRealizedState>>>,
|
||||||
|
|
||||||
#[traversable(flatten)]
|
#[traversable(flatten)]
|
||||||
pub metrics: MinimalCohortMetrics<M>,
|
pub metrics: MinimalCohortMetrics<M>,
|
||||||
|
|
||||||
pub address_count: PerBlockWithDeltas<StoredU64, StoredI64, BasisPointsSigned32, M>,
|
pub addr_count: PerBlockWithDeltas<StoredU64, StoredI64, BasisPointsSigned32, M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddressCohortVecs {
|
impl AddrCohortVecs {
|
||||||
pub(crate) fn forced_import(
|
pub(crate) fn forced_import(
|
||||||
db: &Database,
|
db: &Database,
|
||||||
filter: Filter,
|
filter: Filter,
|
||||||
@@ -40,7 +40,7 @@ impl AddressCohortVecs {
|
|||||||
states_path: Option<&Path>,
|
states_path: Option<&Path>,
|
||||||
cached_starts: &CachedWindowStarts,
|
cached_starts: &CachedWindowStarts,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let full_name = CohortContext::Address.full_name(&filter, name);
|
let full_name = CohortContext::Addr.full_name(&filter, name);
|
||||||
|
|
||||||
let cfg = ImportConfig {
|
let cfg = ImportConfig {
|
||||||
db,
|
db,
|
||||||
@@ -51,9 +51,9 @@ impl AddressCohortVecs {
|
|||||||
cached_starts,
|
cached_starts,
|
||||||
};
|
};
|
||||||
|
|
||||||
let address_count = PerBlockWithDeltas::forced_import(
|
let addr_count = PerBlockWithDeltas::forced_import(
|
||||||
db,
|
db,
|
||||||
&cfg.name("address_count"),
|
&cfg.name("addr_count"),
|
||||||
version,
|
version,
|
||||||
Version::ONE,
|
Version::ONE,
|
||||||
indexes,
|
indexes,
|
||||||
@@ -62,9 +62,9 @@ impl AddressCohortVecs {
|
|||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
starting_height: None,
|
starting_height: None,
|
||||||
state: states_path.map(|path| Box::new(AddressCohortState::new(path, &full_name))),
|
state: states_path.map(|path| Box::new(AddrCohortState::new(path, &full_name))),
|
||||||
metrics: MinimalCohortMetrics::forced_import(&cfg)?,
|
metrics: MinimalCohortMetrics::forced_import(&cfg)?,
|
||||||
address_count,
|
addr_count,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ impl AddressCohortVecs {
|
|||||||
&mut self,
|
&mut self,
|
||||||
) -> impl ParallelIterator<Item = &mut dyn AnyStoredVec> {
|
) -> impl ParallelIterator<Item = &mut dyn AnyStoredVec> {
|
||||||
let mut vecs: Vec<&mut dyn AnyStoredVec> = Vec::new();
|
let mut vecs: Vec<&mut dyn AnyStoredVec> = Vec::new();
|
||||||
vecs.push(&mut self.address_count.height as &mut dyn AnyStoredVec);
|
vecs.push(&mut self.addr_count.height as &mut dyn AnyStoredVec);
|
||||||
vecs.extend(self.metrics.collect_all_vecs_mut());
|
vecs.extend(self.metrics.collect_all_vecs_mut());
|
||||||
vecs.into_par_iter()
|
vecs.into_par_iter()
|
||||||
}
|
}
|
||||||
@@ -89,15 +89,15 @@ impl AddressCohortVecs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Filtered for AddressCohortVecs {
|
impl Filtered for AddrCohortVecs {
|
||||||
fn filter(&self) -> &Filter {
|
fn filter(&self) -> &Filter {
|
||||||
&self.metrics.filter
|
&self.metrics.filter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DynCohortVecs for AddressCohortVecs {
|
impl DynCohortVecs for AddrCohortVecs {
|
||||||
fn min_stateful_len(&self) -> usize {
|
fn min_stateful_len(&self) -> usize {
|
||||||
self.address_count
|
self.addr_count
|
||||||
.height
|
.height
|
||||||
.len()
|
.len()
|
||||||
.min(self.metrics.min_stateful_len())
|
.min(self.metrics.min_stateful_len())
|
||||||
@@ -130,7 +130,7 @@ impl DynCohortVecs for AddressCohortVecs {
|
|||||||
.height
|
.height
|
||||||
.collect_one(prev_height)
|
.collect_one(prev_height)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
state.address_count = *self.address_count.height.collect_one(prev_height).unwrap();
|
state.addr_count = *self.addr_count.height.collect_one(prev_height).unwrap();
|
||||||
|
|
||||||
state.inner.restore_realized_cap();
|
state.inner.restore_realized_cap();
|
||||||
|
|
||||||
@@ -149,7 +149,7 @@ impl DynCohortVecs for AddressCohortVecs {
|
|||||||
|
|
||||||
fn validate_computed_versions(&mut self, base_version: Version) -> Result<()> {
|
fn validate_computed_versions(&mut self, base_version: Version) -> Result<()> {
|
||||||
use vecdb::WritableVec;
|
use vecdb::WritableVec;
|
||||||
self.address_count
|
self.addr_count
|
||||||
.height
|
.height
|
||||||
.validate_computed_version_or_reset(base_version)?;
|
.validate_computed_version_or_reset(base_version)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -161,9 +161,9 @@ impl DynCohortVecs for AddressCohortVecs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(state) = self.state.as_ref() {
|
if let Some(state) = self.state.as_ref() {
|
||||||
self.address_count
|
self.addr_count
|
||||||
.height
|
.height
|
||||||
.push(state.address_count.into());
|
.push(state.addr_count.into());
|
||||||
self.metrics.supply.push_state(&state.inner);
|
self.metrics.supply.push_state(&state.inner);
|
||||||
self.metrics.outputs.push_state(&state.inner);
|
self.metrics.outputs.push_state(&state.inner);
|
||||||
self.metrics.realized.push_state(&state.inner);
|
self.metrics.realized.push_state(&state.inner);
|
||||||
@@ -203,18 +203,18 @@ impl DynCohortVecs for AddressCohortVecs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CohortVecs for AddressCohortVecs {
|
impl CohortVecs for AddrCohortVecs {
|
||||||
fn compute_from_stateful(
|
fn compute_from_stateful(
|
||||||
&mut self,
|
&mut self,
|
||||||
starting_indexes: &Indexes,
|
starting_indexes: &Indexes,
|
||||||
others: &[&Self],
|
others: &[&Self],
|
||||||
exit: &Exit,
|
exit: &Exit,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
self.address_count.height.compute_sum_of_others(
|
self.addr_count.height.compute_sum_of_others(
|
||||||
starting_indexes.height,
|
starting_indexes.height,
|
||||||
others
|
others
|
||||||
.iter()
|
.iter()
|
||||||
.map(|v| &v.address_count.height)
|
.map(|v| &v.addr_count.height)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.as_slice(),
|
.as_slice(),
|
||||||
exit,
|
exit,
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
mod address;
|
mod addr;
|
||||||
mod traits;
|
mod traits;
|
||||||
mod utxo;
|
mod utxo;
|
||||||
|
|
||||||
pub use address::AddressCohorts;
|
pub use addr::AddrCohorts;
|
||||||
pub use traits::DynCohortVecs;
|
pub use traits::DynCohortVecs;
|
||||||
pub use utxo::UTXOCohorts;
|
pub use utxo::UTXOCohorts;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use brk_cohort::ByAddressType;
|
use brk_cohort::ByAddrType;
|
||||||
use brk_error::Result;
|
use brk_error::Result;
|
||||||
use brk_indexer::Indexer;
|
use brk_indexer::Indexer;
|
||||||
use brk_types::{
|
use brk_types::{
|
||||||
@@ -11,12 +11,12 @@ use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, VecIndex, WritableVec};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
distribution::{
|
distribution::{
|
||||||
address::{AddressTypeToActivityCounts, AddressTypeToAddressCount},
|
addr::{AddrTypeToActivityCounts, AddrTypeToAddrCount},
|
||||||
block::{
|
block::{
|
||||||
AddressCache, InputsResult, process_inputs, process_outputs, process_received,
|
AddrCache, InputsResult, process_inputs, process_outputs, process_received,
|
||||||
process_sent,
|
process_sent,
|
||||||
},
|
},
|
||||||
compute::write::{process_address_updates, write},
|
compute::write::{process_addr_updates, write},
|
||||||
state::{BlockState, Transacted},
|
state::{BlockState, Transacted},
|
||||||
},
|
},
|
||||||
indexes, inputs, outputs, transactions,
|
indexes, inputs, outputs, transactions,
|
||||||
@@ -25,7 +25,7 @@ use crate::{
|
|||||||
use super::{
|
use super::{
|
||||||
super::{
|
super::{
|
||||||
RangeMap,
|
RangeMap,
|
||||||
cohorts::{AddressCohorts, DynCohortVecs, UTXOCohorts},
|
cohorts::{AddrCohorts, DynCohortVecs, UTXOCohorts},
|
||||||
vecs::Vecs,
|
vecs::Vecs,
|
||||||
},
|
},
|
||||||
BIP30_DUPLICATE_HEIGHT_1, BIP30_DUPLICATE_HEIGHT_2, BIP30_ORIGINAL_HEIGHT_1,
|
BIP30_DUPLICATE_HEIGHT_1, BIP30_DUPLICATE_HEIGHT_2, BIP30_ORIGINAL_HEIGHT_1,
|
||||||
@@ -103,7 +103,7 @@ pub(crate) fn process_blocks(
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
debug!("creating VecsReaders");
|
debug!("creating VecsReaders");
|
||||||
let mut vr = VecsReaders::new(&vecs.any_address_indexes, &vecs.addresses_data);
|
let mut vr = VecsReaders::new(&vecs.any_addr_indexes, &vecs.addrs_data);
|
||||||
debug!("VecsReaders created");
|
debug!("VecsReaders created");
|
||||||
|
|
||||||
// Extend tx_index_to_height RangeMap with new entries (incremental, O(new_blocks))
|
// Extend tx_index_to_height RangeMap with new entries (incremental, O(new_blocks))
|
||||||
@@ -143,69 +143,69 @@ pub(crate) fn process_blocks(
|
|||||||
// Pre-collect first address indexes per type for the block range
|
// Pre-collect first address indexes per type for the block range
|
||||||
let first_p2a_vec = indexer
|
let first_p2a_vec = indexer
|
||||||
.vecs
|
.vecs
|
||||||
.addresses
|
.addrs
|
||||||
.p2a.first_index
|
.p2a.first_index
|
||||||
.collect_range_at(start_usize, end_usize);
|
.collect_range_at(start_usize, end_usize);
|
||||||
let first_p2pk33_vec = indexer
|
let first_p2pk33_vec = indexer
|
||||||
.vecs
|
.vecs
|
||||||
.addresses
|
.addrs
|
||||||
.p2pk33.first_index
|
.p2pk33.first_index
|
||||||
.collect_range_at(start_usize, end_usize);
|
.collect_range_at(start_usize, end_usize);
|
||||||
let first_p2pk65_vec = indexer
|
let first_p2pk65_vec = indexer
|
||||||
.vecs
|
.vecs
|
||||||
.addresses
|
.addrs
|
||||||
.p2pk65.first_index
|
.p2pk65.first_index
|
||||||
.collect_range_at(start_usize, end_usize);
|
.collect_range_at(start_usize, end_usize);
|
||||||
let first_p2pkh_vec = indexer
|
let first_p2pkh_vec = indexer
|
||||||
.vecs
|
.vecs
|
||||||
.addresses
|
.addrs
|
||||||
.p2pkh.first_index
|
.p2pkh.first_index
|
||||||
.collect_range_at(start_usize, end_usize);
|
.collect_range_at(start_usize, end_usize);
|
||||||
let first_p2sh_vec = indexer
|
let first_p2sh_vec = indexer
|
||||||
.vecs
|
.vecs
|
||||||
.addresses
|
.addrs
|
||||||
.p2sh.first_index
|
.p2sh.first_index
|
||||||
.collect_range_at(start_usize, end_usize);
|
.collect_range_at(start_usize, end_usize);
|
||||||
let first_p2tr_vec = indexer
|
let first_p2tr_vec = indexer
|
||||||
.vecs
|
.vecs
|
||||||
.addresses
|
.addrs
|
||||||
.p2tr.first_index
|
.p2tr.first_index
|
||||||
.collect_range_at(start_usize, end_usize);
|
.collect_range_at(start_usize, end_usize);
|
||||||
let first_p2wpkh_vec = indexer
|
let first_p2wpkh_vec = indexer
|
||||||
.vecs
|
.vecs
|
||||||
.addresses
|
.addrs
|
||||||
.p2wpkh.first_index
|
.p2wpkh.first_index
|
||||||
.collect_range_at(start_usize, end_usize);
|
.collect_range_at(start_usize, end_usize);
|
||||||
let first_p2wsh_vec = indexer
|
let first_p2wsh_vec = indexer
|
||||||
.vecs
|
.vecs
|
||||||
.addresses
|
.addrs
|
||||||
.p2wsh.first_index
|
.p2wsh.first_index
|
||||||
.collect_range_at(start_usize, end_usize);
|
.collect_range_at(start_usize, end_usize);
|
||||||
|
|
||||||
// Track running totals - recover from previous height if resuming
|
// Track running totals - recover from previous height if resuming
|
||||||
debug!("recovering address_counts from height {}", starting_height);
|
debug!("recovering addr_counts from height {}", starting_height);
|
||||||
let (mut address_counts, mut empty_address_counts) = if starting_height > Height::ZERO {
|
let (mut addr_counts, mut empty_addr_counts) = if starting_height > Height::ZERO {
|
||||||
let address_counts =
|
let addr_counts =
|
||||||
AddressTypeToAddressCount::from((&vecs.addresses.funded.by_address_type, starting_height));
|
AddrTypeToAddrCount::from((&vecs.addrs.funded.by_addr_type, starting_height));
|
||||||
let empty_address_counts = AddressTypeToAddressCount::from((
|
let empty_addr_counts = AddrTypeToAddrCount::from((
|
||||||
&vecs.addresses.empty.by_address_type,
|
&vecs.addrs.empty.by_addr_type,
|
||||||
starting_height,
|
starting_height,
|
||||||
));
|
));
|
||||||
(address_counts, empty_address_counts)
|
(addr_counts, empty_addr_counts)
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
AddressTypeToAddressCount::default(),
|
AddrTypeToAddrCount::default(),
|
||||||
AddressTypeToAddressCount::default(),
|
AddrTypeToAddrCount::default(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
debug!("address_counts recovered");
|
debug!("addr_counts recovered");
|
||||||
|
|
||||||
// Track activity counts - reset each block
|
// Track activity counts - reset each block
|
||||||
let mut activity_counts = AddressTypeToActivityCounts::default();
|
let mut activity_counts = AddrTypeToActivityCounts::default();
|
||||||
|
|
||||||
debug!("creating AddressCache");
|
debug!("creating AddrCache");
|
||||||
let mut cache = AddressCache::new();
|
let mut cache = AddrCache::new();
|
||||||
debug!("AddressCache created, entering main loop");
|
debug!("AddrCache created, entering main loop");
|
||||||
|
|
||||||
// Initialize Fenwick tree from imported BTreeMap state (one-time)
|
// Initialize Fenwick tree from imported BTreeMap state (one-time)
|
||||||
vecs.utxo_cohorts.init_fenwick_if_needed();
|
vecs.utxo_cohorts.init_fenwick_if_needed();
|
||||||
@@ -216,10 +216,10 @@ pub(crate) fn process_blocks(
|
|||||||
let start = starting_height.to_usize();
|
let start = starting_height.to_usize();
|
||||||
vecs.utxo_cohorts
|
vecs.utxo_cohorts
|
||||||
.par_iter_vecs_mut()
|
.par_iter_vecs_mut()
|
||||||
.chain(vecs.address_cohorts.par_iter_vecs_mut())
|
.chain(vecs.addr_cohorts.par_iter_vecs_mut())
|
||||||
.chain(vecs.addresses.funded.par_iter_height_mut())
|
.chain(vecs.addrs.funded.par_iter_height_mut())
|
||||||
.chain(vecs.addresses.empty.par_iter_height_mut())
|
.chain(vecs.addrs.empty.par_iter_height_mut())
|
||||||
.chain(vecs.addresses.activity.par_iter_height_mut())
|
.chain(vecs.addrs.activity.par_iter_height_mut())
|
||||||
.chain(rayon::iter::once(
|
.chain(rayon::iter::once(
|
||||||
&mut vecs.coinblocks_destroyed.base.height as &mut dyn AnyStoredVec,
|
&mut vecs.coinblocks_destroyed.base.height as &mut dyn AnyStoredVec,
|
||||||
))
|
))
|
||||||
@@ -227,8 +227,8 @@ pub(crate) fn process_blocks(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reusable hashsets (avoid per-block allocation)
|
// Reusable hashsets (avoid per-block allocation)
|
||||||
let mut received_addresses = ByAddressType::<FxHashSet<TypeIndex>>::default();
|
let mut received_addrs = ByAddrType::<FxHashSet<TypeIndex>>::default();
|
||||||
let mut seen_senders = ByAddressType::<FxHashSet<TypeIndex>>::default();
|
let mut seen_senders = ByAddrType::<FxHashSet<TypeIndex>>::default();
|
||||||
|
|
||||||
// Track earliest chain_state modification from sends (for incremental supply_state writes)
|
// Track earliest chain_state modification from sends (for incremental supply_state writes)
|
||||||
let mut min_supply_modified: Option<Height> = None;
|
let mut min_supply_modified: Option<Height> = None;
|
||||||
@@ -255,7 +255,7 @@ pub(crate) fn process_blocks(
|
|||||||
debug_assert_eq!(ctx.price_at(height), block_price);
|
debug_assert_eq!(ctx.price_at(height), block_price);
|
||||||
|
|
||||||
// Get first address indexes for this height from pre-collected vecs
|
// Get first address indexes for this height from pre-collected vecs
|
||||||
let first_address_indexes = ByAddressType {
|
let first_addr_indexes = ByAddrType {
|
||||||
p2a: TypeIndex::from(first_p2a_vec[offset].to_usize()),
|
p2a: TypeIndex::from(first_p2a_vec[offset].to_usize()),
|
||||||
p2pk33: TypeIndex::from(first_p2pk33_vec[offset].to_usize()),
|
p2pk33: TypeIndex::from(first_p2pk33_vec[offset].to_usize()),
|
||||||
p2pk65: TypeIndex::from(first_p2pk65_vec[offset].to_usize()),
|
p2pk65: TypeIndex::from(first_p2pk65_vec[offset].to_usize()),
|
||||||
@@ -285,11 +285,11 @@ pub(crate) fn process_blocks(
|
|||||||
process_outputs(
|
process_outputs(
|
||||||
txout_index_to_tx_index,
|
txout_index_to_tx_index,
|
||||||
txout_data_vec,
|
txout_data_vec,
|
||||||
&first_address_indexes,
|
&first_addr_indexes,
|
||||||
&cache,
|
&cache,
|
||||||
&vr,
|
&vr,
|
||||||
&vecs.any_address_indexes,
|
&vecs.any_addr_indexes,
|
||||||
&vecs.addresses_data,
|
&vecs.addrs_data,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|| -> Result<_> {
|
|| -> Result<_> {
|
||||||
@@ -309,17 +309,17 @@ pub(crate) fn process_blocks(
|
|||||||
input_output_types,
|
input_output_types,
|
||||||
input_type_indexes,
|
input_type_indexes,
|
||||||
input_prev_heights,
|
input_prev_heights,
|
||||||
&first_address_indexes,
|
&first_addr_indexes,
|
||||||
&cache,
|
&cache,
|
||||||
&vr,
|
&vr,
|
||||||
&vecs.any_address_indexes,
|
&vecs.any_addr_indexes,
|
||||||
&vecs.addresses_data,
|
&vecs.addrs_data,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Ok(InputsResult {
|
Ok(InputsResult {
|
||||||
height_to_sent: Default::default(),
|
height_to_sent: Default::default(),
|
||||||
sent_data: Default::default(),
|
sent_data: Default::default(),
|
||||||
address_data: Default::default(),
|
addr_data: Default::default(),
|
||||||
tx_index_vecs: Default::default(),
|
tx_index_vecs: Default::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -331,8 +331,8 @@ pub(crate) fn process_blocks(
|
|||||||
let (outputs_result, inputs_result) = oi_result?;
|
let (outputs_result, inputs_result) = oi_result?;
|
||||||
|
|
||||||
// Merge new address data into current cache
|
// Merge new address data into current cache
|
||||||
cache.merge_funded(outputs_result.address_data);
|
cache.merge_funded(outputs_result.addr_data);
|
||||||
cache.merge_funded(inputs_result.address_data);
|
cache.merge_funded(inputs_result.addr_data);
|
||||||
|
|
||||||
// Combine tx_index_vecs from outputs and inputs, then update tx_count
|
// Combine tx_index_vecs from outputs and inputs, then update tx_count
|
||||||
let combined_tx_index_vecs = outputs_result
|
let combined_tx_index_vecs = outputs_result
|
||||||
@@ -390,15 +390,15 @@ pub(crate) fn process_blocks(
|
|||||||
|
|
||||||
// Build set of addresses that received this block (for detecting "both" in sent)
|
// Build set of addresses that received this block (for detecting "both" in sent)
|
||||||
// Reuse pre-allocated hashsets: clear preserves capacity, avoiding reallocation
|
// Reuse pre-allocated hashsets: clear preserves capacity, avoiding reallocation
|
||||||
received_addresses.values_mut().for_each(|set| set.clear());
|
received_addrs.values_mut().for_each(|set| set.clear());
|
||||||
for (output_type, vec) in outputs_result.received_data.iter() {
|
for (output_type, vec) in outputs_result.received_data.iter() {
|
||||||
let set = received_addresses.get_mut_unwrap(output_type);
|
let set = received_addrs.get_mut_unwrap(output_type);
|
||||||
for (type_index, _) in vec {
|
for (type_index, _) in vec {
|
||||||
set.insert(*type_index);
|
set.insert(*type_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process UTXO cohorts and Address cohorts in parallel
|
// Process UTXO cohorts and Addr cohorts in parallel
|
||||||
let (_, addr_result) = rayon::join(
|
let (_, addr_result) = rayon::join(
|
||||||
|| {
|
|| {
|
||||||
// UTXO cohorts receive/send
|
// UTXO cohorts receive/send
|
||||||
@@ -418,25 +418,25 @@ pub(crate) fn process_blocks(
|
|||||||
// Process received outputs (addresses receiving funds)
|
// Process received outputs (addresses receiving funds)
|
||||||
process_received(
|
process_received(
|
||||||
outputs_result.received_data,
|
outputs_result.received_data,
|
||||||
&mut vecs.address_cohorts,
|
&mut vecs.addr_cohorts,
|
||||||
&mut lookup,
|
&mut lookup,
|
||||||
block_price,
|
block_price,
|
||||||
&mut address_counts,
|
&mut addr_counts,
|
||||||
&mut empty_address_counts,
|
&mut empty_addr_counts,
|
||||||
&mut activity_counts,
|
&mut activity_counts,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Process sent inputs (addresses sending funds)
|
// Process sent inputs (addresses sending funds)
|
||||||
process_sent(
|
process_sent(
|
||||||
inputs_result.sent_data,
|
inputs_result.sent_data,
|
||||||
&mut vecs.address_cohorts,
|
&mut vecs.addr_cohorts,
|
||||||
&mut lookup,
|
&mut lookup,
|
||||||
block_price,
|
block_price,
|
||||||
ctx.price_range_max,
|
ctx.price_range_max,
|
||||||
&mut address_counts,
|
&mut addr_counts,
|
||||||
&mut empty_address_counts,
|
&mut empty_addr_counts,
|
||||||
&mut activity_counts,
|
&mut activity_counts,
|
||||||
&received_addresses,
|
&received_addrs,
|
||||||
height_to_price_vec,
|
height_to_price_vec,
|
||||||
height_to_timestamp_vec,
|
height_to_timestamp_vec,
|
||||||
height,
|
height,
|
||||||
@@ -451,18 +451,18 @@ pub(crate) fn process_blocks(
|
|||||||
vecs.utxo_cohorts.update_fenwick_from_pending();
|
vecs.utxo_cohorts.update_fenwick_from_pending();
|
||||||
|
|
||||||
// Push to height-indexed vectors
|
// Push to height-indexed vectors
|
||||||
vecs.addresses.funded
|
vecs.addrs.funded
|
||||||
.push_height(address_counts.sum(), &address_counts);
|
.push_height(addr_counts.sum(), &addr_counts);
|
||||||
vecs.addresses.empty
|
vecs.addrs.empty
|
||||||
.push_height(empty_address_counts.sum(), &empty_address_counts);
|
.push_height(empty_addr_counts.sum(), &empty_addr_counts);
|
||||||
vecs.addresses.activity.push_height(&activity_counts);
|
vecs.addrs.activity.push_height(&activity_counts);
|
||||||
|
|
||||||
let is_last_of_day = is_last_of_day[offset];
|
let is_last_of_day = is_last_of_day[offset];
|
||||||
let date_opt = is_last_of_day.then(|| Date::from(timestamp));
|
let date_opt = is_last_of_day.then(|| Date::from(timestamp));
|
||||||
|
|
||||||
push_cohort_states(
|
push_cohort_states(
|
||||||
&mut vecs.utxo_cohorts,
|
&mut vecs.utxo_cohorts,
|
||||||
&mut vecs.address_cohorts,
|
&mut vecs.addr_cohorts,
|
||||||
height,
|
height,
|
||||||
block_price,
|
block_price,
|
||||||
);
|
);
|
||||||
@@ -484,9 +484,9 @@ pub(crate) fn process_blocks(
|
|||||||
let (empty_updates, funded_updates) = cache.take();
|
let (empty_updates, funded_updates) = cache.take();
|
||||||
|
|
||||||
// Process address updates (mutations)
|
// Process address updates (mutations)
|
||||||
process_address_updates(
|
process_addr_updates(
|
||||||
&mut vecs.addresses_data,
|
&mut vecs.addrs_data,
|
||||||
&mut vecs.any_address_indexes,
|
&mut vecs.any_addr_indexes,
|
||||||
empty_updates,
|
empty_updates,
|
||||||
funded_updates,
|
funded_updates,
|
||||||
)?;
|
)?;
|
||||||
@@ -499,7 +499,7 @@ pub(crate) fn process_blocks(
|
|||||||
vecs.flush()?;
|
vecs.flush()?;
|
||||||
|
|
||||||
// Recreate readers
|
// Recreate readers
|
||||||
vr = VecsReaders::new(&vecs.any_address_indexes, &vecs.addresses_data);
|
vr = VecsReaders::new(&vecs.any_addr_indexes, &vecs.addrs_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -511,9 +511,9 @@ pub(crate) fn process_blocks(
|
|||||||
let (empty_updates, funded_updates) = cache.take();
|
let (empty_updates, funded_updates) = cache.take();
|
||||||
|
|
||||||
// Process address updates (mutations)
|
// Process address updates (mutations)
|
||||||
process_address_updates(
|
process_addr_updates(
|
||||||
&mut vecs.addresses_data,
|
&mut vecs.addrs_data,
|
||||||
&mut vecs.any_address_indexes,
|
&mut vecs.any_addr_indexes,
|
||||||
empty_updates,
|
empty_updates,
|
||||||
funded_updates,
|
funded_updates,
|
||||||
)?;
|
)?;
|
||||||
@@ -527,7 +527,7 @@ pub(crate) fn process_blocks(
|
|||||||
/// Push cohort states to height-indexed vectors, then reset per-block values.
|
/// Push cohort states to height-indexed vectors, then reset per-block values.
|
||||||
fn push_cohort_states(
|
fn push_cohort_states(
|
||||||
utxo_cohorts: &mut UTXOCohorts,
|
utxo_cohorts: &mut UTXOCohorts,
|
||||||
address_cohorts: &mut AddressCohorts,
|
addr_cohorts: &mut AddrCohorts,
|
||||||
height: Height,
|
height: Height,
|
||||||
height_price: Cents,
|
height_price: Cents,
|
||||||
) {
|
) {
|
||||||
@@ -542,7 +542,7 @@ fn push_cohort_states(
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|| {
|
|| {
|
||||||
address_cohorts
|
addr_cohorts
|
||||||
.par_iter_separate_mut()
|
.par_iter_separate_mut()
|
||||||
.for_each(|v| {
|
.for_each(|v| {
|
||||||
v.push_state(height);
|
v.push_state(height);
|
||||||
@@ -558,7 +558,7 @@ fn push_cohort_states(
|
|||||||
utxo_cohorts
|
utxo_cohorts
|
||||||
.iter_separate_mut()
|
.iter_separate_mut()
|
||||||
.for_each(|v| v.reset_single_iteration_values());
|
.for_each(|v| v.reset_single_iteration_values());
|
||||||
address_cohorts
|
addr_cohorts
|
||||||
.iter_separate_mut()
|
.iter_separate_mut()
|
||||||
.for_each(|v| v.reset_single_iteration_values());
|
.for_each(|v| v.reset_single_iteration_values());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use brk_cohort::{ByAddressType, ByAnyAddress};
|
use brk_cohort::{ByAddrType, ByAnyAddr};
|
||||||
use brk_indexer::Indexer;
|
use brk_indexer::Indexer;
|
||||||
use brk_types::{Height, OutPoint, OutputType, Sats, StoredU64, TxIndex, TypeIndex};
|
use brk_types::{Height, OutPoint, OutputType, Sats, StoredU64, TxIndex, TypeIndex};
|
||||||
use vecdb::{ReadableVec, Reader, VecIndex};
|
use vecdb::{ReadableVec, Reader, VecIndex};
|
||||||
@@ -6,7 +6,7 @@ use vecdb::{ReadableVec, Reader, VecIndex};
|
|||||||
use crate::{
|
use crate::{
|
||||||
distribution::{
|
distribution::{
|
||||||
RangeMap,
|
RangeMap,
|
||||||
address::{AddressesDataVecs, AnyAddressIndexesVecs},
|
addr::{AddrsDataVecs, AnyAddrIndexesVecs},
|
||||||
},
|
},
|
||||||
inputs,
|
inputs,
|
||||||
};
|
};
|
||||||
@@ -161,37 +161,37 @@ impl<'a> TxInReaders<'a> {
|
|||||||
|
|
||||||
/// Cached readers for stateful vectors.
|
/// Cached readers for stateful vectors.
|
||||||
pub struct VecsReaders {
|
pub struct VecsReaders {
|
||||||
pub address_type_index_to_any_address_index: ByAddressType<Reader>,
|
pub addr_type_index_to_any_addr_index: ByAddrType<Reader>,
|
||||||
pub any_address_index_to_any_address_data: ByAnyAddress<Reader>,
|
pub any_addr_index_to_any_addr_data: ByAnyAddr<Reader>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VecsReaders {
|
impl VecsReaders {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
any_address_indexes: &AnyAddressIndexesVecs,
|
any_addr_indexes: &AnyAddrIndexesVecs,
|
||||||
addresses_data: &AddressesDataVecs,
|
addrs_data: &AddrsDataVecs,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
address_type_index_to_any_address_index: ByAddressType {
|
addr_type_index_to_any_addr_index: ByAddrType {
|
||||||
p2a: any_address_indexes.p2a.create_reader(),
|
p2a: any_addr_indexes.p2a.create_reader(),
|
||||||
p2pk33: any_address_indexes.p2pk33.create_reader(),
|
p2pk33: any_addr_indexes.p2pk33.create_reader(),
|
||||||
p2pk65: any_address_indexes.p2pk65.create_reader(),
|
p2pk65: any_addr_indexes.p2pk65.create_reader(),
|
||||||
p2pkh: any_address_indexes.p2pkh.create_reader(),
|
p2pkh: any_addr_indexes.p2pkh.create_reader(),
|
||||||
p2sh: any_address_indexes.p2sh.create_reader(),
|
p2sh: any_addr_indexes.p2sh.create_reader(),
|
||||||
p2tr: any_address_indexes.p2tr.create_reader(),
|
p2tr: any_addr_indexes.p2tr.create_reader(),
|
||||||
p2wpkh: any_address_indexes.p2wpkh.create_reader(),
|
p2wpkh: any_addr_indexes.p2wpkh.create_reader(),
|
||||||
p2wsh: any_address_indexes.p2wsh.create_reader(),
|
p2wsh: any_addr_indexes.p2wsh.create_reader(),
|
||||||
},
|
},
|
||||||
any_address_index_to_any_address_data: ByAnyAddress {
|
any_addr_index_to_any_addr_data: ByAnyAddr {
|
||||||
funded: addresses_data.funded.create_reader(),
|
funded: addrs_data.funded.create_reader(),
|
||||||
empty: addresses_data.empty.create_reader(),
|
empty: addrs_data.empty.create_reader(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get reader for specific address type.
|
/// Get reader for specific address type.
|
||||||
pub(crate) fn address_reader(&self, address_type: OutputType) -> &Reader {
|
pub(crate) fn addr_reader(&self, addr_type: OutputType) -> &Reader {
|
||||||
self.address_type_index_to_any_address_index
|
self.addr_type_index_to_any_addr_index
|
||||||
.get(address_type)
|
.get(addr_type)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ use tracing::{debug, warn};
|
|||||||
use vecdb::Stamp;
|
use vecdb::Stamp;
|
||||||
|
|
||||||
use super::super::{
|
use super::super::{
|
||||||
AddressesDataVecs,
|
AddrsDataVecs,
|
||||||
address::AnyAddressIndexesVecs,
|
addr::AnyAddrIndexesVecs,
|
||||||
cohorts::{AddressCohorts, UTXOCohorts},
|
cohorts::{AddrCohorts, UTXOCohorts},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Result of state recovery.
|
/// Result of state recovery.
|
||||||
@@ -25,22 +25,22 @@ pub struct RecoveredState {
|
|||||||
pub(crate) fn recover_state(
|
pub(crate) fn recover_state(
|
||||||
height: Height,
|
height: Height,
|
||||||
chain_state_rollback: vecdb::Result<Stamp>,
|
chain_state_rollback: vecdb::Result<Stamp>,
|
||||||
any_address_indexes: &mut AnyAddressIndexesVecs,
|
any_addr_indexes: &mut AnyAddrIndexesVecs,
|
||||||
addresses_data: &mut AddressesDataVecs,
|
addrs_data: &mut AddrsDataVecs,
|
||||||
utxo_cohorts: &mut UTXOCohorts,
|
utxo_cohorts: &mut UTXOCohorts,
|
||||||
address_cohorts: &mut AddressCohorts,
|
addr_cohorts: &mut AddrCohorts,
|
||||||
) -> Result<RecoveredState> {
|
) -> Result<RecoveredState> {
|
||||||
let stamp = Stamp::from(height);
|
let stamp = Stamp::from(height);
|
||||||
|
|
||||||
// Rollback address state vectors
|
// Rollback address state vectors
|
||||||
let address_indexes_rollback = any_address_indexes.rollback_before(stamp);
|
let addr_indexes_rollback = any_addr_indexes.rollback_before(stamp);
|
||||||
let address_data_rollback = addresses_data.rollback_before(stamp);
|
let addr_data_rollback = addrs_data.rollback_before(stamp);
|
||||||
|
|
||||||
// Verify rollback consistency - all must agree on the same height
|
// Verify rollback consistency - all must agree on the same height
|
||||||
let consistent_height = rollback_states(
|
let consistent_height = rollback_states(
|
||||||
chain_state_rollback,
|
chain_state_rollback,
|
||||||
address_indexes_rollback,
|
addr_indexes_rollback,
|
||||||
address_data_rollback,
|
addr_data_rollback,
|
||||||
);
|
);
|
||||||
|
|
||||||
// If rollbacks are inconsistent, start fresh
|
// If rollbacks are inconsistent, start fresh
|
||||||
@@ -88,19 +88,19 @@ pub(crate) fn recover_state(
|
|||||||
|
|
||||||
// Import address cohort states - all must succeed
|
// Import address cohort states - all must succeed
|
||||||
debug!(
|
debug!(
|
||||||
"importing address cohort states at height {}",
|
"importing addr cohort states at height {}",
|
||||||
consistent_height
|
consistent_height
|
||||||
);
|
);
|
||||||
if !address_cohorts.import_separate_states(consistent_height) {
|
if !addr_cohorts.import_separate_states(consistent_height) {
|
||||||
warn!(
|
warn!(
|
||||||
"Address cohort state import failed at height {}",
|
"Addr cohort state import failed at height {}",
|
||||||
consistent_height
|
consistent_height
|
||||||
);
|
);
|
||||||
return Ok(RecoveredState {
|
return Ok(RecoveredState {
|
||||||
starting_height: Height::ZERO,
|
starting_height: Height::ZERO,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
debug!("address cohort states imported");
|
debug!("addr cohort states imported");
|
||||||
|
|
||||||
Ok(RecoveredState {
|
Ok(RecoveredState {
|
||||||
starting_height: consistent_height,
|
starting_height: consistent_height,
|
||||||
@@ -111,22 +111,22 @@ pub(crate) fn recover_state(
|
|||||||
///
|
///
|
||||||
/// Resets all state vectors and cohort states.
|
/// Resets all state vectors and cohort states.
|
||||||
pub(crate) fn reset_state(
|
pub(crate) fn reset_state(
|
||||||
any_address_indexes: &mut AnyAddressIndexesVecs,
|
any_addr_indexes: &mut AnyAddrIndexesVecs,
|
||||||
addresses_data: &mut AddressesDataVecs,
|
addrs_data: &mut AddrsDataVecs,
|
||||||
utxo_cohorts: &mut UTXOCohorts,
|
utxo_cohorts: &mut UTXOCohorts,
|
||||||
address_cohorts: &mut AddressCohorts,
|
addr_cohorts: &mut AddrCohorts,
|
||||||
) -> Result<RecoveredState> {
|
) -> Result<RecoveredState> {
|
||||||
// Reset address state
|
// Reset address state
|
||||||
any_address_indexes.reset()?;
|
any_addr_indexes.reset()?;
|
||||||
addresses_data.reset()?;
|
addrs_data.reset()?;
|
||||||
|
|
||||||
// Reset cohort state heights
|
// Reset cohort state heights
|
||||||
utxo_cohorts.reset_separate_state_heights();
|
utxo_cohorts.reset_separate_state_heights();
|
||||||
address_cohorts.reset_separate_state_heights();
|
addr_cohorts.reset_separate_state_heights();
|
||||||
|
|
||||||
// Reset cost_basis_data for all cohorts
|
// Reset cost_basis_data for all cohorts
|
||||||
utxo_cohorts.reset_separate_cost_basis_data()?;
|
utxo_cohorts.reset_separate_cost_basis_data()?;
|
||||||
address_cohorts.reset_separate_cost_basis_data()?;
|
addr_cohorts.reset_separate_cost_basis_data()?;
|
||||||
|
|
||||||
Ok(RecoveredState {
|
Ok(RecoveredState {
|
||||||
starting_height: Height::ZERO,
|
starting_height: Height::ZERO,
|
||||||
@@ -164,8 +164,8 @@ pub enum StartMode {
|
|||||||
/// otherwise returns Height::ZERO (need fresh start).
|
/// otherwise returns Height::ZERO (need fresh start).
|
||||||
fn rollback_states(
|
fn rollback_states(
|
||||||
chain_state_rollback: vecdb::Result<Stamp>,
|
chain_state_rollback: vecdb::Result<Stamp>,
|
||||||
address_indexes_rollbacks: Result<Vec<Stamp>>,
|
addr_indexes_rollbacks: Result<Vec<Stamp>>,
|
||||||
address_data_rollbacks: Result<[Stamp; 2]>,
|
addr_data_rollbacks: Result<[Stamp; 2]>,
|
||||||
) -> Height {
|
) -> Height {
|
||||||
let mut heights: BTreeSet<Height> = BTreeSet::new();
|
let mut heights: BTreeSet<Height> = BTreeSet::new();
|
||||||
|
|
||||||
@@ -181,30 +181,30 @@ fn rollback_states(
|
|||||||
);
|
);
|
||||||
heights.insert(chain_height);
|
heights.insert(chain_height);
|
||||||
|
|
||||||
let Ok(stamps) = address_indexes_rollbacks else {
|
let Ok(stamps) = addr_indexes_rollbacks else {
|
||||||
warn!(
|
warn!(
|
||||||
"address_indexes rollback failed: {:?}",
|
"addr_indexes rollback failed: {:?}",
|
||||||
address_indexes_rollbacks
|
addr_indexes_rollbacks
|
||||||
);
|
);
|
||||||
return Height::ZERO;
|
return Height::ZERO;
|
||||||
};
|
};
|
||||||
for (i, s) in stamps.iter().enumerate() {
|
for (i, s) in stamps.iter().enumerate() {
|
||||||
let h = Height::from(*s).incremented();
|
let h = Height::from(*s).incremented();
|
||||||
debug!(
|
debug!(
|
||||||
"address_indexes[{}] rolled back to stamp {:?}, height {}",
|
"addr_indexes[{}] rolled back to stamp {:?}, height {}",
|
||||||
i, s, h
|
i, s, h
|
||||||
);
|
);
|
||||||
heights.insert(h);
|
heights.insert(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
let Ok(stamps) = address_data_rollbacks else {
|
let Ok(stamps) = addr_data_rollbacks else {
|
||||||
warn!("address_data rollback failed: {:?}", address_data_rollbacks);
|
warn!("addr_data rollback failed: {:?}", addr_data_rollbacks);
|
||||||
return Height::ZERO;
|
return Height::ZERO;
|
||||||
};
|
};
|
||||||
for (i, s) in stamps.iter().enumerate() {
|
for (i, s) in stamps.iter().enumerate() {
|
||||||
let h = Height::from(*s).incremented();
|
let h = Height::from(*s).incremented();
|
||||||
debug!(
|
debug!(
|
||||||
"address_data[{}] rolled back to stamp {:?}, height {}",
|
"addr_data[{}] rolled back to stamp {:?}, height {}",
|
||||||
i, s, h
|
i, s, h
|
||||||
);
|
);
|
||||||
heights.insert(h);
|
heights.insert(h);
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use brk_error::Result;
|
use brk_error::Result;
|
||||||
use brk_types::{EmptyAddressData, FundedAddressData, Height};
|
use brk_types::{EmptyAddrData, FundedAddrData, Height};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
use vecdb::{AnyStoredVec, AnyVec, Stamp, VecIndex, WritableVec};
|
use vecdb::{AnyStoredVec, AnyVec, Stamp, VecIndex, WritableVec};
|
||||||
|
|
||||||
use crate::distribution::{
|
use crate::distribution::{
|
||||||
Vecs,
|
Vecs,
|
||||||
block::{WithAddressDataSource, process_empty_addresses, process_funded_addresses},
|
block::{WithAddrDataSource, process_empty_addrs, process_funded_addrs},
|
||||||
state::BlockState,
|
state::BlockState,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::super::address::{AddressTypeToTypeIndexMap, AddressesDataVecs, AnyAddressIndexesVecs};
|
use super::super::addr::{AddrTypeToTypeIndexMap, AddrsDataVecs, AnyAddrIndexesVecs};
|
||||||
|
|
||||||
/// Process address updates from caches.
|
/// Process address updates from caches.
|
||||||
///
|
///
|
||||||
@@ -22,20 +22,20 @@ use super::super::address::{AddressTypeToTypeIndexMap, AddressesDataVecs, AnyAdd
|
|||||||
/// - Updates address indexes
|
/// - Updates address indexes
|
||||||
///
|
///
|
||||||
/// Call this before `flush()` to prepare data for writing.
|
/// Call this before `flush()` to prepare data for writing.
|
||||||
pub(crate) fn process_address_updates(
|
pub(crate) fn process_addr_updates(
|
||||||
addresses_data: &mut AddressesDataVecs,
|
addrs_data: &mut AddrsDataVecs,
|
||||||
address_indexes: &mut AnyAddressIndexesVecs,
|
addr_indexes: &mut AnyAddrIndexesVecs,
|
||||||
empty_updates: AddressTypeToTypeIndexMap<WithAddressDataSource<EmptyAddressData>>,
|
empty_updates: AddrTypeToTypeIndexMap<WithAddrDataSource<EmptyAddrData>>,
|
||||||
funded_updates: AddressTypeToTypeIndexMap<WithAddressDataSource<FundedAddressData>>,
|
funded_updates: AddrTypeToTypeIndexMap<WithAddrDataSource<FundedAddrData>>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
info!("Processing address updates...");
|
info!("Processing addr updates...");
|
||||||
|
|
||||||
let i = Instant::now();
|
let i = Instant::now();
|
||||||
let empty_result = process_empty_addresses(addresses_data, empty_updates)?;
|
let empty_result = process_empty_addrs(addrs_data, empty_updates)?;
|
||||||
let funded_result = process_funded_addresses(addresses_data, funded_updates)?;
|
let funded_result = process_funded_addrs(addrs_data, funded_updates)?;
|
||||||
address_indexes.par_batch_update(empty_result, funded_result)?;
|
addr_indexes.par_batch_update(empty_result, funded_result)?;
|
||||||
|
|
||||||
info!("Processed address updates in {:?}", i.elapsed());
|
info!("Processed addr updates in {:?}", i.elapsed());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -73,12 +73,12 @@ pub(crate) fn write(
|
|||||||
vecs.supply_state.push(block_state.supply);
|
vecs.supply_state.push(block_state.supply);
|
||||||
}
|
}
|
||||||
|
|
||||||
vecs.any_address_indexes
|
vecs.any_addr_indexes
|
||||||
.par_iter_mut()
|
.par_iter_mut()
|
||||||
.chain(vecs.addresses_data.par_iter_mut())
|
.chain(vecs.addrs_data.par_iter_mut())
|
||||||
.chain(vecs.addresses.funded.par_iter_height_mut())
|
.chain(vecs.addrs.funded.par_iter_height_mut())
|
||||||
.chain(vecs.addresses.empty.par_iter_height_mut())
|
.chain(vecs.addrs.empty.par_iter_height_mut())
|
||||||
.chain(vecs.addresses.activity.par_iter_height_mut())
|
.chain(vecs.addrs.activity.par_iter_height_mut())
|
||||||
.chain(
|
.chain(
|
||||||
[
|
[
|
||||||
&mut vecs.supply_state as &mut dyn AnyStoredVec,
|
&mut vecs.supply_state as &mut dyn AnyStoredVec,
|
||||||
@@ -87,13 +87,13 @@ pub(crate) fn write(
|
|||||||
.into_par_iter(),
|
.into_par_iter(),
|
||||||
)
|
)
|
||||||
.chain(vecs.utxo_cohorts.par_iter_vecs_mut())
|
.chain(vecs.utxo_cohorts.par_iter_vecs_mut())
|
||||||
.chain(vecs.address_cohorts.par_iter_vecs_mut())
|
.chain(vecs.addr_cohorts.par_iter_vecs_mut())
|
||||||
.try_for_each(|v| v.any_stamped_write_maybe_with_changes(stamp, with_changes))?;
|
.try_for_each(|v| v.any_stamped_write_maybe_with_changes(stamp, with_changes))?;
|
||||||
|
|
||||||
// Commit states after vec writes
|
// Commit states after vec writes
|
||||||
let cleanup = with_changes;
|
let cleanup = with_changes;
|
||||||
vecs.utxo_cohorts.commit_all_states(height, cleanup)?;
|
vecs.utxo_cohorts.commit_all_states(height, cleanup)?;
|
||||||
vecs.address_cohorts.commit_all_states(height, cleanup)?;
|
vecs.addr_cohorts.commit_all_states(height, cleanup)?;
|
||||||
|
|
||||||
info!("Wrote in {:?}", i.elapsed());
|
info!("Wrote in {:?}", i.elapsed());
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
pub mod address;
|
pub mod addr;
|
||||||
mod block;
|
mod block;
|
||||||
pub mod cohorts;
|
pub mod cohorts;
|
||||||
pub mod compute;
|
pub mod compute;
|
||||||
@@ -11,5 +11,5 @@ pub use vecs::Vecs;
|
|||||||
|
|
||||||
pub const DB_NAME: &str = "distribution";
|
pub const DB_NAME: &str = "distribution";
|
||||||
|
|
||||||
pub use address::{AddressTypeToTypeIndexMap, AddressesDataVecs, AnyAddressIndexesVecs};
|
pub use addr::{AddrTypeToTypeIndexMap, AddrsDataVecs, AnyAddrIndexesVecs};
|
||||||
pub use cohorts::{AddressCohorts, DynCohortVecs, UTXOCohorts};
|
pub use cohorts::{AddrCohorts, DynCohortVecs, UTXOCohorts};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use brk_error::Result;
|
use brk_error::Result;
|
||||||
use brk_types::{Age, Cents, FundedAddressData, Sats, SupplyState};
|
use brk_types::{Age, Cents, FundedAddrData, Sats, SupplyState};
|
||||||
use vecdb::unlikely;
|
use vecdb::unlikely;
|
||||||
|
|
||||||
use super::super::cost_basis::{CostBasisRaw, RealizedOps};
|
use super::super::cost_basis::{CostBasisRaw, RealizedOps};
|
||||||
@@ -10,22 +10,22 @@ use super::base::CohortState;
|
|||||||
/// Significant digits for address cost basis prices (after rounding to dollars).
|
/// Significant digits for address cost basis prices (after rounding to dollars).
|
||||||
const COST_BASIS_PRICE_DIGITS: i32 = 4;
|
const COST_BASIS_PRICE_DIGITS: i32 = 4;
|
||||||
|
|
||||||
pub struct AddressCohortState<R: RealizedOps> {
|
pub struct AddrCohortState<R: RealizedOps> {
|
||||||
pub address_count: u64,
|
pub addr_count: u64,
|
||||||
pub inner: CohortState<R, CostBasisRaw>,
|
pub inner: CohortState<R, CostBasisRaw>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: RealizedOps> AddressCohortState<R> {
|
impl<R: RealizedOps> AddrCohortState<R> {
|
||||||
pub(crate) fn new(path: &Path, name: &str) -> Self {
|
pub(crate) fn new(path: &Path, name: &str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
address_count: 0,
|
addr_count: 0,
|
||||||
inner: CohortState::new(path, name).with_price_rounding(COST_BASIS_PRICE_DIGITS),
|
inner: CohortState::new(path, name).with_price_rounding(COST_BASIS_PRICE_DIGITS),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reset state for fresh start.
|
/// Reset state for fresh start.
|
||||||
pub(crate) fn reset(&mut self) {
|
pub(crate) fn reset(&mut self) {
|
||||||
self.address_count = 0;
|
self.addr_count = 0;
|
||||||
self.inner.supply = SupplyState::default();
|
self.inner.supply = SupplyState::default();
|
||||||
self.inner.sent = Sats::ZERO;
|
self.inner.sent = Sats::ZERO;
|
||||||
self.inner.satdays_destroyed = Sats::ZERO;
|
self.inner.satdays_destroyed = Sats::ZERO;
|
||||||
@@ -34,18 +34,18 @@ impl<R: RealizedOps> AddressCohortState<R> {
|
|||||||
|
|
||||||
pub(crate) fn send(
|
pub(crate) fn send(
|
||||||
&mut self,
|
&mut self,
|
||||||
address_data: &mut FundedAddressData,
|
addr_data: &mut FundedAddrData,
|
||||||
value: Sats,
|
value: Sats,
|
||||||
current_price: Cents,
|
current_price: Cents,
|
||||||
prev_price: Cents,
|
prev_price: Cents,
|
||||||
ath: Cents,
|
ath: Cents,
|
||||||
age: Age,
|
age: Age,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let prev = address_data.cost_basis_snapshot();
|
let prev = addr_data.cost_basis_snapshot();
|
||||||
address_data.send(value, prev_price)?;
|
addr_data.send(value, prev_price)?;
|
||||||
let current = address_data.cost_basis_snapshot();
|
let current = addr_data.cost_basis_snapshot();
|
||||||
|
|
||||||
self.inner.send_address(
|
self.inner.send_addr(
|
||||||
&SupplyState {
|
&SupplyState {
|
||||||
utxo_count: 1,
|
utxo_count: 1,
|
||||||
value,
|
value,
|
||||||
@@ -63,16 +63,16 @@ impl<R: RealizedOps> AddressCohortState<R> {
|
|||||||
|
|
||||||
pub(crate) fn receive_outputs(
|
pub(crate) fn receive_outputs(
|
||||||
&mut self,
|
&mut self,
|
||||||
address_data: &mut FundedAddressData,
|
addr_data: &mut FundedAddrData,
|
||||||
value: Sats,
|
value: Sats,
|
||||||
price: Cents,
|
price: Cents,
|
||||||
output_count: u32,
|
output_count: u32,
|
||||||
) {
|
) {
|
||||||
let prev = address_data.cost_basis_snapshot();
|
let prev = addr_data.cost_basis_snapshot();
|
||||||
address_data.receive_outputs(value, price, output_count);
|
addr_data.receive_outputs(value, price, output_count);
|
||||||
let current = address_data.cost_basis_snapshot();
|
let current = addr_data.cost_basis_snapshot();
|
||||||
|
|
||||||
self.inner.receive_address(
|
self.inner.receive_addr(
|
||||||
&SupplyState {
|
&SupplyState {
|
||||||
utxo_count: output_count as u64,
|
utxo_count: output_count as u64,
|
||||||
value,
|
value,
|
||||||
@@ -83,53 +83,53 @@ impl<R: RealizedOps> AddressCohortState<R> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add(&mut self, address_data: &FundedAddressData) {
|
pub(crate) fn add(&mut self, addr_data: &FundedAddrData) {
|
||||||
self.address_count += 1;
|
self.addr_count += 1;
|
||||||
self.inner
|
self.inner
|
||||||
.increment_snapshot(&address_data.cost_basis_snapshot());
|
.increment_snapshot(&addr_data.cost_basis_snapshot());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn subtract(&mut self, address_data: &FundedAddressData) {
|
pub(crate) fn subtract(&mut self, addr_data: &FundedAddrData) {
|
||||||
let snapshot = address_data.cost_basis_snapshot();
|
let snapshot = addr_data.cost_basis_snapshot();
|
||||||
|
|
||||||
// Check for potential underflow before it happens
|
// Check for potential underflow before it happens
|
||||||
if unlikely(self.inner.supply.utxo_count < snapshot.supply_state.utxo_count) {
|
if unlikely(self.inner.supply.utxo_count < snapshot.supply_state.utxo_count) {
|
||||||
panic!(
|
panic!(
|
||||||
"AddressCohortState::subtract underflow!\n\
|
"AddrCohortState::subtract underflow!\n\
|
||||||
Cohort state: address_count={}, supply={}\n\
|
Cohort state: addr_count={}, supply={}\n\
|
||||||
Address being subtracted: {}\n\
|
Addr being subtracted: {}\n\
|
||||||
Address supply: {}\n\
|
Addr supply: {}\n\
|
||||||
Realized price: {}\n\
|
Realized price: {}\n\
|
||||||
This means the address is not properly tracked in this cohort.",
|
This means the addr is not properly tracked in this cohort.",
|
||||||
self.address_count,
|
self.addr_count,
|
||||||
self.inner.supply,
|
self.inner.supply,
|
||||||
address_data,
|
addr_data,
|
||||||
snapshot.supply_state,
|
snapshot.supply_state,
|
||||||
snapshot.realized_price
|
snapshot.realized_price
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if unlikely(self.inner.supply.value < snapshot.supply_state.value) {
|
if unlikely(self.inner.supply.value < snapshot.supply_state.value) {
|
||||||
panic!(
|
panic!(
|
||||||
"AddressCohortState::subtract value underflow!\n\
|
"AddrCohortState::subtract value underflow!\n\
|
||||||
Cohort state: address_count={}, supply={}\n\
|
Cohort state: addr_count={}, supply={}\n\
|
||||||
Address being subtracted: {}\n\
|
Addr being subtracted: {}\n\
|
||||||
Address supply: {}\n\
|
Addr supply: {}\n\
|
||||||
Realized price: {}\n\
|
Realized price: {}\n\
|
||||||
This means the address is not properly tracked in this cohort.",
|
This means the addr is not properly tracked in this cohort.",
|
||||||
self.address_count,
|
self.addr_count,
|
||||||
self.inner.supply,
|
self.inner.supply,
|
||||||
address_data,
|
addr_data,
|
||||||
snapshot.supply_state,
|
snapshot.supply_state,
|
||||||
snapshot.realized_price
|
snapshot.realized_price
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.address_count = self.address_count.checked_sub(1).unwrap_or_else(|| {
|
self.addr_count = self.addr_count.checked_sub(1).unwrap_or_else(|| {
|
||||||
panic!(
|
panic!(
|
||||||
"AddressCohortState::subtract address_count underflow! address_count=0\n\
|
"AddrCohortState::subtract addr_count underflow! addr_count=0\n\
|
||||||
Address being subtracted: {}\n\
|
Addr being subtracted: {}\n\
|
||||||
Realized price: {}",
|
Realized price: {}",
|
||||||
address_data, snapshot.realized_price
|
addr_data, snapshot.realized_price
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -158,7 +158,7 @@ impl<R: RealizedOps, C: CostBasisOps> CohortState<R, C> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn receive_address(
|
pub(crate) fn receive_addr(
|
||||||
&mut self,
|
&mut self,
|
||||||
supply: &SupplyState,
|
supply: &SupplyState,
|
||||||
price: Cents,
|
price: Cents,
|
||||||
@@ -224,7 +224,7 @@ impl<R: RealizedOps, C: CostBasisOps> CohortState<R, C> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(crate) fn send_address(
|
pub(crate) fn send_addr(
|
||||||
&mut self,
|
&mut self,
|
||||||
supply: &SupplyState,
|
supply: &SupplyState,
|
||||||
current_price: Cents,
|
current_price: Cents,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
mod address;
|
mod addr;
|
||||||
mod base;
|
mod base;
|
||||||
mod utxo;
|
mod utxo;
|
||||||
|
|
||||||
pub use address::*;
|
pub use addr::*;
|
||||||
pub use base::*;
|
pub use base::*;
|
||||||
pub use utxo::*;
|
pub use utxo::*;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use brk_error::Result;
|
|||||||
use brk_indexer::Indexer;
|
use brk_indexer::Indexer;
|
||||||
use brk_traversable::Traversable;
|
use brk_traversable::Traversable;
|
||||||
use brk_types::{
|
use brk_types::{
|
||||||
Cents, EmptyAddressData, EmptyAddressIndex, FundedAddressData, FundedAddressIndex, Height,
|
Cents, EmptyAddrData, EmptyAddrIndex, FundedAddrData, FundedAddrIndex, Height,
|
||||||
Indexes, StoredF64, SupplyState, Timestamp, TxIndex, Version,
|
Indexes, StoredF64, SupplyState, Timestamp, TxIndex, Version,
|
||||||
};
|
};
|
||||||
use tracing::{debug, info};
|
use tracing::{debug, info};
|
||||||
@@ -28,28 +28,28 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
AddressCohorts, AddressesDataVecs, AnyAddressIndexesVecs, RangeMap, UTXOCohorts,
|
AddrCohorts, AddrsDataVecs, AnyAddrIndexesVecs, RangeMap, UTXOCohorts,
|
||||||
address::{
|
addr::{
|
||||||
AddressCountsVecs, AddressActivityVecs, DeltaVecs, NewAddressCountVecs, TotalAddressCountVecs,
|
AddrCountsVecs, AddrActivityVecs, DeltaVecs, NewAddrCountVecs, TotalAddrCountVecs,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const VERSION: Version = Version::new(22);
|
const VERSION: Version = Version::new(22);
|
||||||
|
|
||||||
#[derive(Traversable)]
|
#[derive(Traversable)]
|
||||||
pub struct AddressMetricsVecs<M: StorageMode = Rw> {
|
pub struct AddrMetricsVecs<M: StorageMode = Rw> {
|
||||||
pub funded: AddressCountsVecs<M>,
|
pub funded: AddrCountsVecs<M>,
|
||||||
pub empty: AddressCountsVecs<M>,
|
pub empty: AddrCountsVecs<M>,
|
||||||
pub activity: AddressActivityVecs<M>,
|
pub activity: AddrActivityVecs<M>,
|
||||||
pub total: TotalAddressCountVecs<M>,
|
pub total: TotalAddrCountVecs<M>,
|
||||||
pub new: NewAddressCountVecs<M>,
|
pub new: NewAddrCountVecs<M>,
|
||||||
pub delta: DeltaVecs,
|
pub delta: DeltaVecs,
|
||||||
#[traversable(wrap = "indexes", rename = "funded")]
|
#[traversable(wrap = "indexes", rename = "funded")]
|
||||||
pub funded_index:
|
pub funded_index:
|
||||||
LazyVecFrom1<FundedAddressIndex, FundedAddressIndex, FundedAddressIndex, FundedAddressData>,
|
LazyVecFrom1<FundedAddrIndex, FundedAddrIndex, FundedAddrIndex, FundedAddrData>,
|
||||||
#[traversable(wrap = "indexes", rename = "empty")]
|
#[traversable(wrap = "indexes", rename = "empty")]
|
||||||
pub empty_index:
|
pub empty_index:
|
||||||
LazyVecFrom1<EmptyAddressIndex, EmptyAddressIndex, EmptyAddressIndex, EmptyAddressData>,
|
LazyVecFrom1<EmptyAddrIndex, EmptyAddrIndex, EmptyAddrIndex, EmptyAddrData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Traversable)]
|
#[derive(Traversable)]
|
||||||
@@ -61,17 +61,17 @@ pub struct Vecs<M: StorageMode = Rw> {
|
|||||||
|
|
||||||
#[traversable(wrap = "supply", rename = "state")]
|
#[traversable(wrap = "supply", rename = "state")]
|
||||||
pub supply_state: M::Stored<BytesVec<Height, SupplyState>>,
|
pub supply_state: M::Stored<BytesVec<Height, SupplyState>>,
|
||||||
#[traversable(wrap = "addresses", rename = "indexes")]
|
#[traversable(wrap = "addrs", rename = "indexes")]
|
||||||
pub any_address_indexes: AnyAddressIndexesVecs<M>,
|
pub any_addr_indexes: AnyAddrIndexesVecs<M>,
|
||||||
#[traversable(wrap = "addresses", rename = "data")]
|
#[traversable(wrap = "addrs", rename = "data")]
|
||||||
pub addresses_data: AddressesDataVecs<M>,
|
pub addrs_data: AddrsDataVecs<M>,
|
||||||
#[traversable(wrap = "cohorts", rename = "utxo")]
|
#[traversable(wrap = "cohorts", rename = "utxo")]
|
||||||
pub utxo_cohorts: UTXOCohorts<M>,
|
pub utxo_cohorts: UTXOCohorts<M>,
|
||||||
#[traversable(wrap = "cohorts", rename = "address")]
|
#[traversable(wrap = "cohorts", rename = "addr")]
|
||||||
pub address_cohorts: AddressCohorts<M>,
|
pub addr_cohorts: AddrCohorts<M>,
|
||||||
#[traversable(wrap = "cointime/activity")]
|
#[traversable(wrap = "cointime/activity")]
|
||||||
pub coinblocks_destroyed: PerBlockCumulativeWithSums<StoredF64, StoredF64, M>,
|
pub coinblocks_destroyed: PerBlockCumulativeWithSums<StoredF64, StoredF64, M>,
|
||||||
pub addresses: AddressMetricsVecs<M>,
|
pub addrs: AddrMetricsVecs<M>,
|
||||||
|
|
||||||
/// In-memory block state for UTXO processing. Persisted via supply_state.
|
/// In-memory block state for UTXO processing. Persisted via supply_state.
|
||||||
/// Kept across compute() calls to avoid O(n) rebuild on resume.
|
/// Kept across compute() calls to avoid O(n) rebuild on resume.
|
||||||
@@ -111,47 +111,47 @@ impl Vecs {
|
|||||||
|
|
||||||
let utxo_cohorts = UTXOCohorts::forced_import(&db, version, indexes, &states_path, cached_starts)?;
|
let utxo_cohorts = UTXOCohorts::forced_import(&db, version, indexes, &states_path, cached_starts)?;
|
||||||
|
|
||||||
let address_cohorts = AddressCohorts::forced_import(&db, version, indexes, &states_path, cached_starts)?;
|
let addr_cohorts = AddrCohorts::forced_import(&db, version, indexes, &states_path, cached_starts)?;
|
||||||
|
|
||||||
// Create address data BytesVecs first so we can also use them for identity mappings
|
// Create address data BytesVecs first so we can also use them for identity mappings
|
||||||
let funded_address_index_to_funded_address_data = BytesVec::forced_import_with(
|
let funded_addr_index_to_funded_addr_data = BytesVec::forced_import_with(
|
||||||
vecdb::ImportOptions::new(&db, "funded_address_data", version)
|
vecdb::ImportOptions::new(&db, "funded_addr_data", version)
|
||||||
.with_saved_stamped_changes(SAVED_STAMPED_CHANGES),
|
.with_saved_stamped_changes(SAVED_STAMPED_CHANGES),
|
||||||
)?;
|
)?;
|
||||||
let empty_address_index_to_empty_address_data = BytesVec::forced_import_with(
|
let empty_addr_index_to_empty_addr_data = BytesVec::forced_import_with(
|
||||||
vecdb::ImportOptions::new(&db, "empty_address_data", version)
|
vecdb::ImportOptions::new(&db, "empty_addr_data", version)
|
||||||
.with_saved_stamped_changes(SAVED_STAMPED_CHANGES),
|
.with_saved_stamped_changes(SAVED_STAMPED_CHANGES),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Identity mappings for traversable
|
// Identity mappings for traversable
|
||||||
let funded_address_index = LazyVecFrom1::init(
|
let funded_addr_index = LazyVecFrom1::init(
|
||||||
"funded_address_index",
|
"funded_addr_index",
|
||||||
version,
|
version,
|
||||||
funded_address_index_to_funded_address_data.read_only_boxed_clone(),
|
funded_addr_index_to_funded_addr_data.read_only_boxed_clone(),
|
||||||
|index, _| index,
|
|index, _| index,
|
||||||
);
|
);
|
||||||
let empty_address_index = LazyVecFrom1::init(
|
let empty_addr_index = LazyVecFrom1::init(
|
||||||
"empty_address_index",
|
"empty_addr_index",
|
||||||
version,
|
version,
|
||||||
empty_address_index_to_empty_address_data.read_only_boxed_clone(),
|
empty_addr_index_to_empty_addr_data.read_only_boxed_clone(),
|
||||||
|index, _| index,
|
|index, _| index,
|
||||||
);
|
);
|
||||||
|
|
||||||
let address_count = AddressCountsVecs::forced_import(&db, "address_count", version, indexes)?;
|
let addr_count = AddrCountsVecs::forced_import(&db, "addr_count", version, indexes)?;
|
||||||
let empty_address_count =
|
let empty_addr_count =
|
||||||
AddressCountsVecs::forced_import(&db, "empty_address_count", version, indexes)?;
|
AddrCountsVecs::forced_import(&db, "empty_addr_count", version, indexes)?;
|
||||||
let address_activity =
|
let addr_activity =
|
||||||
AddressActivityVecs::forced_import(&db, "address_activity", version, indexes, cached_starts)?;
|
AddrActivityVecs::forced_import(&db, "addr_activity", version, indexes, cached_starts)?;
|
||||||
|
|
||||||
// Stored total = address_count + empty_address_count (global + per-type, with all derived indexes)
|
// Stored total = addr_count + empty_addr_count (global + per-type, with all derived indexes)
|
||||||
let total_address_count = TotalAddressCountVecs::forced_import(&db, version, indexes)?;
|
let total_addr_count = TotalAddrCountVecs::forced_import(&db, version, indexes)?;
|
||||||
|
|
||||||
// Per-block delta of total (global + per-type)
|
// Per-block delta of total (global + per-type)
|
||||||
let new_address_count =
|
let new_addr_count =
|
||||||
NewAddressCountVecs::forced_import(&db, version, indexes, cached_starts)?;
|
NewAddrCountVecs::forced_import(&db, version, indexes, cached_starts)?;
|
||||||
|
|
||||||
// Growth rate: delta change + rate (global + per-type)
|
// Growth rate: delta change + rate (global + per-type)
|
||||||
let delta = DeltaVecs::new(version, &address_count, cached_starts, indexes);
|
let delta = DeltaVecs::new(version, &addr_count, cached_starts, indexes);
|
||||||
|
|
||||||
let this = Self {
|
let this = Self {
|
||||||
supply_state: BytesVec::forced_import_with(
|
supply_state: BytesVec::forced_import_with(
|
||||||
@@ -159,19 +159,19 @@ impl Vecs {
|
|||||||
.with_saved_stamped_changes(SAVED_STAMPED_CHANGES),
|
.with_saved_stamped_changes(SAVED_STAMPED_CHANGES),
|
||||||
)?,
|
)?,
|
||||||
|
|
||||||
addresses: AddressMetricsVecs {
|
addrs: AddrMetricsVecs {
|
||||||
funded: address_count,
|
funded: addr_count,
|
||||||
empty: empty_address_count,
|
empty: empty_addr_count,
|
||||||
activity: address_activity,
|
activity: addr_activity,
|
||||||
total: total_address_count,
|
total: total_addr_count,
|
||||||
new: new_address_count,
|
new: new_addr_count,
|
||||||
delta,
|
delta,
|
||||||
funded_index: funded_address_index,
|
funded_index: funded_addr_index,
|
||||||
empty_index: empty_address_index,
|
empty_index: empty_addr_index,
|
||||||
},
|
},
|
||||||
|
|
||||||
utxo_cohorts,
|
utxo_cohorts,
|
||||||
address_cohorts,
|
addr_cohorts,
|
||||||
|
|
||||||
coinblocks_destroyed: PerBlockCumulativeWithSums::forced_import(
|
coinblocks_destroyed: PerBlockCumulativeWithSums::forced_import(
|
||||||
&db,
|
&db,
|
||||||
@@ -181,10 +181,10 @@ impl Vecs {
|
|||||||
cached_starts,
|
cached_starts,
|
||||||
)?,
|
)?,
|
||||||
|
|
||||||
any_address_indexes: AnyAddressIndexesVecs::forced_import(&db, version)?,
|
any_addr_indexes: AnyAddrIndexesVecs::forced_import(&db, version)?,
|
||||||
addresses_data: AddressesDataVecs {
|
addrs_data: AddrsDataVecs {
|
||||||
funded: funded_address_index_to_funded_address_data,
|
funded: funded_addr_index_to_funded_addr_data,
|
||||||
empty: empty_address_index_to_empty_address_data,
|
empty: empty_addr_index_to_empty_addr_data,
|
||||||
},
|
},
|
||||||
chain_state: Vec::new(),
|
chain_state: Vec::new(),
|
||||||
tx_index_to_height: RangeMap::default(),
|
tx_index_to_height: RangeMap::default(),
|
||||||
@@ -275,10 +275,10 @@ impl Vecs {
|
|||||||
let recovered = recover_state(
|
let recovered = recover_state(
|
||||||
height,
|
height,
|
||||||
chain_state_rollback,
|
chain_state_rollback,
|
||||||
&mut self.any_address_indexes,
|
&mut self.any_addr_indexes,
|
||||||
&mut self.addresses_data,
|
&mut self.addrs_data,
|
||||||
&mut self.utxo_cohorts,
|
&mut self.utxo_cohorts,
|
||||||
&mut self.address_cohorts,
|
&mut self.addr_cohorts,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if recovered.starting_height.is_zero() {
|
if recovered.starting_height.is_zero() {
|
||||||
@@ -302,14 +302,14 @@ impl Vecs {
|
|||||||
// Recover or reuse chain_state
|
// Recover or reuse chain_state
|
||||||
let starting_height = if recovered_height.is_zero() {
|
let starting_height = if recovered_height.is_zero() {
|
||||||
self.supply_state.reset()?;
|
self.supply_state.reset()?;
|
||||||
self.addresses.funded.reset_height()?;
|
self.addrs.funded.reset_height()?;
|
||||||
self.addresses.empty.reset_height()?;
|
self.addrs.empty.reset_height()?;
|
||||||
self.addresses.activity.reset_height()?;
|
self.addrs.activity.reset_height()?;
|
||||||
reset_state(
|
reset_state(
|
||||||
&mut self.any_address_indexes,
|
&mut self.any_addr_indexes,
|
||||||
&mut self.addresses_data,
|
&mut self.addrs_data,
|
||||||
&mut self.utxo_cohorts,
|
&mut self.utxo_cohorts,
|
||||||
&mut self.address_cohorts,
|
&mut self.addr_cohorts,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
chain_state.clear();
|
chain_state.clear();
|
||||||
@@ -356,7 +356,7 @@ impl Vecs {
|
|||||||
debug!("validating computed versions");
|
debug!("validating computed versions");
|
||||||
let base_version = VERSION;
|
let base_version = VERSION;
|
||||||
self.utxo_cohorts.validate_computed_versions(base_version)?;
|
self.utxo_cohorts.validate_computed_versions(base_version)?;
|
||||||
self.address_cohorts
|
self.addr_cohorts
|
||||||
.validate_computed_versions(base_version)?;
|
.validate_computed_versions(base_version)?;
|
||||||
debug!("computed versions validated");
|
debug!("computed versions validated");
|
||||||
|
|
||||||
@@ -406,7 +406,7 @@ impl Vecs {
|
|||||||
{
|
{
|
||||||
let (r1, r2) = rayon::join(
|
let (r1, r2) = rayon::join(
|
||||||
|| self.utxo_cohorts.compute_overlapping_vecs(starting_indexes, exit),
|
|| self.utxo_cohorts.compute_overlapping_vecs(starting_indexes, exit),
|
||||||
|| self.address_cohorts.compute_overlapping_vecs(starting_indexes, exit),
|
|| self.addr_cohorts.compute_overlapping_vecs(starting_indexes, exit),
|
||||||
);
|
);
|
||||||
r1?;
|
r1?;
|
||||||
r2?;
|
r2?;
|
||||||
@@ -421,30 +421,30 @@ impl Vecs {
|
|||||||
{
|
{
|
||||||
let (r1, r2) = rayon::join(
|
let (r1, r2) = rayon::join(
|
||||||
|| self.utxo_cohorts.compute_rest_part1(prices, starting_indexes, exit),
|
|| self.utxo_cohorts.compute_rest_part1(prices, starting_indexes, exit),
|
||||||
|| self.address_cohorts.compute_rest_part1(prices, starting_indexes, exit),
|
|| self.addr_cohorts.compute_rest_part1(prices, starting_indexes, exit),
|
||||||
);
|
);
|
||||||
r1?;
|
r1?;
|
||||||
r2?;
|
r2?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6b. Compute address count sum (by address_type → all)
|
// 6b. Compute address count sum (by addr_type -> all)
|
||||||
self.addresses.funded.compute_rest(starting_indexes, exit)?;
|
self.addrs.funded.compute_rest(starting_indexes, exit)?;
|
||||||
self.addresses.empty.compute_rest(starting_indexes, exit)?;
|
self.addrs.empty.compute_rest(starting_indexes, exit)?;
|
||||||
|
|
||||||
// 6c. Compute total_address_count = address_count + empty_address_count
|
// 6c. Compute total_addr_count = addr_count + empty_addr_count
|
||||||
self.addresses.total.compute(
|
self.addrs.total.compute(
|
||||||
starting_indexes.height,
|
starting_indexes.height,
|
||||||
&self.addresses.funded,
|
&self.addrs.funded,
|
||||||
&self.addresses.empty,
|
&self.addrs.empty,
|
||||||
exit,
|
exit,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.addresses
|
self.addrs
|
||||||
.activity
|
.activity
|
||||||
.compute_rest(starting_indexes.height, exit)?;
|
.compute_rest(starting_indexes.height, exit)?;
|
||||||
self.addresses.new.compute(
|
self.addrs.new.compute(
|
||||||
starting_indexes.height,
|
starting_indexes.height,
|
||||||
&self.addresses.total,
|
&self.addrs.total,
|
||||||
exit,
|
exit,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@@ -467,7 +467,7 @@ impl Vecs {
|
|||||||
&height_to_market_cap,
|
&height_to_market_cap,
|
||||||
exit,
|
exit,
|
||||||
)?;
|
)?;
|
||||||
self.address_cohorts
|
self.addr_cohorts
|
||||||
.compute_rest_part2(prices, starting_indexes, exit)?;
|
.compute_rest_part2(prices, starting_indexes, exit)?;
|
||||||
|
|
||||||
let _lock = exit.lock();
|
let _lock = exit.lock();
|
||||||
@@ -483,13 +483,13 @@ impl Vecs {
|
|||||||
fn min_stateful_len(&self) -> Height {
|
fn min_stateful_len(&self) -> Height {
|
||||||
self.utxo_cohorts
|
self.utxo_cohorts
|
||||||
.min_stateful_len()
|
.min_stateful_len()
|
||||||
.min(self.address_cohorts.min_stateful_len())
|
.min(self.addr_cohorts.min_stateful_len())
|
||||||
.min(Height::from(self.supply_state.len()))
|
.min(Height::from(self.supply_state.len()))
|
||||||
.min(self.any_address_indexes.min_stamped_len())
|
.min(self.any_addr_indexes.min_stamped_len())
|
||||||
.min(self.addresses_data.min_stamped_len())
|
.min(self.addrs_data.min_stamped_len())
|
||||||
.min(Height::from(self.addresses.funded.min_stateful_len()))
|
.min(Height::from(self.addrs.funded.min_stateful_len()))
|
||||||
.min(Height::from(self.addresses.empty.min_stateful_len()))
|
.min(Height::from(self.addrs.empty.min_stateful_len()))
|
||||||
.min(Height::from(self.addresses.activity.min_stateful_len()))
|
.min(Height::from(self.addrs.activity.min_stateful_len()))
|
||||||
.min(Height::from(self.coinblocks_destroyed.base.height.len()))
|
.min(Height::from(self.coinblocks_destroyed.base.height.len()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use brk_indexer::Indexer;
|
use brk_indexer::Indexer;
|
||||||
use brk_traversable::Traversable;
|
use brk_traversable::Traversable;
|
||||||
use brk_types::{
|
use brk_types::{
|
||||||
Address, AddressBytes, EmptyOutputIndex, OpReturnIndex, P2AAddressIndex, P2ABytes,
|
Addr, AddrBytes, EmptyOutputIndex, OpReturnIndex, P2AAddrIndex, P2ABytes,
|
||||||
P2MSOutputIndex, P2PK33AddressIndex, P2PK33Bytes, P2PK65AddressIndex, P2PK65Bytes,
|
P2MSOutputIndex, P2PK33AddrIndex, P2PK33Bytes, P2PK65AddrIndex, P2PK65Bytes,
|
||||||
P2PKHAddressIndex, P2PKHBytes, P2SHAddressIndex, P2SHBytes, P2TRAddressIndex, P2TRBytes,
|
P2PKHAddrIndex, P2PKHBytes, P2SHAddrIndex, P2SHBytes, P2TRAddrIndex, P2TRBytes,
|
||||||
P2WPKHAddressIndex, P2WPKHBytes, P2WSHAddressIndex, P2WSHBytes, TxIndex, UnknownOutputIndex,
|
P2WPKHAddrIndex, P2WPKHBytes, P2WSHAddrIndex, P2WSHBytes, TxIndex, UnknownOutputIndex,
|
||||||
Version,
|
Version,
|
||||||
};
|
};
|
||||||
use vecdb::{LazyVecFrom1, ReadableCloneableVec};
|
use vecdb::{LazyVecFrom1, ReadableCloneableVec};
|
||||||
@@ -28,52 +28,52 @@ pub struct Vecs {
|
|||||||
#[derive(Clone, Traversable)]
|
#[derive(Clone, Traversable)]
|
||||||
pub struct P2PK33Vecs {
|
pub struct P2PK33Vecs {
|
||||||
pub identity:
|
pub identity:
|
||||||
LazyVecFrom1<P2PK33AddressIndex, P2PK33AddressIndex, P2PK33AddressIndex, P2PK33Bytes>,
|
LazyVecFrom1<P2PK33AddrIndex, P2PK33AddrIndex, P2PK33AddrIndex, P2PK33Bytes>,
|
||||||
pub address: LazyVecFrom1<P2PK33AddressIndex, Address, P2PK33AddressIndex, P2PK33Bytes>,
|
pub addr: LazyVecFrom1<P2PK33AddrIndex, Addr, P2PK33AddrIndex, P2PK33Bytes>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Traversable)]
|
#[derive(Clone, Traversable)]
|
||||||
pub struct P2PK65Vecs {
|
pub struct P2PK65Vecs {
|
||||||
pub identity:
|
pub identity:
|
||||||
LazyVecFrom1<P2PK65AddressIndex, P2PK65AddressIndex, P2PK65AddressIndex, P2PK65Bytes>,
|
LazyVecFrom1<P2PK65AddrIndex, P2PK65AddrIndex, P2PK65AddrIndex, P2PK65Bytes>,
|
||||||
pub address: LazyVecFrom1<P2PK65AddressIndex, Address, P2PK65AddressIndex, P2PK65Bytes>,
|
pub addr: LazyVecFrom1<P2PK65AddrIndex, Addr, P2PK65AddrIndex, P2PK65Bytes>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Traversable)]
|
#[derive(Clone, Traversable)]
|
||||||
pub struct P2PKHVecs {
|
pub struct P2PKHVecs {
|
||||||
pub identity: LazyVecFrom1<P2PKHAddressIndex, P2PKHAddressIndex, P2PKHAddressIndex, P2PKHBytes>,
|
pub identity: LazyVecFrom1<P2PKHAddrIndex, P2PKHAddrIndex, P2PKHAddrIndex, P2PKHBytes>,
|
||||||
pub address: LazyVecFrom1<P2PKHAddressIndex, Address, P2PKHAddressIndex, P2PKHBytes>,
|
pub addr: LazyVecFrom1<P2PKHAddrIndex, Addr, P2PKHAddrIndex, P2PKHBytes>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Traversable)]
|
#[derive(Clone, Traversable)]
|
||||||
pub struct P2SHVecs {
|
pub struct P2SHVecs {
|
||||||
pub identity: LazyVecFrom1<P2SHAddressIndex, P2SHAddressIndex, P2SHAddressIndex, P2SHBytes>,
|
pub identity: LazyVecFrom1<P2SHAddrIndex, P2SHAddrIndex, P2SHAddrIndex, P2SHBytes>,
|
||||||
pub address: LazyVecFrom1<P2SHAddressIndex, Address, P2SHAddressIndex, P2SHBytes>,
|
pub addr: LazyVecFrom1<P2SHAddrIndex, Addr, P2SHAddrIndex, P2SHBytes>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Traversable)]
|
#[derive(Clone, Traversable)]
|
||||||
pub struct P2TRVecs {
|
pub struct P2TRVecs {
|
||||||
pub identity: LazyVecFrom1<P2TRAddressIndex, P2TRAddressIndex, P2TRAddressIndex, P2TRBytes>,
|
pub identity: LazyVecFrom1<P2TRAddrIndex, P2TRAddrIndex, P2TRAddrIndex, P2TRBytes>,
|
||||||
pub address: LazyVecFrom1<P2TRAddressIndex, Address, P2TRAddressIndex, P2TRBytes>,
|
pub addr: LazyVecFrom1<P2TRAddrIndex, Addr, P2TRAddrIndex, P2TRBytes>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Traversable)]
|
#[derive(Clone, Traversable)]
|
||||||
pub struct P2WPKHVecs {
|
pub struct P2WPKHVecs {
|
||||||
pub identity:
|
pub identity:
|
||||||
LazyVecFrom1<P2WPKHAddressIndex, P2WPKHAddressIndex, P2WPKHAddressIndex, P2WPKHBytes>,
|
LazyVecFrom1<P2WPKHAddrIndex, P2WPKHAddrIndex, P2WPKHAddrIndex, P2WPKHBytes>,
|
||||||
pub address: LazyVecFrom1<P2WPKHAddressIndex, Address, P2WPKHAddressIndex, P2WPKHBytes>,
|
pub addr: LazyVecFrom1<P2WPKHAddrIndex, Addr, P2WPKHAddrIndex, P2WPKHBytes>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Traversable)]
|
#[derive(Clone, Traversable)]
|
||||||
pub struct P2WSHVecs {
|
pub struct P2WSHVecs {
|
||||||
pub identity: LazyVecFrom1<P2WSHAddressIndex, P2WSHAddressIndex, P2WSHAddressIndex, P2WSHBytes>,
|
pub identity: LazyVecFrom1<P2WSHAddrIndex, P2WSHAddrIndex, P2WSHAddrIndex, P2WSHBytes>,
|
||||||
pub address: LazyVecFrom1<P2WSHAddressIndex, Address, P2WSHAddressIndex, P2WSHBytes>,
|
pub addr: LazyVecFrom1<P2WSHAddrIndex, Addr, P2WSHAddrIndex, P2WSHBytes>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Traversable)]
|
#[derive(Clone, Traversable)]
|
||||||
pub struct P2AVecs {
|
pub struct P2AVecs {
|
||||||
pub identity: LazyVecFrom1<P2AAddressIndex, P2AAddressIndex, P2AAddressIndex, P2ABytes>,
|
pub identity: LazyVecFrom1<P2AAddrIndex, P2AAddrIndex, P2AAddrIndex, P2ABytes>,
|
||||||
pub address: LazyVecFrom1<P2AAddressIndex, Address, P2AAddressIndex, P2ABytes>,
|
pub addr: LazyVecFrom1<P2AAddrIndex, Addr, P2AAddrIndex, P2ABytes>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Traversable)]
|
#[derive(Clone, Traversable)]
|
||||||
@@ -101,114 +101,114 @@ impl Vecs {
|
|||||||
Self {
|
Self {
|
||||||
p2pk33: P2PK33Vecs {
|
p2pk33: P2PK33Vecs {
|
||||||
identity: LazyVecFrom1::init(
|
identity: LazyVecFrom1::init(
|
||||||
"p2pk33_address_index",
|
"p2pk33_addr_index",
|
||||||
version,
|
version,
|
||||||
indexer.vecs.addresses.p2pk33.bytes.read_only_boxed_clone(),
|
indexer.vecs.addrs.p2pk33.bytes.read_only_boxed_clone(),
|
||||||
|index, _| index,
|
|index, _| index,
|
||||||
),
|
),
|
||||||
address: LazyVecFrom1::init(
|
addr: LazyVecFrom1::init(
|
||||||
"p2pk33_address",
|
"p2pk33_addr",
|
||||||
version,
|
version,
|
||||||
indexer.vecs.addresses.p2pk33.bytes.read_only_boxed_clone(),
|
indexer.vecs.addrs.p2pk33.bytes.read_only_boxed_clone(),
|
||||||
|_, bytes| Address::try_from(&AddressBytes::from(bytes)).unwrap(),
|
|_, bytes| Addr::try_from(&AddrBytes::from(bytes)).unwrap(),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
p2pk65: P2PK65Vecs {
|
p2pk65: P2PK65Vecs {
|
||||||
identity: LazyVecFrom1::init(
|
identity: LazyVecFrom1::init(
|
||||||
"p2pk65_address_index",
|
"p2pk65_addr_index",
|
||||||
version,
|
version,
|
||||||
indexer.vecs.addresses.p2pk65.bytes.read_only_boxed_clone(),
|
indexer.vecs.addrs.p2pk65.bytes.read_only_boxed_clone(),
|
||||||
|index, _| index,
|
|index, _| index,
|
||||||
),
|
),
|
||||||
address: LazyVecFrom1::init(
|
addr: LazyVecFrom1::init(
|
||||||
"p2pk65_address",
|
"p2pk65_addr",
|
||||||
version,
|
version,
|
||||||
indexer.vecs.addresses.p2pk65.bytes.read_only_boxed_clone(),
|
indexer.vecs.addrs.p2pk65.bytes.read_only_boxed_clone(),
|
||||||
|_, bytes| Address::try_from(&AddressBytes::from(bytes)).unwrap(),
|
|_, bytes| Addr::try_from(&AddrBytes::from(bytes)).unwrap(),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
p2pkh: P2PKHVecs {
|
p2pkh: P2PKHVecs {
|
||||||
identity: LazyVecFrom1::init(
|
identity: LazyVecFrom1::init(
|
||||||
"p2pkh_address_index",
|
"p2pkh_addr_index",
|
||||||
version,
|
version,
|
||||||
indexer.vecs.addresses.p2pkh.bytes.read_only_boxed_clone(),
|
indexer.vecs.addrs.p2pkh.bytes.read_only_boxed_clone(),
|
||||||
|index, _| index,
|
|index, _| index,
|
||||||
),
|
),
|
||||||
address: LazyVecFrom1::init(
|
addr: LazyVecFrom1::init(
|
||||||
"p2pkh_address",
|
"p2pkh_addr",
|
||||||
version,
|
version,
|
||||||
indexer.vecs.addresses.p2pkh.bytes.read_only_boxed_clone(),
|
indexer.vecs.addrs.p2pkh.bytes.read_only_boxed_clone(),
|
||||||
|_, bytes| Address::try_from(&AddressBytes::from(bytes)).unwrap(),
|
|_, bytes| Addr::try_from(&AddrBytes::from(bytes)).unwrap(),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
p2sh: P2SHVecs {
|
p2sh: P2SHVecs {
|
||||||
identity: LazyVecFrom1::init(
|
identity: LazyVecFrom1::init(
|
||||||
"p2sh_address_index",
|
"p2sh_addr_index",
|
||||||
version,
|
version,
|
||||||
indexer.vecs.addresses.p2sh.bytes.read_only_boxed_clone(),
|
indexer.vecs.addrs.p2sh.bytes.read_only_boxed_clone(),
|
||||||
|index, _| index,
|
|index, _| index,
|
||||||
),
|
),
|
||||||
address: LazyVecFrom1::init(
|
addr: LazyVecFrom1::init(
|
||||||
"p2sh_address",
|
"p2sh_addr",
|
||||||
version,
|
version,
|
||||||
indexer.vecs.addresses.p2sh.bytes.read_only_boxed_clone(),
|
indexer.vecs.addrs.p2sh.bytes.read_only_boxed_clone(),
|
||||||
|_, bytes| Address::try_from(&AddressBytes::from(bytes)).unwrap(),
|
|_, bytes| Addr::try_from(&AddrBytes::from(bytes)).unwrap(),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
p2tr: P2TRVecs {
|
p2tr: P2TRVecs {
|
||||||
identity: LazyVecFrom1::init(
|
identity: LazyVecFrom1::init(
|
||||||
"p2tr_address_index",
|
"p2tr_addr_index",
|
||||||
version,
|
version,
|
||||||
indexer.vecs.addresses.p2tr.bytes.read_only_boxed_clone(),
|
indexer.vecs.addrs.p2tr.bytes.read_only_boxed_clone(),
|
||||||
|index, _| index,
|
|index, _| index,
|
||||||
),
|
),
|
||||||
address: LazyVecFrom1::init(
|
addr: LazyVecFrom1::init(
|
||||||
"p2tr_address",
|
"p2tr_addr",
|
||||||
version,
|
version,
|
||||||
indexer.vecs.addresses.p2tr.bytes.read_only_boxed_clone(),
|
indexer.vecs.addrs.p2tr.bytes.read_only_boxed_clone(),
|
||||||
|_, bytes| Address::try_from(&AddressBytes::from(bytes)).unwrap(),
|
|_, bytes| Addr::try_from(&AddrBytes::from(bytes)).unwrap(),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
p2wpkh: P2WPKHVecs {
|
p2wpkh: P2WPKHVecs {
|
||||||
identity: LazyVecFrom1::init(
|
identity: LazyVecFrom1::init(
|
||||||
"p2wpkh_address_index",
|
"p2wpkh_addr_index",
|
||||||
version,
|
version,
|
||||||
indexer.vecs.addresses.p2wpkh.bytes.read_only_boxed_clone(),
|
indexer.vecs.addrs.p2wpkh.bytes.read_only_boxed_clone(),
|
||||||
|index, _| index,
|
|index, _| index,
|
||||||
),
|
),
|
||||||
address: LazyVecFrom1::init(
|
addr: LazyVecFrom1::init(
|
||||||
"p2wpkh_address",
|
"p2wpkh_addr",
|
||||||
version,
|
version,
|
||||||
indexer.vecs.addresses.p2wpkh.bytes.read_only_boxed_clone(),
|
indexer.vecs.addrs.p2wpkh.bytes.read_only_boxed_clone(),
|
||||||
|_, bytes| Address::try_from(&AddressBytes::from(bytes)).unwrap(),
|
|_, bytes| Addr::try_from(&AddrBytes::from(bytes)).unwrap(),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
p2wsh: P2WSHVecs {
|
p2wsh: P2WSHVecs {
|
||||||
identity: LazyVecFrom1::init(
|
identity: LazyVecFrom1::init(
|
||||||
"p2wsh_address_index",
|
"p2wsh_addr_index",
|
||||||
version,
|
version,
|
||||||
indexer.vecs.addresses.p2wsh.bytes.read_only_boxed_clone(),
|
indexer.vecs.addrs.p2wsh.bytes.read_only_boxed_clone(),
|
||||||
|index, _| index,
|
|index, _| index,
|
||||||
),
|
),
|
||||||
address: LazyVecFrom1::init(
|
addr: LazyVecFrom1::init(
|
||||||
"p2wsh_address",
|
"p2wsh_addr",
|
||||||
version,
|
version,
|
||||||
indexer.vecs.addresses.p2wsh.bytes.read_only_boxed_clone(),
|
indexer.vecs.addrs.p2wsh.bytes.read_only_boxed_clone(),
|
||||||
|_, bytes| Address::try_from(&AddressBytes::from(bytes)).unwrap(),
|
|_, bytes| Addr::try_from(&AddrBytes::from(bytes)).unwrap(),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
p2a: P2AVecs {
|
p2a: P2AVecs {
|
||||||
identity: LazyVecFrom1::init(
|
identity: LazyVecFrom1::init(
|
||||||
"p2a_address_index",
|
"p2a_addr_index",
|
||||||
version,
|
version,
|
||||||
indexer.vecs.addresses.p2a.bytes.read_only_boxed_clone(),
|
indexer.vecs.addrs.p2a.bytes.read_only_boxed_clone(),
|
||||||
|index, _| index,
|
|index, _| index,
|
||||||
),
|
),
|
||||||
address: LazyVecFrom1::init(
|
addr: LazyVecFrom1::init(
|
||||||
"p2a_address",
|
"p2a_addr",
|
||||||
version,
|
version,
|
||||||
indexer.vecs.addresses.p2a.bytes.read_only_boxed_clone(),
|
indexer.vecs.addrs.p2a.bytes.read_only_boxed_clone(),
|
||||||
|_, bytes| Address::try_from(&AddressBytes::from(bytes)).unwrap(),
|
|_, bytes| Addr::try_from(&AddrBytes::from(bytes)).unwrap(),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
p2ms: P2MSVecs {
|
p2ms: P2MSVecs {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
mod address;
|
mod addr;
|
||||||
mod cached_mappings;
|
mod cached_mappings;
|
||||||
mod day1;
|
mod day1;
|
||||||
mod day3;
|
mod day3;
|
||||||
@@ -37,7 +37,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub use cached_mappings::CachedMappings;
|
pub use cached_mappings::CachedMappings;
|
||||||
pub use address::Vecs as AddressVecs;
|
pub use addr::Vecs as AddrVecs;
|
||||||
pub use day1::Vecs as Day1Vecs;
|
pub use day1::Vecs as Day1Vecs;
|
||||||
pub use day3::Vecs as Day3Vecs;
|
pub use day3::Vecs as Day3Vecs;
|
||||||
pub use epoch::Vecs as EpochVecs;
|
pub use epoch::Vecs as EpochVecs;
|
||||||
@@ -65,7 +65,7 @@ pub struct Vecs<M: StorageMode = Rw> {
|
|||||||
db: Database,
|
db: Database,
|
||||||
#[traversable(skip)]
|
#[traversable(skip)]
|
||||||
pub cached_mappings: CachedMappings,
|
pub cached_mappings: CachedMappings,
|
||||||
pub address: AddressVecs,
|
pub addr: AddrVecs,
|
||||||
pub height: HeightVecs<M>,
|
pub height: HeightVecs<M>,
|
||||||
pub epoch: EpochVecs<M>,
|
pub epoch: EpochVecs<M>,
|
||||||
pub halving: HalvingVecs<M>,
|
pub halving: HalvingVecs<M>,
|
||||||
@@ -97,7 +97,7 @@ impl Vecs {
|
|||||||
|
|
||||||
let version = parent_version;
|
let version = parent_version;
|
||||||
|
|
||||||
let address = AddressVecs::forced_import(version, indexer);
|
let addr = AddrVecs::forced_import(version, indexer);
|
||||||
let height = HeightVecs::forced_import(&db, version)?;
|
let height = HeightVecs::forced_import(&db, version)?;
|
||||||
let epoch = EpochVecs::forced_import(&db, version)?;
|
let epoch = EpochVecs::forced_import(&db, version)?;
|
||||||
let halving = HalvingVecs::forced_import(&db, version)?;
|
let halving = HalvingVecs::forced_import(&db, version)?;
|
||||||
@@ -138,7 +138,7 @@ impl Vecs {
|
|||||||
|
|
||||||
let this = Self {
|
let this = Self {
|
||||||
cached_mappings,
|
cached_mappings,
|
||||||
address,
|
addr,
|
||||||
height,
|
height,
|
||||||
epoch,
|
epoch,
|
||||||
halving,
|
halving,
|
||||||
|
|||||||
@@ -306,12 +306,8 @@ impl Computer {
|
|||||||
.compute(indexer, &mut self.blocks, starting_indexes, exit)
|
.compute(indexer, &mut self.blocks, starting_indexes, exit)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
timed("Computed prices", || {
|
|
||||||
self.prices
|
|
||||||
.compute(indexer, &self.indexes, &starting_indexes, exit)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
thread::scope(|scope| -> Result<()> {
|
thread::scope(|scope| -> Result<()> {
|
||||||
|
// Positions only needs indexer + starting_indexes — start immediately.
|
||||||
let positions = scope.spawn(|| {
|
let positions = scope.spawn(|| {
|
||||||
timed("Computed positions", || {
|
timed("Computed positions", || {
|
||||||
self.positions
|
self.positions
|
||||||
@@ -319,10 +315,37 @@ impl Computer {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
timed("Computed blocks", || {
|
// Prices and blocks are independent — parallelize.
|
||||||
self.blocks
|
let (prices_result, blocks_result) = rayon::join(
|
||||||
.compute(indexer, &self.indexes, &starting_indexes, exit)
|
|| {
|
||||||
})?;
|
timed("Computed prices", || {
|
||||||
|
self.prices
|
||||||
|
.compute(indexer, &self.indexes, &starting_indexes, exit)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|| {
|
||||||
|
timed("Computed blocks", || {
|
||||||
|
self.blocks
|
||||||
|
.compute(indexer, &self.indexes, &starting_indexes, exit)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
);
|
||||||
|
prices_result?;
|
||||||
|
blocks_result?;
|
||||||
|
|
||||||
|
// Market only needs indexes, prices, blocks — start it early
|
||||||
|
// so it runs in the background alongside the rest of the pipeline.
|
||||||
|
let market = scope.spawn(|| {
|
||||||
|
timed("Computed market", || {
|
||||||
|
self.market.compute(
|
||||||
|
&self.indexes,
|
||||||
|
&self.prices,
|
||||||
|
&self.blocks,
|
||||||
|
&starting_indexes,
|
||||||
|
exit,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
// inputs and scripts are independent — parallelize
|
// inputs and scripts are independent — parallelize
|
||||||
let (inputs_result, scripts_result) = rayon::join(
|
let (inputs_result, scripts_result) = rayon::join(
|
||||||
@@ -390,6 +413,7 @@ impl Computer {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
positions.join().unwrap()?;
|
positions.join().unwrap()?;
|
||||||
|
market.join().unwrap()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@@ -427,13 +451,16 @@ impl Computer {
|
|||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
// Indicators doesn't depend on supply or cointime — run it in the
|
||||||
|
// background alongside supply + cointime to save a scope barrier.
|
||||||
thread::scope(|scope| -> Result<()> {
|
thread::scope(|scope| -> Result<()> {
|
||||||
let market = scope.spawn(|| {
|
let indicators = scope.spawn(|| {
|
||||||
timed("Computed market", || {
|
timed("Computed indicators", || {
|
||||||
self.market.compute(
|
self.indicators.compute(
|
||||||
&self.indexes,
|
&self.mining,
|
||||||
&self.prices,
|
&self.distribution,
|
||||||
&self.blocks,
|
&self.transactions,
|
||||||
|
&self.market,
|
||||||
&starting_indexes,
|
&starting_indexes,
|
||||||
exit,
|
exit,
|
||||||
)
|
)
|
||||||
@@ -453,24 +480,6 @@ impl Computer {
|
|||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
market.join().unwrap()?;
|
|
||||||
Ok(())
|
|
||||||
})?;
|
|
||||||
|
|
||||||
thread::scope(|scope| -> Result<()> {
|
|
||||||
let indicators = scope.spawn(|| {
|
|
||||||
timed("Computed indicators", || {
|
|
||||||
self.indicators.compute(
|
|
||||||
&self.mining,
|
|
||||||
&self.distribution,
|
|
||||||
&self.transactions,
|
|
||||||
&self.market,
|
|
||||||
&starting_indexes,
|
|
||||||
exit,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
timed("Computed cointime", || {
|
timed("Computed cointime", || {
|
||||||
self.cointime.compute(
|
self.cointime.compute(
|
||||||
&starting_indexes,
|
&starting_indexes,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use brk_indexer::Indexer;
|
|||||||
use brk_store::AnyStore;
|
use brk_store::AnyStore;
|
||||||
use brk_traversable::Traversable;
|
use brk_traversable::Traversable;
|
||||||
use brk_types::{
|
use brk_types::{
|
||||||
Address, AddressBytes, Height, Indexes, OutputType, PoolSlug, Pools, TxOutIndex, pools,
|
Addr, AddrBytes, Height, Indexes, OutputType, PoolSlug, Pools, TxOutIndex, pools,
|
||||||
};
|
};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use vecdb::{
|
use vecdb::{
|
||||||
@@ -121,14 +121,14 @@ impl Vecs {
|
|||||||
let first_txout_index = indexer.vecs.transactions.first_txout_index.reader();
|
let first_txout_index = indexer.vecs.transactions.first_txout_index.reader();
|
||||||
let output_type = indexer.vecs.outputs.output_type.reader();
|
let output_type = indexer.vecs.outputs.output_type.reader();
|
||||||
let type_index = indexer.vecs.outputs.type_index.reader();
|
let type_index = indexer.vecs.outputs.type_index.reader();
|
||||||
let p2pk65 = indexer.vecs.addresses.p2pk65.bytes.reader();
|
let p2pk65 = indexer.vecs.addrs.p2pk65.bytes.reader();
|
||||||
let p2pk33 = indexer.vecs.addresses.p2pk33.bytes.reader();
|
let p2pk33 = indexer.vecs.addrs.p2pk33.bytes.reader();
|
||||||
let p2pkh = indexer.vecs.addresses.p2pkh.bytes.reader();
|
let p2pkh = indexer.vecs.addrs.p2pkh.bytes.reader();
|
||||||
let p2sh = indexer.vecs.addresses.p2sh.bytes.reader();
|
let p2sh = indexer.vecs.addrs.p2sh.bytes.reader();
|
||||||
let p2wpkh = indexer.vecs.addresses.p2wpkh.bytes.reader();
|
let p2wpkh = indexer.vecs.addrs.p2wpkh.bytes.reader();
|
||||||
let p2wsh = indexer.vecs.addresses.p2wsh.bytes.reader();
|
let p2wsh = indexer.vecs.addrs.p2wsh.bytes.reader();
|
||||||
let p2tr = indexer.vecs.addresses.p2tr.bytes.reader();
|
let p2tr = indexer.vecs.addrs.p2tr.bytes.reader();
|
||||||
let p2a = indexer.vecs.addresses.p2a.bytes.reader();
|
let p2a = indexer.vecs.addrs.p2a.bytes.reader();
|
||||||
|
|
||||||
let unknown = self.pools.get_unknown();
|
let unknown = self.pools.get_unknown();
|
||||||
|
|
||||||
@@ -165,18 +165,18 @@ impl Vecs {
|
|||||||
let ot = output_type.get(txout_index.to_usize());
|
let ot = output_type.get(txout_index.to_usize());
|
||||||
let ti = usize::from(type_index.get(txout_index.to_usize()));
|
let ti = usize::from(type_index.get(txout_index.to_usize()));
|
||||||
match ot {
|
match ot {
|
||||||
OutputType::P2PK65 => Some(AddressBytes::from(p2pk65.get(ti))),
|
OutputType::P2PK65 => Some(AddrBytes::from(p2pk65.get(ti))),
|
||||||
OutputType::P2PK33 => Some(AddressBytes::from(p2pk33.get(ti))),
|
OutputType::P2PK33 => Some(AddrBytes::from(p2pk33.get(ti))),
|
||||||
OutputType::P2PKH => Some(AddressBytes::from(p2pkh.get(ti))),
|
OutputType::P2PKH => Some(AddrBytes::from(p2pkh.get(ti))),
|
||||||
OutputType::P2SH => Some(AddressBytes::from(p2sh.get(ti))),
|
OutputType::P2SH => Some(AddrBytes::from(p2sh.get(ti))),
|
||||||
OutputType::P2WPKH => Some(AddressBytes::from(p2wpkh.get(ti))),
|
OutputType::P2WPKH => Some(AddrBytes::from(p2wpkh.get(ti))),
|
||||||
OutputType::P2WSH => Some(AddressBytes::from(p2wsh.get(ti))),
|
OutputType::P2WSH => Some(AddrBytes::from(p2wsh.get(ti))),
|
||||||
OutputType::P2TR => Some(AddressBytes::from(p2tr.get(ti))),
|
OutputType::P2TR => Some(AddrBytes::from(p2tr.get(ti))),
|
||||||
OutputType::P2A => Some(AddressBytes::from(p2a.get(ti))),
|
OutputType::P2A => Some(AddrBytes::from(p2a.get(ti))),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
.map(|bytes| Address::try_from(&bytes).unwrap())
|
.map(|bytes| Addr::try_from(&bytes).unwrap())
|
||||||
.and_then(|address| self.pools.find_from_address(&address))
|
.and_then(|addr| self.pools.find_from_addr(&addr))
|
||||||
})
|
})
|
||||||
.or_else(|| self.pools.find_from_coinbase_tag(&coinbase_tag))
|
.or_else(|| self.pools.find_from_coinbase_tag(&coinbase_tag))
|
||||||
.unwrap_or(unknown);
|
.unwrap_or(unknown);
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ impl Vecs {
|
|||||||
.compute(starting_indexes.height, exit, |v| {
|
.compute(starting_indexes.height, exit, |v| {
|
||||||
Ok(v.compute_count_from_indexes(
|
Ok(v.compute_count_from_indexes(
|
||||||
starting_indexes.height,
|
starting_indexes.height,
|
||||||
&indexer.vecs.addresses.p2a.first_index,
|
&indexer.vecs.addrs.p2a.first_index,
|
||||||
&indexer.vecs.addresses.p2a.bytes,
|
&indexer.vecs.addrs.p2a.bytes,
|
||||||
exit,
|
exit,
|
||||||
)?)
|
)?)
|
||||||
})?;
|
})?;
|
||||||
@@ -36,8 +36,8 @@ impl Vecs {
|
|||||||
.compute(starting_indexes.height, exit, |v| {
|
.compute(starting_indexes.height, exit, |v| {
|
||||||
Ok(v.compute_count_from_indexes(
|
Ok(v.compute_count_from_indexes(
|
||||||
starting_indexes.height,
|
starting_indexes.height,
|
||||||
&indexer.vecs.addresses.p2pk33.first_index,
|
&indexer.vecs.addrs.p2pk33.first_index,
|
||||||
&indexer.vecs.addresses.p2pk33.bytes,
|
&indexer.vecs.addrs.p2pk33.bytes,
|
||||||
exit,
|
exit,
|
||||||
)?)
|
)?)
|
||||||
})?;
|
})?;
|
||||||
@@ -46,8 +46,8 @@ impl Vecs {
|
|||||||
.compute(starting_indexes.height, exit, |v| {
|
.compute(starting_indexes.height, exit, |v| {
|
||||||
Ok(v.compute_count_from_indexes(
|
Ok(v.compute_count_from_indexes(
|
||||||
starting_indexes.height,
|
starting_indexes.height,
|
||||||
&indexer.vecs.addresses.p2pk65.first_index,
|
&indexer.vecs.addrs.p2pk65.first_index,
|
||||||
&indexer.vecs.addresses.p2pk65.bytes,
|
&indexer.vecs.addrs.p2pk65.bytes,
|
||||||
exit,
|
exit,
|
||||||
)?)
|
)?)
|
||||||
})?;
|
})?;
|
||||||
@@ -56,8 +56,8 @@ impl Vecs {
|
|||||||
.compute(starting_indexes.height, exit, |v| {
|
.compute(starting_indexes.height, exit, |v| {
|
||||||
Ok(v.compute_count_from_indexes(
|
Ok(v.compute_count_from_indexes(
|
||||||
starting_indexes.height,
|
starting_indexes.height,
|
||||||
&indexer.vecs.addresses.p2pkh.first_index,
|
&indexer.vecs.addrs.p2pkh.first_index,
|
||||||
&indexer.vecs.addresses.p2pkh.bytes,
|
&indexer.vecs.addrs.p2pkh.bytes,
|
||||||
exit,
|
exit,
|
||||||
)?)
|
)?)
|
||||||
})?;
|
})?;
|
||||||
@@ -66,8 +66,8 @@ impl Vecs {
|
|||||||
.compute(starting_indexes.height, exit, |v| {
|
.compute(starting_indexes.height, exit, |v| {
|
||||||
Ok(v.compute_count_from_indexes(
|
Ok(v.compute_count_from_indexes(
|
||||||
starting_indexes.height,
|
starting_indexes.height,
|
||||||
&indexer.vecs.addresses.p2sh.first_index,
|
&indexer.vecs.addrs.p2sh.first_index,
|
||||||
&indexer.vecs.addresses.p2sh.bytes,
|
&indexer.vecs.addrs.p2sh.bytes,
|
||||||
exit,
|
exit,
|
||||||
)?)
|
)?)
|
||||||
})?;
|
})?;
|
||||||
@@ -76,8 +76,8 @@ impl Vecs {
|
|||||||
.compute(starting_indexes.height, exit, |v| {
|
.compute(starting_indexes.height, exit, |v| {
|
||||||
Ok(v.compute_count_from_indexes(
|
Ok(v.compute_count_from_indexes(
|
||||||
starting_indexes.height,
|
starting_indexes.height,
|
||||||
&indexer.vecs.addresses.p2tr.first_index,
|
&indexer.vecs.addrs.p2tr.first_index,
|
||||||
&indexer.vecs.addresses.p2tr.bytes,
|
&indexer.vecs.addrs.p2tr.bytes,
|
||||||
exit,
|
exit,
|
||||||
)?)
|
)?)
|
||||||
})?;
|
})?;
|
||||||
@@ -86,8 +86,8 @@ impl Vecs {
|
|||||||
.compute(starting_indexes.height, exit, |v| {
|
.compute(starting_indexes.height, exit, |v| {
|
||||||
Ok(v.compute_count_from_indexes(
|
Ok(v.compute_count_from_indexes(
|
||||||
starting_indexes.height,
|
starting_indexes.height,
|
||||||
&indexer.vecs.addresses.p2wpkh.first_index,
|
&indexer.vecs.addrs.p2wpkh.first_index,
|
||||||
&indexer.vecs.addresses.p2wpkh.bytes,
|
&indexer.vecs.addrs.p2wpkh.bytes,
|
||||||
exit,
|
exit,
|
||||||
)?)
|
)?)
|
||||||
})?;
|
})?;
|
||||||
@@ -96,8 +96,8 @@ impl Vecs {
|
|||||||
.compute(starting_indexes.height, exit, |v| {
|
.compute(starting_indexes.height, exit, |v| {
|
||||||
Ok(v.compute_count_from_indexes(
|
Ok(v.compute_count_from_indexes(
|
||||||
starting_indexes.height,
|
starting_indexes.height,
|
||||||
&indexer.vecs.addresses.p2wsh.first_index,
|
&indexer.vecs.addrs.p2wsh.first_index,
|
||||||
&indexer.vecs.addresses.p2wsh.bytes,
|
&indexer.vecs.addrs.p2wsh.bytes,
|
||||||
exit,
|
exit,
|
||||||
)?)
|
)?)
|
||||||
})?;
|
})?;
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ pub enum Error {
|
|||||||
WrongLength { expected: usize, received: usize },
|
WrongLength { expected: usize, received: usize },
|
||||||
|
|
||||||
#[error("Wrong address type")]
|
#[error("Wrong address type")]
|
||||||
WrongAddressType,
|
WrongAddrType,
|
||||||
|
|
||||||
#[error("Date cannot be indexed, must be 2009-01-03, 2009-01-09 or greater")]
|
#[error("Date cannot be indexed, must be 2009-01-03, 2009-01-09 or greater")]
|
||||||
UnindexableDate,
|
UnindexableDate,
|
||||||
@@ -90,7 +90,7 @@ pub enum Error {
|
|||||||
QuickCacheError,
|
QuickCacheError,
|
||||||
|
|
||||||
#[error("The provided address appears to be invalid")]
|
#[error("The provided address appears to be invalid")]
|
||||||
InvalidAddress,
|
InvalidAddr,
|
||||||
|
|
||||||
#[error("Invalid network")]
|
#[error("Invalid network")]
|
||||||
InvalidNetwork,
|
InvalidNetwork,
|
||||||
@@ -102,7 +102,7 @@ pub enum Error {
|
|||||||
MempoolNotAvailable,
|
MempoolNotAvailable,
|
||||||
|
|
||||||
#[error("Address not found in the blockchain (no transaction history)")]
|
#[error("Address not found in the blockchain (no transaction history)")]
|
||||||
UnknownAddress,
|
UnknownAddr,
|
||||||
|
|
||||||
#[error("Failed to find the TXID in the blockchain")]
|
#[error("Failed to find the TXID in the blockchain")]
|
||||||
UnknownTxid,
|
UnknownTxid,
|
||||||
|
|||||||
@@ -38,33 +38,33 @@ impl IndexesExt for Indexes {
|
|||||||
vecs.scripts
|
vecs.scripts
|
||||||
.op_return.first_index
|
.op_return.first_index
|
||||||
.checked_push(height, self.op_return_index)?;
|
.checked_push(height, self.op_return_index)?;
|
||||||
vecs.addresses
|
vecs.addrs
|
||||||
.p2a.first_index
|
.p2a.first_index
|
||||||
.checked_push(height, self.p2a_address_index)?;
|
.checked_push(height, self.p2a_addr_index)?;
|
||||||
vecs.scripts
|
vecs.scripts
|
||||||
.unknown.first_index
|
.unknown.first_index
|
||||||
.checked_push(height, self.unknown_output_index)?;
|
.checked_push(height, self.unknown_output_index)?;
|
||||||
vecs.addresses
|
vecs.addrs
|
||||||
.p2pk33.first_index
|
.p2pk33.first_index
|
||||||
.checked_push(height, self.p2pk33_address_index)?;
|
.checked_push(height, self.p2pk33_addr_index)?;
|
||||||
vecs.addresses
|
vecs.addrs
|
||||||
.p2pk65.first_index
|
.p2pk65.first_index
|
||||||
.checked_push(height, self.p2pk65_address_index)?;
|
.checked_push(height, self.p2pk65_addr_index)?;
|
||||||
vecs.addresses
|
vecs.addrs
|
||||||
.p2pkh.first_index
|
.p2pkh.first_index
|
||||||
.checked_push(height, self.p2pkh_address_index)?;
|
.checked_push(height, self.p2pkh_addr_index)?;
|
||||||
vecs.addresses
|
vecs.addrs
|
||||||
.p2sh.first_index
|
.p2sh.first_index
|
||||||
.checked_push(height, self.p2sh_address_index)?;
|
.checked_push(height, self.p2sh_addr_index)?;
|
||||||
vecs.addresses
|
vecs.addrs
|
||||||
.p2tr.first_index
|
.p2tr.first_index
|
||||||
.checked_push(height, self.p2tr_address_index)?;
|
.checked_push(height, self.p2tr_addr_index)?;
|
||||||
vecs.addresses
|
vecs.addrs
|
||||||
.p2wpkh.first_index
|
.p2wpkh.first_index
|
||||||
.checked_push(height, self.p2wpkh_address_index)?;
|
.checked_push(height, self.p2wpkh_addr_index)?;
|
||||||
vecs.addresses
|
vecs.addrs
|
||||||
.p2wsh.first_index
|
.p2wsh.first_index
|
||||||
.checked_push(height, self.p2wsh_address_index)?;
|
.checked_push(height, self.p2wsh_addr_index)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -115,51 +115,51 @@ impl IndexesExt for Indexes {
|
|||||||
starting_height,
|
starting_height,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let p2pk33_address_index = starting_index(
|
let p2pk33_addr_index = starting_index(
|
||||||
&vecs.addresses.p2pk33.first_index,
|
&vecs.addrs.p2pk33.first_index,
|
||||||
&vecs.addresses.p2pk33.bytes,
|
&vecs.addrs.p2pk33.bytes,
|
||||||
starting_height,
|
starting_height,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let p2pk65_address_index = starting_index(
|
let p2pk65_addr_index = starting_index(
|
||||||
&vecs.addresses.p2pk65.first_index,
|
&vecs.addrs.p2pk65.first_index,
|
||||||
&vecs.addresses.p2pk65.bytes,
|
&vecs.addrs.p2pk65.bytes,
|
||||||
starting_height,
|
starting_height,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let p2pkh_address_index = starting_index(
|
let p2pkh_addr_index = starting_index(
|
||||||
&vecs.addresses.p2pkh.first_index,
|
&vecs.addrs.p2pkh.first_index,
|
||||||
&vecs.addresses.p2pkh.bytes,
|
&vecs.addrs.p2pkh.bytes,
|
||||||
starting_height,
|
starting_height,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let p2sh_address_index = starting_index(
|
let p2sh_addr_index = starting_index(
|
||||||
&vecs.addresses.p2sh.first_index,
|
&vecs.addrs.p2sh.first_index,
|
||||||
&vecs.addresses.p2sh.bytes,
|
&vecs.addrs.p2sh.bytes,
|
||||||
starting_height,
|
starting_height,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let p2tr_address_index = starting_index(
|
let p2tr_addr_index = starting_index(
|
||||||
&vecs.addresses.p2tr.first_index,
|
&vecs.addrs.p2tr.first_index,
|
||||||
&vecs.addresses.p2tr.bytes,
|
&vecs.addrs.p2tr.bytes,
|
||||||
starting_height,
|
starting_height,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let p2wpkh_address_index = starting_index(
|
let p2wpkh_addr_index = starting_index(
|
||||||
&vecs.addresses.p2wpkh.first_index,
|
&vecs.addrs.p2wpkh.first_index,
|
||||||
&vecs.addresses.p2wpkh.bytes,
|
&vecs.addrs.p2wpkh.bytes,
|
||||||
starting_height,
|
starting_height,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let p2wsh_address_index = starting_index(
|
let p2wsh_addr_index = starting_index(
|
||||||
&vecs.addresses.p2wsh.first_index,
|
&vecs.addrs.p2wsh.first_index,
|
||||||
&vecs.addresses.p2wsh.bytes,
|
&vecs.addrs.p2wsh.bytes,
|
||||||
starting_height,
|
starting_height,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let p2a_address_index = starting_index(
|
let p2a_addr_index = starting_index(
|
||||||
&vecs.addresses.p2a.first_index,
|
&vecs.addrs.p2a.first_index,
|
||||||
&vecs.addresses.p2a.bytes,
|
&vecs.addrs.p2a.bytes,
|
||||||
starting_height,
|
starting_height,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@@ -192,14 +192,14 @@ impl IndexesExt for Indexes {
|
|||||||
height: starting_height,
|
height: starting_height,
|
||||||
p2ms_output_index,
|
p2ms_output_index,
|
||||||
op_return_index,
|
op_return_index,
|
||||||
p2pk33_address_index,
|
p2pk33_addr_index,
|
||||||
p2pk65_address_index,
|
p2pk65_addr_index,
|
||||||
p2pkh_address_index,
|
p2pkh_addr_index,
|
||||||
p2sh_address_index,
|
p2sh_addr_index,
|
||||||
p2tr_address_index,
|
p2tr_addr_index,
|
||||||
p2wpkh_address_index,
|
p2wpkh_addr_index,
|
||||||
p2wsh_address_index,
|
p2wsh_addr_index,
|
||||||
p2a_address_index,
|
p2a_addr_index,
|
||||||
tx_index,
|
tx_index,
|
||||||
txin_index,
|
txin_index,
|
||||||
txout_index,
|
txout_index,
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ impl Indexer {
|
|||||||
txouts,
|
txouts,
|
||||||
txins,
|
txins,
|
||||||
&buffers.same_block_spent,
|
&buffers.same_block_spent,
|
||||||
&mut buffers.already_added_addresses,
|
&mut buffers.already_added_addrs,
|
||||||
&mut buffers.same_block_output_info,
|
&mut buffers.same_block_output_info,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ mod types;
|
|||||||
|
|
||||||
pub use types::*;
|
pub use types::*;
|
||||||
|
|
||||||
use brk_cohort::ByAddressType;
|
use brk_cohort::ByAddrType;
|
||||||
use brk_error::Result;
|
use brk_error::Result;
|
||||||
use brk_types::{AddressHash, Block, Height, OutPoint, TxInIndex, TxIndex, TxOutIndex, TypeIndex};
|
use brk_types::{AddrHash, Block, Height, OutPoint, TxInIndex, TxIndex, TxOutIndex, TypeIndex};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
use crate::{Indexes, Readers, Stores, Vecs};
|
use crate::{Indexes, Readers, Stores, Vecs};
|
||||||
@@ -40,7 +40,7 @@ impl BlockProcessor<'_> {
|
|||||||
txouts: Vec<ProcessedOutput>,
|
txouts: Vec<ProcessedOutput>,
|
||||||
txins: Vec<(TxInIndex, InputSource)>,
|
txins: Vec<(TxInIndex, InputSource)>,
|
||||||
same_block_spent_outpoints: &FxHashSet<OutPoint>,
|
same_block_spent_outpoints: &FxHashSet<OutPoint>,
|
||||||
already_added: &mut ByAddressType<FxHashMap<AddressHash, TypeIndex>>,
|
already_added: &mut ByAddrType<FxHashMap<AddrHash, TypeIndex>>,
|
||||||
same_block_info: &mut FxHashMap<OutPoint, SameBlockOutputInfo>,
|
same_block_info: &mut FxHashMap<OutPoint, SameBlockOutputInfo>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let height = self.height;
|
let height = self.height;
|
||||||
@@ -52,12 +52,12 @@ impl BlockProcessor<'_> {
|
|||||||
|
|
||||||
let outputs = &mut self.vecs.outputs;
|
let outputs = &mut self.vecs.outputs;
|
||||||
let inputs = &mut self.vecs.inputs;
|
let inputs = &mut self.vecs.inputs;
|
||||||
let addresses = &mut self.vecs.addresses;
|
let addrs = &mut self.vecs.addrs;
|
||||||
let scripts = &mut self.vecs.scripts;
|
let scripts = &mut self.vecs.scripts;
|
||||||
|
|
||||||
let addr_hash_stores = &mut self.stores.address_type_to_address_hash_to_address_index;
|
let addr_hash_stores = &mut self.stores.addr_type_to_addr_hash_to_addr_index;
|
||||||
let addr_tx_index_stores = &mut self.stores.address_type_to_address_index_and_tx_index;
|
let addr_tx_index_stores = &mut self.stores.addr_type_to_addr_index_and_tx_index;
|
||||||
let addr_outpoint_stores = &mut self.stores.address_type_to_address_index_and_unspent_outpoint;
|
let addr_outpoint_stores = &mut self.stores.addr_type_to_addr_index_and_unspent_outpoint;
|
||||||
let txid_prefix_store = &mut self.stores.txid_prefix_to_tx_index;
|
let txid_prefix_store = &mut self.stores.txid_prefix_to_tx_index;
|
||||||
|
|
||||||
let (finalize_result, metadata_result) = rayon::join(
|
let (finalize_result, metadata_result) = rayon::join(
|
||||||
@@ -66,7 +66,7 @@ impl BlockProcessor<'_> {
|
|||||||
indexes,
|
indexes,
|
||||||
first_txout_index,
|
first_txout_index,
|
||||||
outputs,
|
outputs,
|
||||||
addresses,
|
addrs,
|
||||||
scripts,
|
scripts,
|
||||||
addr_hash_stores,
|
addr_hash_stores,
|
||||||
addr_tx_index_stores,
|
addr_tx_index_stores,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use brk_cohort::ByAddressType;
|
use brk_cohort::ByAddrType;
|
||||||
use brk_error::{Error, Result};
|
use brk_error::{Error, Result};
|
||||||
use brk_store::Store;
|
use brk_store::Store;
|
||||||
use brk_types::{
|
use brk_types::{
|
||||||
AddressIndexOutPoint, AddressIndexTxIndex, OutPoint, OutputType, TxInIndex, TxIndex, Txid,
|
AddrIndexOutPoint, AddrIndexTxIndex, OutPoint, OutputType, TxInIndex, TxIndex, Txid,
|
||||||
TxidPrefix, TypeIndex, Unit, Vin, Vout,
|
TxidPrefix, TypeIndex, Unit, Vin, Vout,
|
||||||
};
|
};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
@@ -151,8 +151,8 @@ impl<'a> BlockProcessor<'a> {
|
|||||||
pub(super) fn finalize_inputs(
|
pub(super) fn finalize_inputs(
|
||||||
first_txin_index: &mut PcoVec<TxIndex, TxInIndex>,
|
first_txin_index: &mut PcoVec<TxIndex, TxInIndex>,
|
||||||
inputs: &mut InputsVecs,
|
inputs: &mut InputsVecs,
|
||||||
addr_tx_index_stores: &mut ByAddressType<Store<AddressIndexTxIndex, Unit>>,
|
addr_tx_index_stores: &mut ByAddrType<Store<AddrIndexTxIndex, Unit>>,
|
||||||
addr_outpoint_stores: &mut ByAddressType<Store<AddressIndexOutPoint, Unit>>,
|
addr_outpoint_stores: &mut ByAddrType<Store<AddrIndexOutPoint, Unit>>,
|
||||||
txins: Vec<(TxInIndex, InputSource)>,
|
txins: Vec<(TxInIndex, InputSource)>,
|
||||||
same_block_output_info: &mut FxHashMap<OutPoint, SameBlockOutputInfo>,
|
same_block_output_info: &mut FxHashMap<OutPoint, SameBlockOutputInfo>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
@@ -203,19 +203,19 @@ pub(super) fn finalize_inputs(
|
|||||||
inputs.output_type.checked_push(txin_index, output_type)?;
|
inputs.output_type.checked_push(txin_index, output_type)?;
|
||||||
inputs.type_index.checked_push(txin_index, type_index)?;
|
inputs.type_index.checked_push(txin_index, type_index)?;
|
||||||
|
|
||||||
if !output_type.is_address() {
|
if !output_type.is_addr() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let address_type = output_type;
|
let addr_type = output_type;
|
||||||
let address_index = type_index;
|
let addr_index = type_index;
|
||||||
|
|
||||||
addr_tx_index_stores
|
addr_tx_index_stores
|
||||||
.get_mut_unwrap(address_type)
|
.get_mut_unwrap(addr_type)
|
||||||
.insert(AddressIndexTxIndex::from((address_index, tx_index)), Unit);
|
.insert(AddrIndexTxIndex::from((addr_index, tx_index)), Unit);
|
||||||
|
|
||||||
addr_outpoint_stores
|
addr_outpoint_stores
|
||||||
.get_mut_unwrap(address_type)
|
.get_mut_unwrap(addr_type)
|
||||||
.remove(AddressIndexOutPoint::from((address_index, outpoint)));
|
.remove(AddrIndexOutPoint::from((addr_index, outpoint)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use brk_cohort::ByAddressType;
|
use brk_cohort::ByAddrType;
|
||||||
use brk_error::{Error, Result};
|
use brk_error::{Error, Result};
|
||||||
use brk_store::Store;
|
use brk_store::Store;
|
||||||
use brk_types::{
|
use brk_types::{
|
||||||
AddressBytes, AddressHash, AddressIndexOutPoint, AddressIndexTxIndex, OutPoint, OutputType,
|
AddrBytes, AddrHash, AddrIndexOutPoint, AddrIndexTxIndex, OutPoint, OutputType,
|
||||||
Sats, TxIndex, TxOutIndex, TypeIndex, Unit, Vout,
|
Sats, TxIndex, TxOutIndex, TypeIndex, Unit, Vout,
|
||||||
};
|
};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
@@ -11,7 +11,7 @@ use tracing::error;
|
|||||||
use vecdb::{BytesVec, WritableVec};
|
use vecdb::{BytesVec, WritableVec};
|
||||||
|
|
||||||
use super::{BlockProcessor, ProcessedOutput, SameBlockOutputInfo};
|
use super::{BlockProcessor, ProcessedOutput, SameBlockOutputInfo};
|
||||||
use crate::{AddressesVecs, Indexes, OutputsVecs, ScriptsVecs};
|
use crate::{AddrsVecs, Indexes, OutputsVecs, ScriptsVecs};
|
||||||
|
|
||||||
impl<'a> BlockProcessor<'a> {
|
impl<'a> BlockProcessor<'a> {
|
||||||
pub fn process_outputs(&self) -> Result<Vec<ProcessedOutput<'a>>> {
|
pub fn process_outputs(&self) -> Result<Vec<ProcessedOutput<'a>>> {
|
||||||
@@ -40,48 +40,48 @@ impl<'a> BlockProcessor<'a> {
|
|||||||
let script = &txout.script_pubkey;
|
let script = &txout.script_pubkey;
|
||||||
let output_type = OutputType::from(script);
|
let output_type = OutputType::from(script);
|
||||||
|
|
||||||
if output_type.is_not_address() {
|
if output_type.is_not_addr() {
|
||||||
return Ok(ProcessedOutput {
|
return Ok(ProcessedOutput {
|
||||||
txout_index,
|
txout_index,
|
||||||
txout,
|
txout,
|
||||||
tx_index,
|
tx_index,
|
||||||
vout,
|
vout,
|
||||||
output_type,
|
output_type,
|
||||||
address_info: None,
|
addr_info: None,
|
||||||
existing_type_index: None,
|
existing_type_index: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let address_type = output_type;
|
let addr_type = output_type;
|
||||||
let address_bytes = AddressBytes::try_from((script, address_type)).unwrap();
|
let addr_bytes = AddrBytes::try_from((script, addr_type)).unwrap();
|
||||||
let address_hash = AddressHash::from(&address_bytes);
|
let addr_hash = AddrHash::from(&addr_bytes);
|
||||||
|
|
||||||
let existing_type_index = self
|
let existing_type_index = self
|
||||||
.stores
|
.stores
|
||||||
.address_type_to_address_hash_to_address_index
|
.addr_type_to_addr_hash_to_addr_index
|
||||||
.get_unwrap(address_type)
|
.get_unwrap(addr_type)
|
||||||
.get(&address_hash)?
|
.get(&addr_hash)?
|
||||||
.map(|v| *v)
|
.map(|v| *v)
|
||||||
.and_then(|type_index_local| {
|
.and_then(|type_index_local| {
|
||||||
(type_index_local < self.indexes.to_type_index(address_type))
|
(type_index_local < self.indexes.to_type_index(addr_type))
|
||||||
.then_some(type_index_local)
|
.then_some(type_index_local)
|
||||||
});
|
});
|
||||||
|
|
||||||
if check_collisions && let Some(type_index) = existing_type_index {
|
if check_collisions && let Some(type_index) = existing_type_index {
|
||||||
let prev_addressbytes = self
|
let prev_addrbytes = self
|
||||||
.vecs
|
.vecs
|
||||||
.addresses
|
.addrs
|
||||||
.get_bytes_by_type(address_type, type_index, &self.readers.addressbytes)
|
.get_bytes_by_type(addr_type, type_index, &self.readers.addrbytes)
|
||||||
.ok_or(Error::Internal("Missing addressbytes"))?;
|
.ok_or(Error::Internal("Missing addrbytes"))?;
|
||||||
|
|
||||||
if prev_addressbytes != address_bytes {
|
if prev_addrbytes != addr_bytes {
|
||||||
error!(
|
error!(
|
||||||
?height,
|
?height,
|
||||||
?vout,
|
?vout,
|
||||||
?block_tx_index,
|
?block_tx_index,
|
||||||
?address_type,
|
?addr_type,
|
||||||
?prev_addressbytes,
|
?prev_addrbytes,
|
||||||
?address_bytes,
|
?addr_bytes,
|
||||||
?type_index,
|
?type_index,
|
||||||
"Address hash collision"
|
"Address hash collision"
|
||||||
);
|
);
|
||||||
@@ -95,7 +95,7 @@ impl<'a> BlockProcessor<'a> {
|
|||||||
tx_index,
|
tx_index,
|
||||||
vout,
|
vout,
|
||||||
output_type,
|
output_type,
|
||||||
address_info: Some((address_bytes, address_hash)),
|
addr_info: Some((addr_bytes, addr_hash)),
|
||||||
existing_type_index,
|
existing_type_index,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -109,17 +109,17 @@ pub(super) fn finalize_outputs(
|
|||||||
indexes: &mut Indexes,
|
indexes: &mut Indexes,
|
||||||
first_txout_index: &mut BytesVec<TxIndex, TxOutIndex>,
|
first_txout_index: &mut BytesVec<TxIndex, TxOutIndex>,
|
||||||
outputs: &mut OutputsVecs,
|
outputs: &mut OutputsVecs,
|
||||||
addresses: &mut AddressesVecs,
|
addrs: &mut AddrsVecs,
|
||||||
scripts: &mut ScriptsVecs,
|
scripts: &mut ScriptsVecs,
|
||||||
addr_hash_stores: &mut ByAddressType<Store<AddressHash, TypeIndex>>,
|
addr_hash_stores: &mut ByAddrType<Store<AddrHash, TypeIndex>>,
|
||||||
addr_tx_index_stores: &mut ByAddressType<Store<AddressIndexTxIndex, Unit>>,
|
addr_tx_index_stores: &mut ByAddrType<Store<AddrIndexTxIndex, Unit>>,
|
||||||
addr_outpoint_stores: &mut ByAddressType<Store<AddressIndexOutPoint, Unit>>,
|
addr_outpoint_stores: &mut ByAddrType<Store<AddrIndexOutPoint, Unit>>,
|
||||||
txouts: Vec<ProcessedOutput>,
|
txouts: Vec<ProcessedOutput>,
|
||||||
same_block_spent_outpoints: &FxHashSet<OutPoint>,
|
same_block_spent_outpoints: &FxHashSet<OutPoint>,
|
||||||
already_added_address_hash: &mut ByAddressType<FxHashMap<AddressHash, TypeIndex>>,
|
already_added_addr_hash: &mut ByAddrType<FxHashMap<AddrHash, TypeIndex>>,
|
||||||
same_block_output_info: &mut FxHashMap<OutPoint, SameBlockOutputInfo>,
|
same_block_output_info: &mut FxHashMap<OutPoint, SameBlockOutputInfo>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
already_added_address_hash
|
already_added_addr_hash
|
||||||
.values_mut()
|
.values_mut()
|
||||||
.for_each(|m| m.clear());
|
.for_each(|m| m.clear());
|
||||||
same_block_output_info.clear();
|
same_block_output_info.clear();
|
||||||
@@ -130,7 +130,7 @@ pub(super) fn finalize_outputs(
|
|||||||
tx_index,
|
tx_index,
|
||||||
vout,
|
vout,
|
||||||
output_type,
|
output_type,
|
||||||
address_info,
|
addr_info,
|
||||||
existing_type_index,
|
existing_type_index,
|
||||||
} in txouts
|
} in txouts
|
||||||
{
|
{
|
||||||
@@ -144,23 +144,23 @@ pub(super) fn finalize_outputs(
|
|||||||
|
|
||||||
let type_index = if let Some(ti) = existing_type_index {
|
let type_index = if let Some(ti) = existing_type_index {
|
||||||
ti
|
ti
|
||||||
} else if let Some((address_bytes, address_hash)) = address_info {
|
} else if let Some((addr_bytes, addr_hash)) = addr_info {
|
||||||
let address_type = output_type;
|
let addr_type = output_type;
|
||||||
if let Some(&ti) = already_added_address_hash
|
if let Some(&ti) = already_added_addr_hash
|
||||||
.get_unwrap(address_type)
|
.get_unwrap(addr_type)
|
||||||
.get(&address_hash)
|
.get(&addr_hash)
|
||||||
{
|
{
|
||||||
ti
|
ti
|
||||||
} else {
|
} else {
|
||||||
let ti = indexes.increment_address_index(address_type);
|
let ti = indexes.increment_addr_index(addr_type);
|
||||||
|
|
||||||
already_added_address_hash
|
already_added_addr_hash
|
||||||
.get_mut_unwrap(address_type)
|
.get_mut_unwrap(addr_type)
|
||||||
.insert(address_hash, ti);
|
.insert(addr_hash, ti);
|
||||||
addr_hash_stores
|
addr_hash_stores
|
||||||
.get_mut_unwrap(address_type)
|
.get_mut_unwrap(addr_type)
|
||||||
.insert(address_hash, ti);
|
.insert(addr_hash, ti);
|
||||||
addresses.push_bytes_if_needed(ti, address_bytes)?;
|
addrs.push_bytes_if_needed(ti, addr_bytes)?;
|
||||||
|
|
||||||
ti
|
ti
|
||||||
}
|
}
|
||||||
@@ -200,13 +200,13 @@ pub(super) fn finalize_outputs(
|
|||||||
|
|
||||||
if output_type.is_unspendable() {
|
if output_type.is_unspendable() {
|
||||||
continue;
|
continue;
|
||||||
} else if output_type.is_address() {
|
} else if output_type.is_addr() {
|
||||||
let address_type = output_type;
|
let addr_type = output_type;
|
||||||
let address_index = type_index;
|
let addr_index = type_index;
|
||||||
|
|
||||||
addr_tx_index_stores
|
addr_tx_index_stores
|
||||||
.get_mut_unwrap(address_type)
|
.get_mut_unwrap(addr_type)
|
||||||
.insert(AddressIndexTxIndex::from((address_index, tx_index)), Unit);
|
.insert(AddrIndexTxIndex::from((addr_index, tx_index)), Unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
let outpoint = OutPoint::new(tx_index, vout);
|
let outpoint = OutPoint::new(tx_index, vout);
|
||||||
@@ -219,13 +219,13 @@ pub(super) fn finalize_outputs(
|
|||||||
type_index,
|
type_index,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} else if output_type.is_address() {
|
} else if output_type.is_addr() {
|
||||||
let address_type = output_type;
|
let addr_type = output_type;
|
||||||
let address_index = type_index;
|
let addr_index = type_index;
|
||||||
|
|
||||||
addr_outpoint_stores
|
addr_outpoint_stores
|
||||||
.get_mut_unwrap(address_type)
|
.get_mut_unwrap(addr_type)
|
||||||
.insert(AddressIndexOutPoint::from((address_index, outpoint)), Unit);
|
.insert(AddrIndexOutPoint::from((addr_index, outpoint)), Unit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use bitcoin::{Transaction, TxOut};
|
use bitcoin::{Transaction, TxOut};
|
||||||
use brk_cohort::ByAddressType;
|
use brk_cohort::ByAddrType;
|
||||||
use brk_types::{
|
use brk_types::{
|
||||||
AddressBytes, AddressHash, OutPoint, OutputType, TxIndex, TxOutIndex, Txid, TxidPrefix,
|
AddrBytes, AddrHash, OutPoint, OutputType, TxIndex, TxOutIndex, Txid, TxidPrefix,
|
||||||
TypeIndex, Vin, Vout,
|
TypeIndex, Vin, Vout,
|
||||||
};
|
};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
@@ -34,7 +34,7 @@ pub struct ProcessedOutput<'a> {
|
|||||||
pub tx_index: TxIndex,
|
pub tx_index: TxIndex,
|
||||||
pub vout: Vout,
|
pub vout: Vout,
|
||||||
pub output_type: OutputType,
|
pub output_type: OutputType,
|
||||||
pub address_info: Option<(AddressBytes, AddressHash)>,
|
pub addr_info: Option<(AddrBytes, AddrHash)>,
|
||||||
pub existing_type_index: Option<TypeIndex>,
|
pub existing_type_index: Option<TypeIndex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,6 +53,6 @@ pub struct ComputedTx<'a> {
|
|||||||
pub struct BlockBuffers {
|
pub struct BlockBuffers {
|
||||||
pub txid_prefix_map: FxHashMap<TxidPrefix, TxIndex>,
|
pub txid_prefix_map: FxHashMap<TxidPrefix, TxIndex>,
|
||||||
pub same_block_spent: FxHashSet<OutPoint>,
|
pub same_block_spent: FxHashSet<OutPoint>,
|
||||||
pub already_added_addresses: ByAddressType<FxHashMap<AddressHash, TypeIndex>>,
|
pub already_added_addrs: ByAddrType<FxHashMap<AddrHash, TypeIndex>>,
|
||||||
pub same_block_output_info: FxHashMap<OutPoint, SameBlockOutputInfo>,
|
pub same_block_output_info: FxHashMap<OutPoint, SameBlockOutputInfo>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
use bitcoin::ScriptBuf;
|
use bitcoin::ScriptBuf;
|
||||||
use brk_types::{
|
use brk_types::{
|
||||||
AddressBytes, OutputType, P2AAddressIndex, P2ABytes, P2PK33AddressIndex, P2PK33Bytes,
|
AddrBytes, OutputType, P2AAddrIndex, P2ABytes, P2PK33AddrIndex, P2PK33Bytes,
|
||||||
P2PK65AddressIndex, P2PK65Bytes, P2PKHAddressIndex, P2PKHBytes, P2SHAddressIndex, P2SHBytes,
|
P2PK65AddrIndex, P2PK65Bytes, P2PKHAddrIndex, P2PKHBytes, P2SHAddrIndex, P2SHBytes,
|
||||||
P2TRAddressIndex, P2TRBytes, P2WPKHAddressIndex, P2WPKHBytes, P2WSHAddressIndex, P2WSHBytes,
|
P2TRAddrIndex, P2TRBytes, P2WPKHAddrIndex, P2WPKHBytes, P2WSHAddrIndex, P2WSHBytes,
|
||||||
TxIndex, TxOutIndex, Txid, TypeIndex,
|
TxIndex, TxOutIndex, Txid, TypeIndex,
|
||||||
};
|
};
|
||||||
use vecdb::{BytesStrategy, VecReader};
|
use vecdb::{BytesStrategy, VecReader};
|
||||||
|
|
||||||
use crate::Vecs;
|
use crate::Vecs;
|
||||||
|
|
||||||
pub struct AddressReaders {
|
pub struct AddrReaders {
|
||||||
pub p2pk65: VecReader<P2PK65AddressIndex, P2PK65Bytes, BytesStrategy<P2PK65Bytes>>,
|
pub p2pk65: VecReader<P2PK65AddrIndex, P2PK65Bytes, BytesStrategy<P2PK65Bytes>>,
|
||||||
pub p2pk33: VecReader<P2PK33AddressIndex, P2PK33Bytes, BytesStrategy<P2PK33Bytes>>,
|
pub p2pk33: VecReader<P2PK33AddrIndex, P2PK33Bytes, BytesStrategy<P2PK33Bytes>>,
|
||||||
pub p2pkh: VecReader<P2PKHAddressIndex, P2PKHBytes, BytesStrategy<P2PKHBytes>>,
|
pub p2pkh: VecReader<P2PKHAddrIndex, P2PKHBytes, BytesStrategy<P2PKHBytes>>,
|
||||||
pub p2sh: VecReader<P2SHAddressIndex, P2SHBytes, BytesStrategy<P2SHBytes>>,
|
pub p2sh: VecReader<P2SHAddrIndex, P2SHBytes, BytesStrategy<P2SHBytes>>,
|
||||||
pub p2wpkh: VecReader<P2WPKHAddressIndex, P2WPKHBytes, BytesStrategy<P2WPKHBytes>>,
|
pub p2wpkh: VecReader<P2WPKHAddrIndex, P2WPKHBytes, BytesStrategy<P2WPKHBytes>>,
|
||||||
pub p2wsh: VecReader<P2WSHAddressIndex, P2WSHBytes, BytesStrategy<P2WSHBytes>>,
|
pub p2wsh: VecReader<P2WSHAddrIndex, P2WSHBytes, BytesStrategy<P2WSHBytes>>,
|
||||||
pub p2tr: VecReader<P2TRAddressIndex, P2TRBytes, BytesStrategy<P2TRBytes>>,
|
pub p2tr: VecReader<P2TRAddrIndex, P2TRBytes, BytesStrategy<P2TRBytes>>,
|
||||||
pub p2a: VecReader<P2AAddressIndex, P2ABytes, BytesStrategy<P2ABytes>>,
|
pub p2a: VecReader<P2AAddrIndex, P2ABytes, BytesStrategy<P2ABytes>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddressReaders {
|
impl AddrReaders {
|
||||||
pub fn script_pubkey(&self, output_type: OutputType, type_index: TypeIndex) -> ScriptBuf {
|
pub fn script_pubkey(&self, output_type: OutputType, type_index: TypeIndex) -> ScriptBuf {
|
||||||
let idx = usize::from(type_index);
|
let idx = usize::from(type_index);
|
||||||
let bytes: Option<AddressBytes> = match output_type {
|
let bytes: Option<AddrBytes> = match output_type {
|
||||||
OutputType::P2PK65 => self.p2pk65.try_get(idx).map(Into::into),
|
OutputType::P2PK65 => self.p2pk65.try_get(idx).map(Into::into),
|
||||||
OutputType::P2PK33 => self.p2pk33.try_get(idx).map(Into::into),
|
OutputType::P2PK33 => self.p2pk33.try_get(idx).map(Into::into),
|
||||||
OutputType::P2PKH => self.p2pkh.try_get(idx).map(Into::into),
|
OutputType::P2PKH => self.p2pkh.try_get(idx).map(Into::into),
|
||||||
@@ -47,7 +47,7 @@ pub struct Readers {
|
|||||||
pub tx_index_to_first_txout_index: VecReader<TxIndex, TxOutIndex, BytesStrategy<TxOutIndex>>,
|
pub tx_index_to_first_txout_index: VecReader<TxIndex, TxOutIndex, BytesStrategy<TxOutIndex>>,
|
||||||
pub txout_index_to_output_type: VecReader<TxOutIndex, OutputType, BytesStrategy<OutputType>>,
|
pub txout_index_to_output_type: VecReader<TxOutIndex, OutputType, BytesStrategy<OutputType>>,
|
||||||
pub txout_index_to_type_index: VecReader<TxOutIndex, TypeIndex, BytesStrategy<TypeIndex>>,
|
pub txout_index_to_type_index: VecReader<TxOutIndex, TypeIndex, BytesStrategy<TypeIndex>>,
|
||||||
pub addressbytes: AddressReaders,
|
pub addrbytes: AddrReaders,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Readers {
|
impl Readers {
|
||||||
@@ -57,7 +57,7 @@ impl Readers {
|
|||||||
tx_index_to_first_txout_index: vecs.transactions.first_txout_index.reader(),
|
tx_index_to_first_txout_index: vecs.transactions.first_txout_index.reader(),
|
||||||
txout_index_to_output_type: vecs.outputs.output_type.reader(),
|
txout_index_to_output_type: vecs.outputs.output_type.reader(),
|
||||||
txout_index_to_type_index: vecs.outputs.type_index.reader(),
|
txout_index_to_type_index: vecs.outputs.type_index.reader(),
|
||||||
addressbytes: vecs.addresses.address_readers(),
|
addrbytes: vecs.addrs.addr_readers(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ use std::{fs, path::Path, time::Instant};
|
|||||||
|
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
|
|
||||||
use brk_cohort::ByAddressType;
|
use brk_cohort::ByAddrType;
|
||||||
use brk_error::Result;
|
use brk_error::Result;
|
||||||
use brk_store::{AnyStore, Kind, Mode, Store};
|
use brk_store::{AnyStore, Kind, Mode, Store};
|
||||||
use brk_types::{
|
use brk_types::{
|
||||||
AddressHash, AddressIndexOutPoint, AddressIndexTxIndex, BlockHashPrefix, Height, OutPoint,
|
AddrHash, AddrIndexOutPoint, AddrIndexTxIndex, BlockHashPrefix, Height, OutPoint,
|
||||||
OutputType, StoredString, TxIndex, TxOutIndex, TxidPrefix, TypeIndex, Unit, Version, Vout,
|
OutputType, StoredString, TxIndex, TxOutIndex, TxidPrefix, TypeIndex, Unit, Version, Vout,
|
||||||
};
|
};
|
||||||
use fjall::{Database, PersistMode};
|
use fjall::{Database, PersistMode};
|
||||||
@@ -22,10 +22,10 @@ use super::Vecs;
|
|||||||
pub struct Stores {
|
pub struct Stores {
|
||||||
pub db: Database,
|
pub db: Database,
|
||||||
|
|
||||||
pub address_type_to_address_hash_to_address_index: ByAddressType<Store<AddressHash, TypeIndex>>,
|
pub addr_type_to_addr_hash_to_addr_index: ByAddrType<Store<AddrHash, TypeIndex>>,
|
||||||
pub address_type_to_address_index_and_tx_index: ByAddressType<Store<AddressIndexTxIndex, Unit>>,
|
pub addr_type_to_addr_index_and_tx_index: ByAddrType<Store<AddrIndexTxIndex, Unit>>,
|
||||||
pub address_type_to_address_index_and_unspent_outpoint:
|
pub addr_type_to_addr_index_and_unspent_outpoint:
|
||||||
ByAddressType<Store<AddressIndexOutPoint, Unit>>,
|
ByAddrType<Store<AddrIndexOutPoint, Unit>>,
|
||||||
pub blockhash_prefix_to_height: Store<BlockHashPrefix, Height>,
|
pub blockhash_prefix_to_height: Store<BlockHashPrefix, Height>,
|
||||||
pub height_to_coinbase_tag: Store<Height, StoredString>,
|
pub height_to_coinbase_tag: Store<Height, StoredString>,
|
||||||
pub txid_prefix_to_tx_index: Store<TxidPrefix, TxIndex>,
|
pub txid_prefix_to_tx_index: Store<TxidPrefix, TxIndex>,
|
||||||
@@ -53,7 +53,7 @@ impl Stores {
|
|||||||
|
|
||||||
let database_ref = &database;
|
let database_ref = &database;
|
||||||
|
|
||||||
let create_address_hash_to_address_index_store = |index| {
|
let create_addr_hash_to_addr_index_store = |index| {
|
||||||
Store::import(
|
Store::import(
|
||||||
database_ref,
|
database_ref,
|
||||||
path,
|
path,
|
||||||
@@ -64,7 +64,7 @@ impl Stores {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let create_address_index_to_tx_index_store = |index| {
|
let create_addr_index_to_tx_index_store = |index| {
|
||||||
Store::import(
|
Store::import(
|
||||||
database_ref,
|
database_ref,
|
||||||
path,
|
path,
|
||||||
@@ -75,7 +75,7 @@ impl Stores {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let create_address_index_to_unspent_outpoint_store = |index| {
|
let create_addr_index_to_unspent_outpoint_store = |index| {
|
||||||
Store::import(
|
Store::import(
|
||||||
database_ref,
|
database_ref,
|
||||||
path,
|
path,
|
||||||
@@ -97,14 +97,14 @@ impl Stores {
|
|||||||
Mode::PushOnly,
|
Mode::PushOnly,
|
||||||
Kind::Sequential,
|
Kind::Sequential,
|
||||||
)?,
|
)?,
|
||||||
address_type_to_address_hash_to_address_index: ByAddressType::new_with_index(
|
addr_type_to_addr_hash_to_addr_index: ByAddrType::new_with_index(
|
||||||
create_address_hash_to_address_index_store,
|
create_addr_hash_to_addr_index_store,
|
||||||
)?,
|
)?,
|
||||||
address_type_to_address_index_and_tx_index: ByAddressType::new_with_index(
|
addr_type_to_addr_index_and_tx_index: ByAddrType::new_with_index(
|
||||||
create_address_index_to_tx_index_store,
|
create_addr_index_to_tx_index_store,
|
||||||
)?,
|
)?,
|
||||||
address_type_to_address_index_and_unspent_outpoint: ByAddressType::new_with_index(
|
addr_type_to_addr_index_and_unspent_outpoint: ByAddrType::new_with_index(
|
||||||
create_address_index_to_unspent_outpoint_store,
|
create_addr_index_to_unspent_outpoint_store,
|
||||||
)?,
|
)?,
|
||||||
blockhash_prefix_to_height: Store::import(
|
blockhash_prefix_to_height: Store::import(
|
||||||
database_ref,
|
database_ref,
|
||||||
@@ -141,17 +141,17 @@ impl Stores {
|
|||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(
|
.chain(
|
||||||
self.address_type_to_address_hash_to_address_index
|
self.addr_type_to_addr_hash_to_addr_index
|
||||||
.values()
|
.values()
|
||||||
.map(|s| s as &dyn AnyStore),
|
.map(|s| s as &dyn AnyStore),
|
||||||
)
|
)
|
||||||
.chain(
|
.chain(
|
||||||
self.address_type_to_address_index_and_tx_index
|
self.addr_type_to_addr_index_and_tx_index
|
||||||
.values()
|
.values()
|
||||||
.map(|s| s as &dyn AnyStore),
|
.map(|s| s as &dyn AnyStore),
|
||||||
)
|
)
|
||||||
.chain(
|
.chain(
|
||||||
self.address_type_to_address_index_and_unspent_outpoint
|
self.addr_type_to_addr_index_and_unspent_outpoint
|
||||||
.values()
|
.values()
|
||||||
.map(|s| s as &dyn AnyStore),
|
.map(|s| s as &dyn AnyStore),
|
||||||
)
|
)
|
||||||
@@ -165,17 +165,17 @@ impl Stores {
|
|||||||
]
|
]
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.chain(
|
.chain(
|
||||||
self.address_type_to_address_hash_to_address_index
|
self.addr_type_to_addr_hash_to_addr_index
|
||||||
.par_values_mut()
|
.par_values_mut()
|
||||||
.map(|s| s as &mut dyn AnyStore),
|
.map(|s| s as &mut dyn AnyStore),
|
||||||
)
|
)
|
||||||
.chain(
|
.chain(
|
||||||
self.address_type_to_address_index_and_tx_index
|
self.addr_type_to_addr_index_and_tx_index
|
||||||
.par_values_mut()
|
.par_values_mut()
|
||||||
.map(|s| s as &mut dyn AnyStore),
|
.map(|s| s as &mut dyn AnyStore),
|
||||||
)
|
)
|
||||||
.chain(
|
.chain(
|
||||||
self.address_type_to_address_index_and_unspent_outpoint
|
self.addr_type_to_addr_index_and_unspent_outpoint
|
||||||
.par_values_mut()
|
.par_values_mut()
|
||||||
.map(|s| s as &mut dyn AnyStore),
|
.map(|s| s as &mut dyn AnyStore),
|
||||||
)
|
)
|
||||||
@@ -224,15 +224,15 @@ impl Stores {
|
|||||||
&& self.txid_prefix_to_tx_index.is_empty()?
|
&& self.txid_prefix_to_tx_index.is_empty()?
|
||||||
&& self.height_to_coinbase_tag.is_empty()?
|
&& self.height_to_coinbase_tag.is_empty()?
|
||||||
&& self
|
&& self
|
||||||
.address_type_to_address_hash_to_address_index
|
.addr_type_to_addr_hash_to_addr_index
|
||||||
.values()
|
.values()
|
||||||
.try_fold(true, |acc, s| s.is_empty().map(|empty| acc && empty))?
|
.try_fold(true, |acc, s| s.is_empty().map(|empty| acc && empty))?
|
||||||
&& self
|
&& self
|
||||||
.address_type_to_address_index_and_tx_index
|
.addr_type_to_addr_index_and_tx_index
|
||||||
.values()
|
.values()
|
||||||
.try_fold(true, |acc, s| s.is_empty().map(|empty| acc && empty))?
|
.try_fold(true, |acc, s| s.is_empty().map(|empty| acc && empty))?
|
||||||
&& self
|
&& self
|
||||||
.address_type_to_address_index_and_unspent_outpoint
|
.addr_type_to_addr_index_and_unspent_outpoint
|
||||||
.values()
|
.values()
|
||||||
.try_fold(true, |acc, s| s.is_empty().map(|empty| acc && empty))?)
|
.try_fold(true, |acc, s| s.is_empty().map(|empty| acc && empty))?)
|
||||||
}
|
}
|
||||||
@@ -257,10 +257,10 @@ impl Stores {
|
|||||||
self.height_to_coinbase_tag.remove(h);
|
self.height_to_coinbase_tag.remove(h);
|
||||||
});
|
});
|
||||||
|
|
||||||
for address_type in OutputType::ADDRESS_TYPES {
|
for addr_type in OutputType::ADDR_TYPES {
|
||||||
for hash in vecs.iter_address_hashes_from(address_type, starting_indexes.height)? {
|
for hash in vecs.iter_addr_hashes_from(addr_type, starting_indexes.height)? {
|
||||||
self.address_type_to_address_hash_to_address_index
|
self.addr_type_to_addr_hash_to_addr_index
|
||||||
.get_mut_unwrap(address_type)
|
.get_mut_unwrap(addr_type)
|
||||||
.remove(hash);
|
.remove(hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -299,7 +299,7 @@ impl Stores {
|
|||||||
let txout_index_to_output_type_reader = vecs.outputs.output_type.reader();
|
let txout_index_to_output_type_reader = vecs.outputs.output_type.reader();
|
||||||
let txout_index_to_type_index_reader = vecs.outputs.type_index.reader();
|
let txout_index_to_type_index_reader = vecs.outputs.type_index.reader();
|
||||||
|
|
||||||
let mut address_index_tx_index_to_remove: FxHashSet<(OutputType, TypeIndex, TxIndex)> =
|
let mut addr_index_tx_index_to_remove: FxHashSet<(OutputType, TypeIndex, TxIndex)> =
|
||||||
FxHashSet::default();
|
FxHashSet::default();
|
||||||
|
|
||||||
let rollback_start = starting_indexes.txout_index.to_usize();
|
let rollback_start = starting_indexes.txout_index.to_usize();
|
||||||
@@ -312,15 +312,15 @@ impl Stores {
|
|||||||
|
|
||||||
for (i, txout_index) in (rollback_start..rollback_end).enumerate() {
|
for (i, txout_index) in (rollback_start..rollback_end).enumerate() {
|
||||||
let output_type = txout_index_to_output_type_reader.get(txout_index);
|
let output_type = txout_index_to_output_type_reader.get(txout_index);
|
||||||
if !output_type.is_address() {
|
if !output_type.is_addr() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let address_type = output_type;
|
let addr_type = output_type;
|
||||||
let address_index = txout_index_to_type_index_reader.get(txout_index);
|
let addr_index = txout_index_to_type_index_reader.get(txout_index);
|
||||||
let tx_index = tx_indexes[i];
|
let tx_index = tx_indexes[i];
|
||||||
|
|
||||||
address_index_tx_index_to_remove.insert((address_type, address_index, tx_index));
|
addr_index_tx_index_to_remove.insert((addr_type, addr_index, tx_index));
|
||||||
|
|
||||||
let vout = Vout::from(
|
let vout = Vout::from(
|
||||||
txout_index
|
txout_index
|
||||||
@@ -330,9 +330,9 @@ impl Stores {
|
|||||||
);
|
);
|
||||||
let outpoint = OutPoint::new(tx_index, vout);
|
let outpoint = OutPoint::new(tx_index, vout);
|
||||||
|
|
||||||
self.address_type_to_address_index_and_unspent_outpoint
|
self.addr_type_to_addr_index_and_unspent_outpoint
|
||||||
.get_mut_unwrap(address_type)
|
.get_mut_unwrap(addr_type)
|
||||||
.remove(AddressIndexOutPoint::from((address_index, outpoint)));
|
.remove(AddrIndexOutPoint::from((addr_index, outpoint)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let start = starting_indexes.txin_index.to_usize();
|
let start = starting_indexes.txin_index.to_usize();
|
||||||
@@ -364,26 +364,26 @@ impl Stores {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
for (outpoint, output_type, type_index, spending_tx_index) in outputs_to_unspend {
|
for (outpoint, output_type, type_index, spending_tx_index) in outputs_to_unspend {
|
||||||
if output_type.is_address() {
|
if output_type.is_addr() {
|
||||||
let address_type = output_type;
|
let addr_type = output_type;
|
||||||
let address_index = type_index;
|
let addr_index = type_index;
|
||||||
|
|
||||||
address_index_tx_index_to_remove.insert((
|
addr_index_tx_index_to_remove.insert((
|
||||||
address_type,
|
addr_type,
|
||||||
address_index,
|
addr_index,
|
||||||
spending_tx_index,
|
spending_tx_index,
|
||||||
));
|
));
|
||||||
|
|
||||||
self.address_type_to_address_index_and_unspent_outpoint
|
self.addr_type_to_addr_index_and_unspent_outpoint
|
||||||
.get_mut_unwrap(address_type)
|
.get_mut_unwrap(addr_type)
|
||||||
.insert(AddressIndexOutPoint::from((address_index, outpoint)), Unit);
|
.insert(AddrIndexOutPoint::from((addr_index, outpoint)), Unit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (address_type, address_index, tx_index) in address_index_tx_index_to_remove {
|
for (addr_type, addr_index, tx_index) in addr_index_tx_index_to_remove {
|
||||||
self.address_type_to_address_index_and_tx_index
|
self.addr_type_to_addr_index_and_tx_index
|
||||||
.get_mut_unwrap(address_type)
|
.get_mut_unwrap(addr_type)
|
||||||
.remove(AddressIndexTxIndex::from((address_index, tx_index)));
|
.remove(AddrIndexTxIndex::from((addr_index, tx_index)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use brk_error::Result;
|
use brk_error::Result;
|
||||||
use brk_traversable::Traversable;
|
use brk_traversable::Traversable;
|
||||||
use brk_types::{
|
use brk_types::{
|
||||||
AddressBytes, AddressHash, Height, OutputType, P2AAddressIndex, P2ABytes, P2PK33AddressIndex,
|
AddrBytes, AddrHash, Height, OutputType, P2AAddrIndex, P2ABytes, P2PK33AddrIndex,
|
||||||
P2PK33Bytes, P2PK65AddressIndex, P2PK65Bytes, P2PKHAddressIndex, P2PKHBytes, P2SHAddressIndex,
|
P2PK33Bytes, P2PK65AddrIndex, P2PK65Bytes, P2PKHAddrIndex, P2PKHBytes, P2SHAddrIndex,
|
||||||
P2SHBytes, P2TRAddressIndex, P2TRBytes, P2WPKHAddressIndex, P2WPKHBytes, P2WSHAddressIndex,
|
P2SHBytes, P2TRAddrIndex, P2TRBytes, P2WPKHAddrIndex, P2WPKHBytes, P2WSHAddrIndex,
|
||||||
P2WSHBytes, TypeIndex, Version,
|
P2WSHBytes, TypeIndex, Version,
|
||||||
};
|
};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
@@ -15,37 +15,37 @@ use vecdb::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::parallel_import;
|
use crate::parallel_import;
|
||||||
use crate::readers::AddressReaders;
|
use crate::readers::AddrReaders;
|
||||||
|
|
||||||
#[derive(Traversable)]
|
#[derive(Traversable)]
|
||||||
pub struct AddressTypeVecs<I: VecIndex + PcoVecValue + Formattable + Serialize + JsonSchema, B: BytesVecValue + Formattable + Serialize + JsonSchema, M: StorageMode = Rw> {
|
pub struct AddrTypeVecs<I: VecIndex + PcoVecValue + Formattable + Serialize + JsonSchema, B: BytesVecValue + Formattable + Serialize + JsonSchema, M: StorageMode = Rw> {
|
||||||
pub first_index: M::Stored<PcoVec<Height, I>>,
|
pub first_index: M::Stored<PcoVec<Height, I>>,
|
||||||
pub bytes: M::Stored<BytesVec<I, B>>,
|
pub bytes: M::Stored<BytesVec<I, B>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Traversable)]
|
#[derive(Traversable)]
|
||||||
pub struct AddressesVecs<M: StorageMode = Rw> {
|
pub struct AddrsVecs<M: StorageMode = Rw> {
|
||||||
pub p2pk65: AddressTypeVecs<P2PK65AddressIndex, P2PK65Bytes, M>,
|
pub p2pk65: AddrTypeVecs<P2PK65AddrIndex, P2PK65Bytes, M>,
|
||||||
pub p2pk33: AddressTypeVecs<P2PK33AddressIndex, P2PK33Bytes, M>,
|
pub p2pk33: AddrTypeVecs<P2PK33AddrIndex, P2PK33Bytes, M>,
|
||||||
pub p2pkh: AddressTypeVecs<P2PKHAddressIndex, P2PKHBytes, M>,
|
pub p2pkh: AddrTypeVecs<P2PKHAddrIndex, P2PKHBytes, M>,
|
||||||
pub p2sh: AddressTypeVecs<P2SHAddressIndex, P2SHBytes, M>,
|
pub p2sh: AddrTypeVecs<P2SHAddrIndex, P2SHBytes, M>,
|
||||||
pub p2wpkh: AddressTypeVecs<P2WPKHAddressIndex, P2WPKHBytes, M>,
|
pub p2wpkh: AddrTypeVecs<P2WPKHAddrIndex, P2WPKHBytes, M>,
|
||||||
pub p2wsh: AddressTypeVecs<P2WSHAddressIndex, P2WSHBytes, M>,
|
pub p2wsh: AddrTypeVecs<P2WSHAddrIndex, P2WSHBytes, M>,
|
||||||
pub p2tr: AddressTypeVecs<P2TRAddressIndex, P2TRBytes, M>,
|
pub p2tr: AddrTypeVecs<P2TRAddrIndex, P2TRBytes, M>,
|
||||||
pub p2a: AddressTypeVecs<P2AAddressIndex, P2ABytes, M>,
|
pub p2a: AddrTypeVecs<P2AAddrIndex, P2ABytes, M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddressesVecs {
|
impl AddrsVecs {
|
||||||
pub fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
pub fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
||||||
let (
|
let (
|
||||||
first_p2pk65_address_index,
|
first_p2pk65_addr_index,
|
||||||
first_p2pk33_address_index,
|
first_p2pk33_addr_index,
|
||||||
first_p2pkh_address_index,
|
first_p2pkh_addr_index,
|
||||||
first_p2sh_address_index,
|
first_p2sh_addr_index,
|
||||||
first_p2wpkh_address_index,
|
first_p2wpkh_addr_index,
|
||||||
first_p2wsh_address_index,
|
first_p2wsh_addr_index,
|
||||||
first_p2tr_address_index,
|
first_p2tr_addr_index,
|
||||||
first_p2a_address_index,
|
first_p2a_addr_index,
|
||||||
p2pk65_bytes,
|
p2pk65_bytes,
|
||||||
p2pk33_bytes,
|
p2pk33_bytes,
|
||||||
p2pkh_bytes,
|
p2pkh_bytes,
|
||||||
@@ -55,14 +55,14 @@ impl AddressesVecs {
|
|||||||
p2tr_bytes,
|
p2tr_bytes,
|
||||||
p2a_bytes,
|
p2a_bytes,
|
||||||
) = parallel_import! {
|
) = parallel_import! {
|
||||||
first_p2pk65_address_index = PcoVec::forced_import(db, "first_p2pk65_address_index", version),
|
first_p2pk65_addr_index = PcoVec::forced_import(db, "first_p2pk65_addr_index", version),
|
||||||
first_p2pk33_address_index = PcoVec::forced_import(db, "first_p2pk33_address_index", version),
|
first_p2pk33_addr_index = PcoVec::forced_import(db, "first_p2pk33_addr_index", version),
|
||||||
first_p2pkh_address_index = PcoVec::forced_import(db, "first_p2pkh_address_index", version),
|
first_p2pkh_addr_index = PcoVec::forced_import(db, "first_p2pkh_addr_index", version),
|
||||||
first_p2sh_address_index = PcoVec::forced_import(db, "first_p2sh_address_index", version),
|
first_p2sh_addr_index = PcoVec::forced_import(db, "first_p2sh_addr_index", version),
|
||||||
first_p2wpkh_address_index = PcoVec::forced_import(db, "first_p2wpkh_address_index", version),
|
first_p2wpkh_addr_index = PcoVec::forced_import(db, "first_p2wpkh_addr_index", version),
|
||||||
first_p2wsh_address_index = PcoVec::forced_import(db, "first_p2wsh_address_index", version),
|
first_p2wsh_addr_index = PcoVec::forced_import(db, "first_p2wsh_addr_index", version),
|
||||||
first_p2tr_address_index = PcoVec::forced_import(db, "first_p2tr_address_index", version),
|
first_p2tr_addr_index = PcoVec::forced_import(db, "first_p2tr_addr_index", version),
|
||||||
first_p2a_address_index = PcoVec::forced_import(db, "first_p2a_address_index", version),
|
first_p2a_addr_index = PcoVec::forced_import(db, "first_p2a_addr_index", version),
|
||||||
p2pk65_bytes = BytesVec::forced_import(db, "p2pk65_bytes", version),
|
p2pk65_bytes = BytesVec::forced_import(db, "p2pk65_bytes", version),
|
||||||
p2pk33_bytes = BytesVec::forced_import(db, "p2pk33_bytes", version),
|
p2pk33_bytes = BytesVec::forced_import(db, "p2pk33_bytes", version),
|
||||||
p2pkh_bytes = BytesVec::forced_import(db, "p2pkh_bytes", version),
|
p2pkh_bytes = BytesVec::forced_import(db, "p2pkh_bytes", version),
|
||||||
@@ -73,14 +73,14 @@ impl AddressesVecs {
|
|||||||
p2a_bytes = BytesVec::forced_import(db, "p2a_bytes", version),
|
p2a_bytes = BytesVec::forced_import(db, "p2a_bytes", version),
|
||||||
};
|
};
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
p2pk65: AddressTypeVecs { first_index: first_p2pk65_address_index, bytes: p2pk65_bytes },
|
p2pk65: AddrTypeVecs { first_index: first_p2pk65_addr_index, bytes: p2pk65_bytes },
|
||||||
p2pk33: AddressTypeVecs { first_index: first_p2pk33_address_index, bytes: p2pk33_bytes },
|
p2pk33: AddrTypeVecs { first_index: first_p2pk33_addr_index, bytes: p2pk33_bytes },
|
||||||
p2pkh: AddressTypeVecs { first_index: first_p2pkh_address_index, bytes: p2pkh_bytes },
|
p2pkh: AddrTypeVecs { first_index: first_p2pkh_addr_index, bytes: p2pkh_bytes },
|
||||||
p2sh: AddressTypeVecs { first_index: first_p2sh_address_index, bytes: p2sh_bytes },
|
p2sh: AddrTypeVecs { first_index: first_p2sh_addr_index, bytes: p2sh_bytes },
|
||||||
p2wpkh: AddressTypeVecs { first_index: first_p2wpkh_address_index, bytes: p2wpkh_bytes },
|
p2wpkh: AddrTypeVecs { first_index: first_p2wpkh_addr_index, bytes: p2wpkh_bytes },
|
||||||
p2wsh: AddressTypeVecs { first_index: first_p2wsh_address_index, bytes: p2wsh_bytes },
|
p2wsh: AddrTypeVecs { first_index: first_p2wsh_addr_index, bytes: p2wsh_bytes },
|
||||||
p2tr: AddressTypeVecs { first_index: first_p2tr_address_index, bytes: p2tr_bytes },
|
p2tr: AddrTypeVecs { first_index: first_p2tr_addr_index, bytes: p2tr_bytes },
|
||||||
p2a: AddressTypeVecs { first_index: first_p2a_address_index, bytes: p2a_bytes },
|
p2a: AddrTypeVecs { first_index: first_p2a_addr_index, bytes: p2a_bytes },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,14 +88,14 @@ impl AddressesVecs {
|
|||||||
pub fn truncate(
|
pub fn truncate(
|
||||||
&mut self,
|
&mut self,
|
||||||
height: Height,
|
height: Height,
|
||||||
p2pk65_address_index: P2PK65AddressIndex,
|
p2pk65_addr_index: P2PK65AddrIndex,
|
||||||
p2pk33_address_index: P2PK33AddressIndex,
|
p2pk33_addr_index: P2PK33AddrIndex,
|
||||||
p2pkh_address_index: P2PKHAddressIndex,
|
p2pkh_addr_index: P2PKHAddrIndex,
|
||||||
p2sh_address_index: P2SHAddressIndex,
|
p2sh_addr_index: P2SHAddrIndex,
|
||||||
p2wpkh_address_index: P2WPKHAddressIndex,
|
p2wpkh_addr_index: P2WPKHAddrIndex,
|
||||||
p2wsh_address_index: P2WSHAddressIndex,
|
p2wsh_addr_index: P2WSHAddrIndex,
|
||||||
p2tr_address_index: P2TRAddressIndex,
|
p2tr_addr_index: P2TRAddrIndex,
|
||||||
p2a_address_index: P2AAddressIndex,
|
p2a_addr_index: P2AAddrIndex,
|
||||||
stamp: Stamp,
|
stamp: Stamp,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
self.p2pk65.first_index
|
self.p2pk65.first_index
|
||||||
@@ -115,21 +115,21 @@ impl AddressesVecs {
|
|||||||
self.p2a.first_index
|
self.p2a.first_index
|
||||||
.truncate_if_needed_with_stamp(height, stamp)?;
|
.truncate_if_needed_with_stamp(height, stamp)?;
|
||||||
self.p2pk65.bytes
|
self.p2pk65.bytes
|
||||||
.truncate_if_needed_with_stamp(p2pk65_address_index, stamp)?;
|
.truncate_if_needed_with_stamp(p2pk65_addr_index, stamp)?;
|
||||||
self.p2pk33.bytes
|
self.p2pk33.bytes
|
||||||
.truncate_if_needed_with_stamp(p2pk33_address_index, stamp)?;
|
.truncate_if_needed_with_stamp(p2pk33_addr_index, stamp)?;
|
||||||
self.p2pkh.bytes
|
self.p2pkh.bytes
|
||||||
.truncate_if_needed_with_stamp(p2pkh_address_index, stamp)?;
|
.truncate_if_needed_with_stamp(p2pkh_addr_index, stamp)?;
|
||||||
self.p2sh.bytes
|
self.p2sh.bytes
|
||||||
.truncate_if_needed_with_stamp(p2sh_address_index, stamp)?;
|
.truncate_if_needed_with_stamp(p2sh_addr_index, stamp)?;
|
||||||
self.p2wpkh.bytes
|
self.p2wpkh.bytes
|
||||||
.truncate_if_needed_with_stamp(p2wpkh_address_index, stamp)?;
|
.truncate_if_needed_with_stamp(p2wpkh_addr_index, stamp)?;
|
||||||
self.p2wsh.bytes
|
self.p2wsh.bytes
|
||||||
.truncate_if_needed_with_stamp(p2wsh_address_index, stamp)?;
|
.truncate_if_needed_with_stamp(p2wsh_addr_index, stamp)?;
|
||||||
self.p2tr.bytes
|
self.p2tr.bytes
|
||||||
.truncate_if_needed_with_stamp(p2tr_address_index, stamp)?;
|
.truncate_if_needed_with_stamp(p2tr_addr_index, stamp)?;
|
||||||
self.p2a.bytes
|
self.p2a.bytes
|
||||||
.truncate_if_needed_with_stamp(p2a_address_index, stamp)?;
|
.truncate_if_needed_with_stamp(p2a_addr_index, stamp)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,69 +159,69 @@ impl AddressesVecs {
|
|||||||
/// Returns None if the index doesn't exist yet.
|
/// Returns None if the index doesn't exist yet.
|
||||||
pub fn get_bytes_by_type(
|
pub fn get_bytes_by_type(
|
||||||
&self,
|
&self,
|
||||||
address_type: OutputType,
|
addr_type: OutputType,
|
||||||
type_index: TypeIndex,
|
type_index: TypeIndex,
|
||||||
readers: &AddressReaders,
|
readers: &AddrReaders,
|
||||||
) -> Option<AddressBytes> {
|
) -> Option<AddrBytes> {
|
||||||
match address_type {
|
match addr_type {
|
||||||
OutputType::P2PK65 => self
|
OutputType::P2PK65 => self
|
||||||
.p2pk65.bytes
|
.p2pk65.bytes
|
||||||
.get_pushed_or_read(type_index.into(), &readers.p2pk65)
|
.get_pushed_or_read(type_index.into(), &readers.p2pk65)
|
||||||
.map(AddressBytes::from),
|
.map(AddrBytes::from),
|
||||||
OutputType::P2PK33 => self
|
OutputType::P2PK33 => self
|
||||||
.p2pk33.bytes
|
.p2pk33.bytes
|
||||||
.get_pushed_or_read(type_index.into(), &readers.p2pk33)
|
.get_pushed_or_read(type_index.into(), &readers.p2pk33)
|
||||||
.map(AddressBytes::from),
|
.map(AddrBytes::from),
|
||||||
OutputType::P2PKH => self
|
OutputType::P2PKH => self
|
||||||
.p2pkh.bytes
|
.p2pkh.bytes
|
||||||
.get_pushed_or_read(type_index.into(), &readers.p2pkh)
|
.get_pushed_or_read(type_index.into(), &readers.p2pkh)
|
||||||
.map(AddressBytes::from),
|
.map(AddrBytes::from),
|
||||||
OutputType::P2SH => self
|
OutputType::P2SH => self
|
||||||
.p2sh.bytes
|
.p2sh.bytes
|
||||||
.get_pushed_or_read(type_index.into(), &readers.p2sh)
|
.get_pushed_or_read(type_index.into(), &readers.p2sh)
|
||||||
.map(AddressBytes::from),
|
.map(AddrBytes::from),
|
||||||
OutputType::P2WPKH => self
|
OutputType::P2WPKH => self
|
||||||
.p2wpkh.bytes
|
.p2wpkh.bytes
|
||||||
.get_pushed_or_read(type_index.into(), &readers.p2wpkh)
|
.get_pushed_or_read(type_index.into(), &readers.p2wpkh)
|
||||||
.map(AddressBytes::from),
|
.map(AddrBytes::from),
|
||||||
OutputType::P2WSH => self
|
OutputType::P2WSH => self
|
||||||
.p2wsh.bytes
|
.p2wsh.bytes
|
||||||
.get_pushed_or_read(type_index.into(), &readers.p2wsh)
|
.get_pushed_or_read(type_index.into(), &readers.p2wsh)
|
||||||
.map(AddressBytes::from),
|
.map(AddrBytes::from),
|
||||||
OutputType::P2TR => self
|
OutputType::P2TR => self
|
||||||
.p2tr.bytes
|
.p2tr.bytes
|
||||||
.get_pushed_or_read(type_index.into(), &readers.p2tr)
|
.get_pushed_or_read(type_index.into(), &readers.p2tr)
|
||||||
.map(AddressBytes::from),
|
.map(AddrBytes::from),
|
||||||
OutputType::P2A => self
|
OutputType::P2A => self
|
||||||
.p2a.bytes
|
.p2a.bytes
|
||||||
.get_pushed_or_read(type_index.into(), &readers.p2a)
|
.get_pushed_or_read(type_index.into(), &readers.p2a)
|
||||||
.map(AddressBytes::from),
|
.map(AddrBytes::from),
|
||||||
_ => unreachable!("get_bytes_by_type called with non-address type"),
|
_ => unreachable!("get_bytes_by_type called with non-address type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_bytes_if_needed(&mut self, index: TypeIndex, bytes: AddressBytes) -> Result<()> {
|
pub fn push_bytes_if_needed(&mut self, index: TypeIndex, bytes: AddrBytes) -> Result<()> {
|
||||||
match bytes {
|
match bytes {
|
||||||
AddressBytes::P2PK65(bytes) => self.p2pk65.bytes.checked_push(index.into(), bytes)?,
|
AddrBytes::P2PK65(bytes) => self.p2pk65.bytes.checked_push(index.into(), bytes)?,
|
||||||
AddressBytes::P2PK33(bytes) => self.p2pk33.bytes.checked_push(index.into(), bytes)?,
|
AddrBytes::P2PK33(bytes) => self.p2pk33.bytes.checked_push(index.into(), bytes)?,
|
||||||
AddressBytes::P2PKH(bytes) => self.p2pkh.bytes.checked_push(index.into(), bytes)?,
|
AddrBytes::P2PKH(bytes) => self.p2pkh.bytes.checked_push(index.into(), bytes)?,
|
||||||
AddressBytes::P2SH(bytes) => self.p2sh.bytes.checked_push(index.into(), bytes)?,
|
AddrBytes::P2SH(bytes) => self.p2sh.bytes.checked_push(index.into(), bytes)?,
|
||||||
AddressBytes::P2WPKH(bytes) => self.p2wpkh.bytes.checked_push(index.into(), bytes)?,
|
AddrBytes::P2WPKH(bytes) => self.p2wpkh.bytes.checked_push(index.into(), bytes)?,
|
||||||
AddressBytes::P2WSH(bytes) => self.p2wsh.bytes.checked_push(index.into(), bytes)?,
|
AddrBytes::P2WSH(bytes) => self.p2wsh.bytes.checked_push(index.into(), bytes)?,
|
||||||
AddressBytes::P2TR(bytes) => self.p2tr.bytes.checked_push(index.into(), bytes)?,
|
AddrBytes::P2TR(bytes) => self.p2tr.bytes.checked_push(index.into(), bytes)?,
|
||||||
AddressBytes::P2A(bytes) => self.p2a.bytes.checked_push(index.into(), bytes)?,
|
AddrBytes::P2A(bytes) => self.p2a.bytes.checked_push(index.into(), bytes)?,
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate address hashes starting from a given height (for rollback).
|
/// Iterate address hashes starting from a given height (for rollback).
|
||||||
/// Returns an iterator of AddressHash values for all addresses of the given type
|
/// Returns an iterator of AddrHash values for all addresses of the given type
|
||||||
/// that were added at or after the given height.
|
/// that were added at or after the given height.
|
||||||
pub fn iter_hashes_from(
|
pub fn iter_hashes_from(
|
||||||
&self,
|
&self,
|
||||||
address_type: OutputType,
|
addr_type: OutputType,
|
||||||
height: Height,
|
height: Height,
|
||||||
) -> Result<Box<dyn Iterator<Item = AddressHash> + '_>> {
|
) -> Result<Box<dyn Iterator<Item = AddrHash> + '_>> {
|
||||||
macro_rules! make_iter {
|
macro_rules! make_iter {
|
||||||
($addr:expr) => {{
|
($addr:expr) => {{
|
||||||
match $addr.first_index.collect_one(height) {
|
match $addr.first_index.collect_one(height) {
|
||||||
@@ -229,22 +229,22 @@ impl AddressesVecs {
|
|||||||
let reader = $addr.bytes.reader();
|
let reader = $addr.bytes.reader();
|
||||||
Ok(Box::new(std::iter::from_fn(move || {
|
Ok(Box::new(std::iter::from_fn(move || {
|
||||||
reader.try_get(index.to_usize()).map(|typedbytes| {
|
reader.try_get(index.to_usize()).map(|typedbytes| {
|
||||||
let bytes = AddressBytes::from(typedbytes);
|
let bytes = AddrBytes::from(typedbytes);
|
||||||
index.increment();
|
index.increment();
|
||||||
AddressHash::from(&bytes)
|
AddrHash::from(&bytes)
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
as Box<dyn Iterator<Item = AddressHash> + '_>)
|
as Box<dyn Iterator<Item = AddrHash> + '_>)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
Ok(Box::new(std::iter::empty())
|
Ok(Box::new(std::iter::empty())
|
||||||
as Box<dyn Iterator<Item = AddressHash> + '_>)
|
as Box<dyn Iterator<Item = AddrHash> + '_>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
match address_type {
|
match addr_type {
|
||||||
OutputType::P2PK65 => make_iter!(self.p2pk65),
|
OutputType::P2PK65 => make_iter!(self.p2pk65),
|
||||||
OutputType::P2PK33 => make_iter!(self.p2pk33),
|
OutputType::P2PK33 => make_iter!(self.p2pk33),
|
||||||
OutputType::P2PKH => make_iter!(self.p2pkh),
|
OutputType::P2PKH => make_iter!(self.p2pkh),
|
||||||
@@ -258,11 +258,11 @@ impl AddressesVecs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_address_readers {
|
macro_rules! impl_addr_readers {
|
||||||
($mode:ty) => {
|
($mode:ty) => {
|
||||||
impl AddressesVecs<$mode> {
|
impl AddrsVecs<$mode> {
|
||||||
pub fn address_readers(&self) -> AddressReaders {
|
pub fn addr_readers(&self) -> AddrReaders {
|
||||||
AddressReaders {
|
AddrReaders {
|
||||||
p2pk65: self.p2pk65.bytes.reader(),
|
p2pk65: self.p2pk65.bytes.reader(),
|
||||||
p2pk33: self.p2pk33.bytes.reader(),
|
p2pk33: self.p2pk33.bytes.reader(),
|
||||||
p2pkh: self.p2pkh.bytes.reader(),
|
p2pkh: self.p2pkh.bytes.reader(),
|
||||||
@@ -277,5 +277,5 @@ macro_rules! impl_address_readers {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_address_readers!(Rw);
|
impl_addr_readers!(Rw);
|
||||||
impl_address_readers!(Ro);
|
impl_addr_readers!(Ro);
|
||||||
@@ -2,7 +2,7 @@ use std::path::Path;
|
|||||||
|
|
||||||
use brk_error::Result;
|
use brk_error::Result;
|
||||||
use brk_traversable::Traversable;
|
use brk_traversable::Traversable;
|
||||||
use brk_types::{AddressHash, Height, OutputType, Version};
|
use brk_types::{AddrHash, Height, OutputType, Version};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use vecdb::{AnyStoredVec, Database, Rw, Stamp, StorageMode};
|
use vecdb::{AnyStoredVec, Database, Rw, Stamp, StorageMode};
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ const PAGE_SIZE: usize = 4096;
|
|||||||
|
|
||||||
use crate::parallel_import;
|
use crate::parallel_import;
|
||||||
|
|
||||||
mod addresses;
|
mod addrs;
|
||||||
mod blocks;
|
mod blocks;
|
||||||
mod inputs;
|
mod inputs;
|
||||||
mod macros;
|
mod macros;
|
||||||
@@ -18,7 +18,7 @@ mod outputs;
|
|||||||
mod scripts;
|
mod scripts;
|
||||||
mod transactions;
|
mod transactions;
|
||||||
|
|
||||||
pub use addresses::*;
|
pub use addrs::*;
|
||||||
pub use blocks::*;
|
pub use blocks::*;
|
||||||
pub use inputs::*;
|
pub use inputs::*;
|
||||||
pub use outputs::*;
|
pub use outputs::*;
|
||||||
@@ -38,8 +38,8 @@ pub struct Vecs<M: StorageMode = Rw> {
|
|||||||
pub inputs: InputsVecs<M>,
|
pub inputs: InputsVecs<M>,
|
||||||
#[traversable(wrap = "outputs", rename = "raw")]
|
#[traversable(wrap = "outputs", rename = "raw")]
|
||||||
pub outputs: OutputsVecs<M>,
|
pub outputs: OutputsVecs<M>,
|
||||||
#[traversable(wrap = "addresses", rename = "raw")]
|
#[traversable(wrap = "addrs", rename = "raw")]
|
||||||
pub addresses: AddressesVecs<M>,
|
pub addrs: AddrsVecs<M>,
|
||||||
#[traversable(wrap = "scripts", rename = "raw")]
|
#[traversable(wrap = "scripts", rename = "raw")]
|
||||||
pub scripts: ScriptsVecs<M>,
|
pub scripts: ScriptsVecs<M>,
|
||||||
}
|
}
|
||||||
@@ -51,12 +51,12 @@ impl Vecs {
|
|||||||
tracing::debug!("Setting min len...");
|
tracing::debug!("Setting min len...");
|
||||||
db.set_min_len(PAGE_SIZE * 50_000_000)?;
|
db.set_min_len(PAGE_SIZE * 50_000_000)?;
|
||||||
|
|
||||||
let (blocks, transactions, inputs, outputs, addresses, scripts) = parallel_import! {
|
let (blocks, transactions, inputs, outputs, addrs, scripts) = parallel_import! {
|
||||||
blocks = BlocksVecs::forced_import(&db, version),
|
blocks = BlocksVecs::forced_import(&db, version),
|
||||||
transactions = TransactionsVecs::forced_import(&db, version),
|
transactions = TransactionsVecs::forced_import(&db, version),
|
||||||
inputs = InputsVecs::forced_import(&db, version),
|
inputs = InputsVecs::forced_import(&db, version),
|
||||||
outputs = OutputsVecs::forced_import(&db, version),
|
outputs = OutputsVecs::forced_import(&db, version),
|
||||||
addresses = AddressesVecs::forced_import(&db, version),
|
addrs = AddrsVecs::forced_import(&db, version),
|
||||||
scripts = ScriptsVecs::forced_import(&db, version),
|
scripts = ScriptsVecs::forced_import(&db, version),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ impl Vecs {
|
|||||||
transactions,
|
transactions,
|
||||||
inputs,
|
inputs,
|
||||||
outputs,
|
outputs,
|
||||||
addresses,
|
addrs,
|
||||||
scripts,
|
scripts,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -95,16 +95,16 @@ impl Vecs {
|
|||||||
self.outputs
|
self.outputs
|
||||||
.truncate(starting_indexes.height, starting_indexes.txout_index, stamp)?;
|
.truncate(starting_indexes.height, starting_indexes.txout_index, stamp)?;
|
||||||
|
|
||||||
self.addresses.truncate(
|
self.addrs.truncate(
|
||||||
starting_indexes.height,
|
starting_indexes.height,
|
||||||
starting_indexes.p2pk65_address_index,
|
starting_indexes.p2pk65_addr_index,
|
||||||
starting_indexes.p2pk33_address_index,
|
starting_indexes.p2pk33_addr_index,
|
||||||
starting_indexes.p2pkh_address_index,
|
starting_indexes.p2pkh_addr_index,
|
||||||
starting_indexes.p2sh_address_index,
|
starting_indexes.p2sh_addr_index,
|
||||||
starting_indexes.p2wpkh_address_index,
|
starting_indexes.p2wpkh_addr_index,
|
||||||
starting_indexes.p2wsh_address_index,
|
starting_indexes.p2wsh_addr_index,
|
||||||
starting_indexes.p2tr_address_index,
|
starting_indexes.p2tr_addr_index,
|
||||||
starting_indexes.p2a_address_index,
|
starting_indexes.p2a_addr_index,
|
||||||
stamp,
|
stamp,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@@ -148,12 +148,12 @@ impl Vecs {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_address_hashes_from(
|
pub fn iter_addr_hashes_from(
|
||||||
&self,
|
&self,
|
||||||
address_type: OutputType,
|
addr_type: OutputType,
|
||||||
height: Height,
|
height: Height,
|
||||||
) -> Result<Box<dyn Iterator<Item = AddressHash> + '_>> {
|
) -> Result<Box<dyn Iterator<Item = AddrHash> + '_>> {
|
||||||
self.addresses.iter_hashes_from(address_type, height)
|
self.addrs.iter_hashes_from(addr_type, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn par_iter_mut_any_stored_vec(
|
fn par_iter_mut_any_stored_vec(
|
||||||
@@ -164,7 +164,7 @@ impl Vecs {
|
|||||||
.chain(self.transactions.par_iter_mut_any())
|
.chain(self.transactions.par_iter_mut_any())
|
||||||
.chain(self.inputs.par_iter_mut_any())
|
.chain(self.inputs.par_iter_mut_any())
|
||||||
.chain(self.outputs.par_iter_mut_any())
|
.chain(self.outputs.par_iter_mut_any())
|
||||||
.chain(self.addresses.par_iter_mut_any())
|
.chain(self.addrs.par_iter_mut_any())
|
||||||
.chain(self.scripts.par_iter_mut_any())
|
.chain(self.scripts.par_iter_mut_any())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,9 +63,9 @@ fn main() -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Address tracking stats
|
// Address tracking stats
|
||||||
let addresses = mempool.get_addresses();
|
let addrs = mempool.get_addrs();
|
||||||
println!("\n=== Address Tracking ===");
|
println!("\n=== Address Tracking ===");
|
||||||
println!(" Addresses with pending txs: {}", addresses.len());
|
println!(" Addresses with pending txs: {}", addrs.len());
|
||||||
|
|
||||||
println!("\n----------------------------------------");
|
println!("\n----------------------------------------");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
use brk_types::{AddressBytes, AddressMempoolStats, Transaction, Txid};
|
use brk_types::{AddrBytes, AddrMempoolStats, Transaction, Txid};
|
||||||
use derive_more::Deref;
|
use derive_more::Deref;
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
/// Per-address stats with associated transaction set.
|
/// Per-address stats with associated transaction set.
|
||||||
pub type AddressStats = (AddressMempoolStats, FxHashSet<Txid>);
|
pub type AddrStats = (AddrMempoolStats, FxHashSet<Txid>);
|
||||||
|
|
||||||
/// Tracks per-address mempool statistics.
|
/// Tracks per-address mempool statistics.
|
||||||
#[derive(Default, Deref)]
|
#[derive(Default, Deref)]
|
||||||
pub struct AddressTracker(FxHashMap<AddressBytes, AddressStats>);
|
pub struct AddrTracker(FxHashMap<AddrBytes, AddrStats>);
|
||||||
|
|
||||||
impl AddressTracker {
|
impl AddrTracker {
|
||||||
/// Add a transaction to address tracking.
|
/// Add a transaction to address tracking.
|
||||||
pub fn add_tx(&mut self, tx: &Transaction, txid: &Txid) {
|
pub fn add_tx(&mut self, tx: &Transaction, txid: &Txid) {
|
||||||
self.update(tx, txid, true);
|
self.update(tx, txid, true);
|
||||||
@@ -26,7 +26,7 @@ impl AddressTracker {
|
|||||||
let Some(prevout) = txin.prevout.as_ref() else {
|
let Some(prevout) = txin.prevout.as_ref() else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let Some(bytes) = prevout.address_bytes() else {
|
let Some(bytes) = prevout.addr_bytes() else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ impl AddressTracker {
|
|||||||
|
|
||||||
// Outputs: track receiving
|
// Outputs: track receiving
|
||||||
for txout in &tx.output {
|
for txout in &tx.output {
|
||||||
let Some(bytes) = txout.address_bytes() else {
|
let Some(bytes) = txout.addr_bytes() else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
mod addresses;
|
mod addrs;
|
||||||
mod block_builder;
|
mod block_builder;
|
||||||
mod entry;
|
mod entry;
|
||||||
mod entry_pool;
|
mod entry_pool;
|
||||||
|
|||||||
@@ -10,14 +10,14 @@ use std::{
|
|||||||
|
|
||||||
use brk_error::Result;
|
use brk_error::Result;
|
||||||
use brk_rpc::Client;
|
use brk_rpc::Client;
|
||||||
use brk_types::{AddressBytes, MempoolEntryInfo, MempoolInfo, TxWithHex, Txid, TxidPrefix};
|
use brk_types::{AddrBytes, MempoolEntryInfo, MempoolInfo, TxWithHex, Txid, TxidPrefix};
|
||||||
use derive_more::Deref;
|
use derive_more::Deref;
|
||||||
use parking_lot::{RwLock, RwLockReadGuard};
|
use parking_lot::{RwLock, RwLockReadGuard};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
addresses::AddressTracker,
|
addrs::AddrTracker,
|
||||||
block_builder::build_projected_blocks,
|
block_builder::build_projected_blocks,
|
||||||
entry::Entry,
|
entry::Entry,
|
||||||
entry_pool::EntryPool,
|
entry_pool::EntryPool,
|
||||||
@@ -49,7 +49,7 @@ pub struct MempoolInner {
|
|||||||
|
|
||||||
info: RwLock<MempoolInfo>,
|
info: RwLock<MempoolInfo>,
|
||||||
txs: RwLock<TxStore>,
|
txs: RwLock<TxStore>,
|
||||||
addresses: RwLock<AddressTracker>,
|
addrs: RwLock<AddrTracker>,
|
||||||
entries: RwLock<EntryPool>,
|
entries: RwLock<EntryPool>,
|
||||||
|
|
||||||
snapshot: RwLock<Snapshot>,
|
snapshot: RwLock<Snapshot>,
|
||||||
@@ -64,7 +64,7 @@ impl MempoolInner {
|
|||||||
client,
|
client,
|
||||||
info: RwLock::new(MempoolInfo::default()),
|
info: RwLock::new(MempoolInfo::default()),
|
||||||
txs: RwLock::new(TxStore::default()),
|
txs: RwLock::new(TxStore::default()),
|
||||||
addresses: RwLock::new(AddressTracker::default()),
|
addrs: RwLock::new(AddrTracker::default()),
|
||||||
entries: RwLock::new(EntryPool::default()),
|
entries: RwLock::new(EntryPool::default()),
|
||||||
snapshot: RwLock::new(Snapshot::default()),
|
snapshot: RwLock::new(Snapshot::default()),
|
||||||
dirty: AtomicBool::new(false),
|
dirty: AtomicBool::new(false),
|
||||||
@@ -92,9 +92,9 @@ impl MempoolInner {
|
|||||||
self.snapshot.read().next_block_hash()
|
self.snapshot.read().next_block_hash()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn address_hash(&self, address: &AddressBytes) -> u64 {
|
pub fn addr_hash(&self, addr: &AddrBytes) -> u64 {
|
||||||
let addresses = self.addresses.read();
|
let addrs = self.addrs.read();
|
||||||
let Some((stats, _)) = addresses.get(address) else {
|
let Some((stats, _)) = addrs.get(addr) else {
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
let mut hasher = DefaultHasher::new();
|
let mut hasher = DefaultHasher::new();
|
||||||
@@ -106,8 +106,8 @@ impl MempoolInner {
|
|||||||
self.txs.read()
|
self.txs.read()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_addresses(&self) -> RwLockReadGuard<'_, AddressTracker> {
|
pub fn get_addrs(&self) -> RwLockReadGuard<'_, AddrTracker> {
|
||||||
self.addresses.read()
|
self.addrs.read()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start an infinite update loop with a 1 second interval.
|
/// Start an infinite update loop with a 1 second interval.
|
||||||
@@ -173,7 +173,7 @@ impl MempoolInner {
|
|||||||
|
|
||||||
let mut info = self.info.write();
|
let mut info = self.info.write();
|
||||||
let mut txs = self.txs.write();
|
let mut txs = self.txs.write();
|
||||||
let mut addresses = self.addresses.write();
|
let mut addrs = self.addrs.write();
|
||||||
let mut entries = self.entries.write();
|
let mut entries = self.entries.write();
|
||||||
|
|
||||||
let mut had_removals = false;
|
let mut had_removals = false;
|
||||||
@@ -190,7 +190,7 @@ impl MempoolInner {
|
|||||||
// Get fee from entries (before removing) - this is the authoritative fee from Bitcoin Core
|
// Get fee from entries (before removing) - this is the authoritative fee from Bitcoin Core
|
||||||
let fee = entries.get(&prefix).map(|e| e.fee).unwrap_or_default();
|
let fee = entries.get(&prefix).map(|e| e.fee).unwrap_or_default();
|
||||||
info.remove(tx, fee);
|
info.remove(tx, fee);
|
||||||
addresses.remove_tx(tx, txid);
|
addrs.remove_tx(tx, txid);
|
||||||
entries.remove(&prefix);
|
entries.remove(&prefix);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -205,7 +205,7 @@ impl MempoolInner {
|
|||||||
};
|
};
|
||||||
|
|
||||||
info.add(tx, entry_info.fee);
|
info.add(tx, entry_info.fee);
|
||||||
addresses.add_tx(tx, txid);
|
addrs.add_tx(tx, txid);
|
||||||
entries.insert(prefix, Entry::from_info(entry_info));
|
entries.insert(prefix, Entry::from_info(entry_info));
|
||||||
}
|
}
|
||||||
txs.extend(new_txs);
|
txs.extend(new_txs);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use brk_mempool::Mempool;
|
|||||||
use brk_query::Query;
|
use brk_query::Query;
|
||||||
use brk_reader::Reader;
|
use brk_reader::Reader;
|
||||||
use brk_rpc::{Auth, Client};
|
use brk_rpc::{Auth, Client};
|
||||||
use brk_types::{Address, OutputType};
|
use brk_types::{Addr, OutputType};
|
||||||
use vecdb::Exit;
|
use vecdb::Exit;
|
||||||
|
|
||||||
pub fn main() -> Result<()> {
|
pub fn main() -> Result<()> {
|
||||||
@@ -48,22 +48,22 @@ pub fn main() -> Result<()> {
|
|||||||
dbg!(
|
dbg!(
|
||||||
indexer
|
indexer
|
||||||
.stores
|
.stores
|
||||||
.address_type_to_address_hash_to_address_index
|
.addr_type_to_addr_hash_to_addr_index
|
||||||
.get_unwrap(OutputType::P2WSH)
|
.get_unwrap(OutputType::P2WSH)
|
||||||
.approximate_len()
|
.approximate_len()
|
||||||
);
|
);
|
||||||
|
|
||||||
let _ = dbg!(query.address(Address::from(
|
let _ = dbg!(query.addr(Addr::from(
|
||||||
"bc1qwzrryqr3ja8w7hnja2spmkgfdcgvqwp5swz4af4ngsjecfz0w0pqud7k38".to_string(),
|
"bc1qwzrryqr3ja8w7hnja2spmkgfdcgvqwp5swz4af4ngsjecfz0w0pqud7k38".to_string(),
|
||||||
)));
|
)));
|
||||||
|
|
||||||
let _ = dbg!(query.address_txids(
|
let _ = dbg!(query.addr_txids(
|
||||||
Address::from("bc1qwzrryqr3ja8w7hnja2spmkgfdcgvqwp5swz4af4ngsjecfz0w0pqud7k38".to_string()),
|
Addr::from("bc1qwzrryqr3ja8w7hnja2spmkgfdcgvqwp5swz4af4ngsjecfz0w0pqud7k38".to_string()),
|
||||||
None,
|
None,
|
||||||
25
|
25
|
||||||
));
|
));
|
||||||
|
|
||||||
let _ = dbg!(query.address_utxos(Address::from(
|
let _ = dbg!(query.addr_utxos(Addr::from(
|
||||||
"bc1qwzrryqr3ja8w7hnja2spmkgfdcgvqwp5swz4af4ngsjecfz0w0pqud7k38".to_string()
|
"bc1qwzrryqr3ja8w7hnja2spmkgfdcgvqwp5swz4af4ngsjecfz0w0pqud7k38".to_string()
|
||||||
)));
|
)));
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ impl AsyncQuery {
|
|||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// let address_stats = query.run(move |q| q.address(address)).await?;
|
/// let addr_stats = query.run(move |q| q.addr(addr)).await?;
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn run<F, T>(&self, f: F) -> Result<T>
|
pub async fn run<F, T>(&self, f: F) -> Result<T>
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ use std::str::FromStr;
|
|||||||
use bitcoin::{Network, PublicKey, ScriptBuf};
|
use bitcoin::{Network, PublicKey, ScriptBuf};
|
||||||
use brk_error::{Error, Result};
|
use brk_error::{Error, Result};
|
||||||
use brk_types::{
|
use brk_types::{
|
||||||
Address, AddressBytes, AddressChainStats, AddressHash, AddressIndexOutPoint,
|
Addr, AddrBytes, AddrChainStats, AddrHash, AddrIndexOutPoint, AddrIndexTxIndex, AddrStats,
|
||||||
AddressIndexTxIndex, AddressStats, AnyAddressDataIndexEnum, OutputType, Sats, Transaction,
|
AnyAddrDataIndexEnum, OutputType, Sats, Transaction, TxIndex, TxStatus, Txid, TypeIndex, Unit,
|
||||||
TxIndex, TxStatus, Txid, TypeIndex, Unit, Utxo, Vout,
|
Utxo, Vout,
|
||||||
};
|
};
|
||||||
use vecdb::{ReadableVec, VecIndex};
|
use vecdb::{ReadableVec, VecIndex};
|
||||||
|
|
||||||
@@ -15,73 +15,73 @@ use crate::Query;
|
|||||||
const MAX_MEMPOOL_TXIDS: usize = 50;
|
const MAX_MEMPOOL_TXIDS: usize = 50;
|
||||||
|
|
||||||
impl Query {
|
impl Query {
|
||||||
pub fn address(&self, address: Address) -> Result<AddressStats> {
|
pub fn addr(&self, addr: Addr) -> Result<AddrStats> {
|
||||||
let indexer = self.indexer();
|
let indexer = self.indexer();
|
||||||
let computer = self.computer();
|
let computer = self.computer();
|
||||||
let stores = &indexer.stores;
|
let stores = &indexer.stores;
|
||||||
|
|
||||||
let script = if let Ok(address) = bitcoin::Address::from_str(&address) {
|
let script = if let Ok(addr) = bitcoin::Address::from_str(&addr) {
|
||||||
if !address.is_valid_for_network(Network::Bitcoin) {
|
if !addr.is_valid_for_network(Network::Bitcoin) {
|
||||||
return Err(Error::InvalidNetwork);
|
return Err(Error::InvalidNetwork);
|
||||||
}
|
}
|
||||||
let address = address.assume_checked();
|
let addr = addr.assume_checked();
|
||||||
address.script_pubkey()
|
addr.script_pubkey()
|
||||||
} else if let Ok(pubkey) = PublicKey::from_str(&address) {
|
} else if let Ok(pubkey) = PublicKey::from_str(&addr) {
|
||||||
ScriptBuf::new_p2pk(&pubkey)
|
ScriptBuf::new_p2pk(&pubkey)
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::InvalidAddress);
|
return Err(Error::InvalidAddr);
|
||||||
};
|
};
|
||||||
|
|
||||||
let output_type = OutputType::from(&script);
|
let output_type = OutputType::from(&script);
|
||||||
let Ok(bytes) = AddressBytes::try_from((&script, output_type)) else {
|
let Ok(bytes) = AddrBytes::try_from((&script, output_type)) else {
|
||||||
return Err(Error::InvalidAddress);
|
return Err(Error::InvalidAddr);
|
||||||
};
|
};
|
||||||
let address_type = output_type;
|
let addr_type = output_type;
|
||||||
let hash = AddressHash::from(&bytes);
|
let hash = AddrHash::from(&bytes);
|
||||||
|
|
||||||
let Ok(Some(type_index)) = stores
|
let Ok(Some(type_index)) = stores
|
||||||
.address_type_to_address_hash_to_address_index
|
.addr_type_to_addr_hash_to_addr_index
|
||||||
.get_unwrap(address_type)
|
.get_unwrap(addr_type)
|
||||||
.get(&hash)
|
.get(&hash)
|
||||||
.map(|opt| opt.map(|cow| cow.into_owned()))
|
.map(|opt| opt.map(|cow| cow.into_owned()))
|
||||||
else {
|
else {
|
||||||
return Err(Error::UnknownAddress);
|
return Err(Error::UnknownAddr);
|
||||||
};
|
};
|
||||||
|
|
||||||
let any_address_index = computer
|
let any_addr_index = computer
|
||||||
.distribution
|
.distribution
|
||||||
.any_address_indexes
|
.any_addr_indexes
|
||||||
.get_once(output_type, type_index)?;
|
.get_once(output_type, type_index)?;
|
||||||
|
|
||||||
let address_data = match any_address_index.to_enum() {
|
let addr_data = match any_addr_index.to_enum() {
|
||||||
AnyAddressDataIndexEnum::Funded(index) => computer
|
AnyAddrDataIndexEnum::Funded(index) => computer
|
||||||
.distribution
|
.distribution
|
||||||
.addresses_data
|
.addrs_data
|
||||||
.funded
|
.funded
|
||||||
.reader()
|
.reader()
|
||||||
.get(usize::from(index)),
|
.get(usize::from(index)),
|
||||||
AnyAddressDataIndexEnum::Empty(index) => computer
|
AnyAddrDataIndexEnum::Empty(index) => computer
|
||||||
.distribution
|
.distribution
|
||||||
.addresses_data
|
.addrs_data
|
||||||
.empty
|
.empty
|
||||||
.reader()
|
.reader()
|
||||||
.get(usize::from(index))
|
.get(usize::from(index))
|
||||||
.into(),
|
.into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(AddressStats {
|
Ok(AddrStats {
|
||||||
address,
|
addr,
|
||||||
chain_stats: AddressChainStats {
|
chain_stats: AddrChainStats {
|
||||||
type_index,
|
type_index,
|
||||||
funded_txo_count: address_data.funded_txo_count,
|
funded_txo_count: addr_data.funded_txo_count,
|
||||||
funded_txo_sum: address_data.received,
|
funded_txo_sum: addr_data.received,
|
||||||
spent_txo_count: address_data.spent_txo_count,
|
spent_txo_count: addr_data.spent_txo_count,
|
||||||
spent_txo_sum: address_data.sent,
|
spent_txo_sum: addr_data.sent,
|
||||||
tx_count: address_data.tx_count,
|
tx_count: addr_data.tx_count,
|
||||||
},
|
},
|
||||||
mempool_stats: self.mempool().map(|mempool| {
|
mempool_stats: self.mempool().map(|mempool| {
|
||||||
mempool
|
mempool
|
||||||
.get_addresses()
|
.get_addrs()
|
||||||
.get(&bytes)
|
.get(&bytes)
|
||||||
.map(|(stats, _)| stats)
|
.map(|(stats, _)| stats)
|
||||||
.cloned()
|
.cloned()
|
||||||
@@ -90,26 +90,26 @@ impl Query {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn address_txs(
|
pub fn addr_txs(
|
||||||
&self,
|
&self,
|
||||||
address: Address,
|
addr: Addr,
|
||||||
after_txid: Option<Txid>,
|
after_txid: Option<Txid>,
|
||||||
limit: usize,
|
limit: usize,
|
||||||
) -> Result<Vec<Transaction>> {
|
) -> Result<Vec<Transaction>> {
|
||||||
let txindices = self.address_txindices(&address, after_txid, limit)?;
|
let txindices = self.addr_txindices(&addr, after_txid, limit)?;
|
||||||
txindices
|
txindices
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|tx_index| self.transaction_by_index(tx_index))
|
.map(|tx_index| self.transaction_by_index(tx_index))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn address_txids(
|
pub fn addr_txids(
|
||||||
&self,
|
&self,
|
||||||
address: Address,
|
addr: Addr,
|
||||||
after_txid: Option<Txid>,
|
after_txid: Option<Txid>,
|
||||||
limit: usize,
|
limit: usize,
|
||||||
) -> Result<Vec<Txid>> {
|
) -> Result<Vec<Txid>> {
|
||||||
let txindices = self.address_txindices(&address, after_txid, limit)?;
|
let txindices = self.addr_txindices(&addr, after_txid, limit)?;
|
||||||
let txid_reader = self.indexer().vecs.transactions.txid.reader();
|
let txid_reader = self.indexer().vecs.transactions.txid.reader();
|
||||||
let txids = txindices
|
let txids = txindices
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -118,19 +118,19 @@ impl Query {
|
|||||||
Ok(txids)
|
Ok(txids)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn address_txindices(
|
fn addr_txindices(
|
||||||
&self,
|
&self,
|
||||||
address: &Address,
|
addr: &Addr,
|
||||||
after_txid: Option<Txid>,
|
after_txid: Option<Txid>,
|
||||||
limit: usize,
|
limit: usize,
|
||||||
) -> Result<Vec<TxIndex>> {
|
) -> Result<Vec<TxIndex>> {
|
||||||
let indexer = self.indexer();
|
let indexer = self.indexer();
|
||||||
let stores = &indexer.stores;
|
let stores = &indexer.stores;
|
||||||
|
|
||||||
let (output_type, type_index) = self.resolve_address(address)?;
|
let (output_type, type_index) = self.resolve_addr(addr)?;
|
||||||
|
|
||||||
let store = stores
|
let store = stores
|
||||||
.address_type_to_address_index_and_tx_index
|
.addr_type_to_addr_index_and_tx_index
|
||||||
.get(output_type)
|
.get(output_type)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -151,7 +151,7 @@ impl Query {
|
|||||||
Ok(store
|
Ok(store
|
||||||
.prefix(prefix)
|
.prefix(prefix)
|
||||||
.rev()
|
.rev()
|
||||||
.filter(|(key, _): &(AddressIndexTxIndex, Unit)| {
|
.filter(|(key, _): &(AddrIndexTxIndex, Unit)| {
|
||||||
if let Some(after) = after_tx_index {
|
if let Some(after) = after_tx_index {
|
||||||
key.tx_index() < after
|
key.tx_index() < after
|
||||||
} else {
|
} else {
|
||||||
@@ -163,15 +163,15 @@ impl Query {
|
|||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn address_utxos(&self, address: Address) -> Result<Vec<Utxo>> {
|
pub fn addr_utxos(&self, addr: Addr) -> Result<Vec<Utxo>> {
|
||||||
let indexer = self.indexer();
|
let indexer = self.indexer();
|
||||||
let stores = &indexer.stores;
|
let stores = &indexer.stores;
|
||||||
let vecs = &indexer.vecs;
|
let vecs = &indexer.vecs;
|
||||||
|
|
||||||
let (output_type, type_index) = self.resolve_address(&address)?;
|
let (output_type, type_index) = self.resolve_addr(&addr)?;
|
||||||
|
|
||||||
let store = stores
|
let store = stores
|
||||||
.address_type_to_address_index_and_unspent_outpoint
|
.addr_type_to_addr_index_and_unspent_outpoint
|
||||||
.get(output_type)
|
.get(output_type)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -179,7 +179,7 @@ impl Query {
|
|||||||
|
|
||||||
let outpoints: Vec<(TxIndex, Vout)> = store
|
let outpoints: Vec<(TxIndex, Vout)> = store
|
||||||
.prefix(prefix)
|
.prefix(prefix)
|
||||||
.map(|(key, _): (AddressIndexOutPoint, Unit)| (key.tx_index(), key.vout()))
|
.map(|(key, _): (AddrIndexOutPoint, Unit)| (key.tx_index(), key.vout()))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let txid_reader = vecs.transactions.txid.reader();
|
let txid_reader = vecs.transactions.txid.reader();
|
||||||
@@ -223,23 +223,23 @@ impl Query {
|
|||||||
Ok(utxos)
|
Ok(utxos)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn address_mempool_hash(&self, address: &Address) -> u64 {
|
pub fn addr_mempool_hash(&self, addr: &Addr) -> u64 {
|
||||||
let Some(mempool) = self.mempool() else {
|
let Some(mempool) = self.mempool() else {
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
let Ok(bytes) = AddressBytes::from_str(address) else {
|
let Ok(bytes) = AddrBytes::from_str(addr) else {
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
mempool.address_hash(&bytes)
|
mempool.addr_hash(&bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn address_mempool_txids(&self, address: Address) -> Result<Vec<Txid>> {
|
pub fn addr_mempool_txids(&self, addr: Addr) -> Result<Vec<Txid>> {
|
||||||
let mempool = self.mempool().ok_or(Error::MempoolNotAvailable)?;
|
let mempool = self.mempool().ok_or(Error::MempoolNotAvailable)?;
|
||||||
|
|
||||||
let bytes = AddressBytes::from_str(&address)?;
|
let bytes = AddrBytes::from_str(&addr)?;
|
||||||
let addresses = mempool.get_addresses();
|
let addrs = mempool.get_addrs();
|
||||||
|
|
||||||
let txids: Vec<Txid> = addresses
|
let txids: Vec<Txid> = addrs
|
||||||
.get(&bytes)
|
.get(&bytes)
|
||||||
.map(|(_, txids)| txids.iter().take(MAX_MEMPOOL_TXIDS).cloned().collect())
|
.map(|(_, txids)| txids.iter().take(MAX_MEMPOOL_TXIDS).cloned().collect())
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
@@ -248,21 +248,21 @@ impl Query {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve an address string to its output type and type_index
|
/// Resolve an address string to its output type and type_index
|
||||||
fn resolve_address(&self, address: &Address) -> Result<(OutputType, TypeIndex)> {
|
fn resolve_addr(&self, addr: &Addr) -> Result<(OutputType, TypeIndex)> {
|
||||||
let stores = &self.indexer().stores;
|
let stores = &self.indexer().stores;
|
||||||
|
|
||||||
let bytes = AddressBytes::from_str(address)?;
|
let bytes = AddrBytes::from_str(addr)?;
|
||||||
let output_type = OutputType::from(&bytes);
|
let output_type = OutputType::from(&bytes);
|
||||||
let hash = AddressHash::from(&bytes);
|
let hash = AddrHash::from(&bytes);
|
||||||
|
|
||||||
let Ok(Some(type_index)) = stores
|
let Ok(Some(type_index)) = stores
|
||||||
.address_type_to_address_hash_to_address_index
|
.addr_type_to_addr_hash_to_addr_index
|
||||||
.get(output_type)
|
.get(output_type)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get(&hash)
|
.get(&hash)
|
||||||
.map(|opt| opt.map(|cow| cow.into_owned()))
|
.map(|opt| opt.map(|cow| cow.into_owned()))
|
||||||
else {
|
else {
|
||||||
return Err(Error::UnknownAddress);
|
return Err(Error::UnknownAddr);
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((output_type, type_index))
|
Ok((output_type, type_index))
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
mod address;
|
mod addr;
|
||||||
mod block;
|
mod block;
|
||||||
mod cost_basis;
|
mod cost_basis;
|
||||||
mod mempool;
|
mod mempool;
|
||||||
mod series;
|
|
||||||
mod mining;
|
mod mining;
|
||||||
mod price;
|
mod price;
|
||||||
mod transaction;
|
mod series;
|
||||||
|
mod tx;
|
||||||
|
|
||||||
pub use block::BLOCK_TXS_PAGE_SIZE;
|
pub use block::BLOCK_TXS_PAGE_SIZE;
|
||||||
pub use series::ResolvedQuery;
|
pub use series::ResolvedQuery;
|
||||||
|
|||||||
@@ -244,7 +244,7 @@ impl Query {
|
|||||||
let value_reader = indexer.vecs.outputs.value.reader();
|
let value_reader = indexer.vecs.outputs.value.reader();
|
||||||
let output_type_reader = indexer.vecs.outputs.output_type.reader();
|
let output_type_reader = indexer.vecs.outputs.output_type.reader();
|
||||||
let type_index_reader = indexer.vecs.outputs.type_index.reader();
|
let type_index_reader = indexer.vecs.outputs.type_index.reader();
|
||||||
let address_readers = indexer.vecs.addresses.address_readers();
|
let addr_readers = indexer.vecs.addrs.addr_readers();
|
||||||
|
|
||||||
// Batch-read outpoints for all inputs (avoids per-input PcoVec page decompression)
|
// Batch-read outpoints for all inputs (avoids per-input PcoVec page decompression)
|
||||||
let outpoints: Vec<_> = indexer.vecs.inputs.outpoint.collect_range_at(
|
let outpoints: Vec<_> = indexer.vecs.inputs.outpoint.collect_range_at(
|
||||||
@@ -280,7 +280,7 @@ impl Query {
|
|||||||
output_type_reader.get(usize::from(prev_txout_index));
|
output_type_reader.get(usize::from(prev_txout_index));
|
||||||
let prev_type_index = type_index_reader.get(usize::from(prev_txout_index));
|
let prev_type_index = type_index_reader.get(usize::from(prev_txout_index));
|
||||||
let script_pubkey =
|
let script_pubkey =
|
||||||
address_readers.script_pubkey(prev_output_type, prev_type_index);
|
addr_readers.script_pubkey(prev_output_type, prev_type_index);
|
||||||
|
|
||||||
let prevout = Some(TxOut::from((script_pubkey, prev_value)));
|
let prevout = Some(TxOut::from((script_pubkey, prev_value)));
|
||||||
|
|
||||||
@@ -6,20 +6,20 @@ use axum::{
|
|||||||
routing::get,
|
routing::get,
|
||||||
};
|
};
|
||||||
use brk_types::{
|
use brk_types::{
|
||||||
AddressParam, AddressStats, AddressTxidsParam, AddressValidation, Transaction, Txid, Utxo,
|
AddrParam, AddrStats, AddrTxidsParam, AddrValidation, Transaction, Txid, Utxo,
|
||||||
ValidateAddressParam,
|
ValidateAddrParam,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{CacheStrategy, extended::TransformResponseExtended};
|
use crate::{CacheStrategy, extended::TransformResponseExtended};
|
||||||
|
|
||||||
use super::AppState;
|
use super::AppState;
|
||||||
|
|
||||||
pub trait AddressRoutes {
|
pub trait AddrRoutes {
|
||||||
fn add_addresses_routes(self) -> Self;
|
fn add_addr_routes(self) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddressRoutes for ApiRouter<AppState> {
|
impl AddrRoutes for ApiRouter<AppState> {
|
||||||
fn add_addresses_routes(self) -> Self {
|
fn add_addr_routes(self) -> Self {
|
||||||
self
|
self
|
||||||
.route("/api/address", get(Redirect::temporary("/api/addresses")))
|
.route("/api/address", get(Redirect::temporary("/api/addresses")))
|
||||||
.route("/api/addresses", get(Redirect::temporary("/api#tag/addresses")))
|
.route("/api/addresses", get(Redirect::temporary("/api#tag/addresses")))
|
||||||
@@ -28,16 +28,16 @@ impl AddressRoutes for ApiRouter<AppState> {
|
|||||||
get_with(async |
|
get_with(async |
|
||||||
uri: Uri,
|
uri: Uri,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
Path(path): Path<AddressParam>,
|
Path(path): Path<AddrParam>,
|
||||||
State(state): State<AppState>
|
State(state): State<AppState>
|
||||||
| {
|
| {
|
||||||
state.cached_json(&headers, CacheStrategy::Height, &uri, move |q| q.address(path.address)).await
|
state.cached_json(&headers, CacheStrategy::Height, &uri, move |q| q.addr(path.addr)).await
|
||||||
}, |op| op
|
}, |op| op
|
||||||
.id("get_address")
|
.id("get_address")
|
||||||
.addresses_tag()
|
.addrs_tag()
|
||||||
.summary("Address information")
|
.summary("Address information")
|
||||||
.description("Retrieve address information including balance and transaction counts. Supports all standard Bitcoin address types (P2PKH, P2SH, P2WPKH, P2WSH, P2TR).\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-address)*")
|
.description("Retrieve address information including balance and transaction counts. Supports all standard Bitcoin address types (P2PKH, P2SH, P2WPKH, P2WSH, P2TR).\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-address)*")
|
||||||
.ok_response::<AddressStats>()
|
.ok_response::<AddrStats>()
|
||||||
.not_modified()
|
.not_modified()
|
||||||
.bad_request()
|
.bad_request()
|
||||||
.not_found()
|
.not_found()
|
||||||
@@ -49,14 +49,14 @@ impl AddressRoutes for ApiRouter<AppState> {
|
|||||||
get_with(async |
|
get_with(async |
|
||||||
uri: Uri,
|
uri: Uri,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
Path(path): Path<AddressParam>,
|
Path(path): Path<AddrParam>,
|
||||||
Query(params): Query<AddressTxidsParam>,
|
Query(params): Query<AddrTxidsParam>,
|
||||||
State(state): State<AppState>
|
State(state): State<AppState>
|
||||||
| {
|
| {
|
||||||
state.cached_json(&headers, CacheStrategy::Height, &uri, move |q| q.address_txs(path.address, params.after_txid, 25)).await
|
state.cached_json(&headers, CacheStrategy::Height, &uri, move |q| q.addr_txs(path.addr, params.after_txid, 25)).await
|
||||||
}, |op| op
|
}, |op| op
|
||||||
.id("get_address_txs")
|
.id("get_address_txs")
|
||||||
.addresses_tag()
|
.addrs_tag()
|
||||||
.summary("Address transactions")
|
.summary("Address transactions")
|
||||||
.description("Get transaction history for an address, sorted with newest first. Returns up to 50 mempool transactions plus the first 25 confirmed transactions. Use ?after_txid=<txid> for pagination.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-address-transactions)*")
|
.description("Get transaction history for an address, sorted with newest first. Returns up to 50 mempool transactions plus the first 25 confirmed transactions. Use ?after_txid=<txid> for pagination.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-address-transactions)*")
|
||||||
.ok_response::<Vec<Transaction>>()
|
.ok_response::<Vec<Transaction>>()
|
||||||
@@ -71,14 +71,14 @@ impl AddressRoutes for ApiRouter<AppState> {
|
|||||||
get_with(async |
|
get_with(async |
|
||||||
uri: Uri,
|
uri: Uri,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
Path(path): Path<AddressParam>,
|
Path(path): Path<AddrParam>,
|
||||||
Query(params): Query<AddressTxidsParam>,
|
Query(params): Query<AddrTxidsParam>,
|
||||||
State(state): State<AppState>
|
State(state): State<AppState>
|
||||||
| {
|
| {
|
||||||
state.cached_json(&headers, CacheStrategy::Height, &uri, move |q| q.address_txs(path.address, params.after_txid, 25)).await
|
state.cached_json(&headers, CacheStrategy::Height, &uri, move |q| q.addr_txs(path.addr, params.after_txid, 25)).await
|
||||||
}, |op| op
|
}, |op| op
|
||||||
.id("get_address_confirmed_txs")
|
.id("get_address_confirmed_txs")
|
||||||
.addresses_tag()
|
.addrs_tag()
|
||||||
.summary("Address confirmed transactions")
|
.summary("Address confirmed transactions")
|
||||||
.description("Get confirmed transactions for an address, 25 per page. Use ?after_txid=<txid> for pagination.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-address-transactions-chain)*")
|
.description("Get confirmed transactions for an address, 25 per page. Use ?after_txid=<txid> for pagination.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-address-transactions-chain)*")
|
||||||
.ok_response::<Vec<Transaction>>()
|
.ok_response::<Vec<Transaction>>()
|
||||||
@@ -93,14 +93,14 @@ impl AddressRoutes for ApiRouter<AppState> {
|
|||||||
get_with(async |
|
get_with(async |
|
||||||
uri: Uri,
|
uri: Uri,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
Path(path): Path<AddressParam>,
|
Path(path): Path<AddrParam>,
|
||||||
State(state): State<AppState>
|
State(state): State<AppState>
|
||||||
| {
|
| {
|
||||||
let hash = state.sync(|q| q.address_mempool_hash(&path.address));
|
let hash = state.sync(|q| q.addr_mempool_hash(&path.addr));
|
||||||
state.cached_json(&headers, CacheStrategy::MempoolHash(hash), &uri, move |q| q.address_mempool_txids(path.address)).await
|
state.cached_json(&headers, CacheStrategy::MempoolHash(hash), &uri, move |q| q.addr_mempool_txids(path.addr)).await
|
||||||
}, |op| op
|
}, |op| op
|
||||||
.id("get_address_mempool_txs")
|
.id("get_address_mempool_txs")
|
||||||
.addresses_tag()
|
.addrs_tag()
|
||||||
.summary("Address mempool transactions")
|
.summary("Address mempool transactions")
|
||||||
.description("Get unconfirmed transaction IDs for an address from the mempool (up to 50).\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-address-transactions-mempool)*")
|
.description("Get unconfirmed transaction IDs for an address from the mempool (up to 50).\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-address-transactions-mempool)*")
|
||||||
.ok_response::<Vec<Txid>>()
|
.ok_response::<Vec<Txid>>()
|
||||||
@@ -114,13 +114,13 @@ impl AddressRoutes for ApiRouter<AppState> {
|
|||||||
get_with(async |
|
get_with(async |
|
||||||
uri: Uri,
|
uri: Uri,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
Path(path): Path<AddressParam>,
|
Path(path): Path<AddrParam>,
|
||||||
State(state): State<AppState>
|
State(state): State<AppState>
|
||||||
| {
|
| {
|
||||||
state.cached_json(&headers, CacheStrategy::Height, &uri, move |q| q.address_utxos(path.address)).await
|
state.cached_json(&headers, CacheStrategy::Height, &uri, move |q| q.addr_utxos(path.addr)).await
|
||||||
}, |op| op
|
}, |op| op
|
||||||
.id("get_address_utxos")
|
.id("get_address_utxos")
|
||||||
.addresses_tag()
|
.addrs_tag()
|
||||||
.summary("Address UTXOs")
|
.summary("Address UTXOs")
|
||||||
.description("Get unspent transaction outputs (UTXOs) for an address. Returns txid, vout, value, and confirmation status for each UTXO.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-address-utxo)*")
|
.description("Get unspent transaction outputs (UTXOs) for an address. Returns txid, vout, value, and confirmation status for each UTXO.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-address-utxo)*")
|
||||||
.ok_response::<Vec<Utxo>>()
|
.ok_response::<Vec<Utxo>>()
|
||||||
@@ -135,16 +135,16 @@ impl AddressRoutes for ApiRouter<AppState> {
|
|||||||
get_with(async |
|
get_with(async |
|
||||||
uri: Uri,
|
uri: Uri,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
Path(path): Path<ValidateAddressParam>,
|
Path(path): Path<ValidateAddrParam>,
|
||||||
State(state): State<AppState>
|
State(state): State<AppState>
|
||||||
| {
|
| {
|
||||||
state.cached_json(&headers, CacheStrategy::Static, &uri, move |_q| Ok(AddressValidation::from_address(&path.address))).await
|
state.cached_json(&headers, CacheStrategy::Static, &uri, move |_q| Ok(AddrValidation::from_addr(&path.addr))).await
|
||||||
}, |op| op
|
}, |op| op
|
||||||
.id("validate_address")
|
.id("validate_address")
|
||||||
.addresses_tag()
|
.addrs_tag()
|
||||||
.summary("Validate address")
|
.summary("Validate address")
|
||||||
.description("Validate a Bitcoin address and get information about its type and scriptPubKey.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-address-validate)*")
|
.description("Validate a Bitcoin address and get information about its type and scriptPubKey.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-address-validate)*")
|
||||||
.ok_response::<AddressValidation>()
|
.ok_response::<AddrValidation>()
|
||||||
.not_modified()
|
.not_modified()
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -14,7 +14,7 @@ use axum::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
Error,
|
Error,
|
||||||
api::{
|
api::{
|
||||||
addresses::AddressRoutes, blocks::BlockRoutes, mempool::MempoolRoutes,
|
addrs::AddrRoutes, blocks::BlockRoutes, mempool::MempoolRoutes,
|
||||||
metrics_legacy::ApiMetricsLegacyRoutes, mining::MiningRoutes,
|
metrics_legacy::ApiMetricsLegacyRoutes, mining::MiningRoutes,
|
||||||
series::ApiSeriesRoutes, server::ServerRoutes, transactions::TxRoutes,
|
series::ApiSeriesRoutes, server::ServerRoutes, transactions::TxRoutes,
|
||||||
},
|
},
|
||||||
@@ -23,7 +23,7 @@ use crate::{
|
|||||||
|
|
||||||
use super::AppState;
|
use super::AppState;
|
||||||
|
|
||||||
mod addresses;
|
mod addrs;
|
||||||
mod blocks;
|
mod blocks;
|
||||||
mod mempool;
|
mod mempool;
|
||||||
mod metrics_legacy;
|
mod metrics_legacy;
|
||||||
@@ -46,7 +46,7 @@ impl ApiRoutes for ApiRouter<AppState> {
|
|||||||
.add_metrics_legacy_routes()
|
.add_metrics_legacy_routes()
|
||||||
.add_block_routes()
|
.add_block_routes()
|
||||||
.add_tx_routes()
|
.add_tx_routes()
|
||||||
.add_addresses_routes()
|
.add_addr_routes()
|
||||||
.add_mempool_routes()
|
.add_mempool_routes()
|
||||||
.add_mining_routes()
|
.add_mining_routes()
|
||||||
.route("/api/server", get(Redirect::temporary("/api#tag/server")))
|
.route("/api/server", get(Redirect::temporary("/api#tag/server")))
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ struct ErrorDetail {
|
|||||||
/// Error category: "invalid_request", "forbidden", "not_found", "unavailable", or "internal"
|
/// Error category: "invalid_request", "forbidden", "not_found", "unavailable", or "internal"
|
||||||
#[schemars(with = "String")]
|
#[schemars(with = "String")]
|
||||||
r#type: &'static str,
|
r#type: &'static str,
|
||||||
/// Machine-readable error code (e.g. "invalid_address", "series_not_found")
|
/// Machine-readable error code (e.g. "invalid_addr", "series_not_found")
|
||||||
#[schemars(with = "String")]
|
#[schemars(with = "String")]
|
||||||
code: &'static str,
|
code: &'static str,
|
||||||
/// Human-readable description
|
/// Human-readable description
|
||||||
@@ -47,14 +47,14 @@ fn error_status(e: &BrkError) -> StatusCode {
|
|||||||
match e {
|
match e {
|
||||||
BrkError::InvalidTxid
|
BrkError::InvalidTxid
|
||||||
| BrkError::InvalidNetwork
|
| BrkError::InvalidNetwork
|
||||||
| BrkError::InvalidAddress
|
| BrkError::InvalidAddr
|
||||||
| BrkError::UnsupportedType(_)
|
| BrkError::UnsupportedType(_)
|
||||||
| BrkError::Parse(_)
|
| BrkError::Parse(_)
|
||||||
| BrkError::NoSeries
|
| BrkError::NoSeries
|
||||||
| BrkError::SeriesUnsupportedIndex { .. }
|
| BrkError::SeriesUnsupportedIndex { .. }
|
||||||
| BrkError::WeightExceeded { .. } => StatusCode::BAD_REQUEST,
|
| BrkError::WeightExceeded { .. } => StatusCode::BAD_REQUEST,
|
||||||
|
|
||||||
BrkError::UnknownAddress
|
BrkError::UnknownAddr
|
||||||
| BrkError::UnknownTxid
|
| BrkError::UnknownTxid
|
||||||
| BrkError::NotFound(_)
|
| BrkError::NotFound(_)
|
||||||
| BrkError::NoData
|
| BrkError::NoData
|
||||||
@@ -70,7 +70,7 @@ fn error_status(e: &BrkError) -> StatusCode {
|
|||||||
|
|
||||||
fn error_code(e: &BrkError) -> &'static str {
|
fn error_code(e: &BrkError) -> &'static str {
|
||||||
match e {
|
match e {
|
||||||
BrkError::InvalidAddress => "invalid_address",
|
BrkError::InvalidAddr => "invalid_addr",
|
||||||
BrkError::InvalidTxid => "invalid_txid",
|
BrkError::InvalidTxid => "invalid_txid",
|
||||||
BrkError::InvalidNetwork => "invalid_network",
|
BrkError::InvalidNetwork => "invalid_network",
|
||||||
BrkError::UnsupportedType(_) => "unsupported_type",
|
BrkError::UnsupportedType(_) => "unsupported_type",
|
||||||
@@ -78,7 +78,7 @@ fn error_code(e: &BrkError) -> &'static str {
|
|||||||
BrkError::NoSeries => "no_series",
|
BrkError::NoSeries => "no_series",
|
||||||
BrkError::SeriesUnsupportedIndex { .. } => "series_unsupported_index",
|
BrkError::SeriesUnsupportedIndex { .. } => "series_unsupported_index",
|
||||||
BrkError::WeightExceeded { .. } => "weight_exceeded",
|
BrkError::WeightExceeded { .. } => "weight_exceeded",
|
||||||
BrkError::UnknownAddress => "unknown_address",
|
BrkError::UnknownAddr => "unknown_addr",
|
||||||
BrkError::UnknownTxid => "unknown_txid",
|
BrkError::UnknownTxid => "unknown_txid",
|
||||||
BrkError::NotFound(_) => "not_found",
|
BrkError::NotFound(_) => "not_found",
|
||||||
BrkError::OutOfRange(_) => "out_of_range",
|
BrkError::OutOfRange(_) => "out_of_range",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use schemars::JsonSchema;
|
|||||||
use crate::error::ErrorBody;
|
use crate::error::ErrorBody;
|
||||||
|
|
||||||
pub trait TransformResponseExtended<'t> {
|
pub trait TransformResponseExtended<'t> {
|
||||||
fn addresses_tag(self) -> Self;
|
fn addrs_tag(self) -> Self;
|
||||||
fn blocks_tag(self) -> Self;
|
fn blocks_tag(self) -> Self;
|
||||||
fn mempool_tag(self) -> Self;
|
fn mempool_tag(self) -> Self;
|
||||||
fn metrics_tag(self) -> Self;
|
fn metrics_tag(self) -> Self;
|
||||||
@@ -40,7 +40,7 @@ pub trait TransformResponseExtended<'t> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'t> TransformResponseExtended<'t> for TransformOperation<'t> {
|
impl<'t> TransformResponseExtended<'t> for TransformOperation<'t> {
|
||||||
fn addresses_tag(self) -> Self {
|
fn addrs_tag(self) -> Self {
|
||||||
self.tag("Addresses")
|
self.tag("Addresses")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,9 +59,7 @@ struct FieldInfo<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns None for skip, Some((attr, rename, wrap, hidden)) for normal/flatten/hidden.
|
/// Returns None for skip, Some((attr, rename, wrap, hidden)) for normal/flatten/hidden.
|
||||||
fn get_field_attr(
|
fn get_field_attr(field: &syn::Field) -> Option<(FieldAttr, Option<String>, Option<String>, bool)> {
|
||||||
field: &syn::Field,
|
|
||||||
) -> Option<(FieldAttr, Option<String>, Option<String>, bool)> {
|
|
||||||
let mut attr_type = FieldAttr::Normal;
|
let mut attr_type = FieldAttr::Normal;
|
||||||
let mut rename = None;
|
let mut rename = None;
|
||||||
let mut wrap = None;
|
let mut wrap = None;
|
||||||
@@ -568,13 +566,19 @@ fn generate_iter_body(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn generate_iterator_impl(infos: &[FieldInfo], struct_hidden: bool) -> proc_macro2::TokenStream {
|
fn generate_iterator_impl(infos: &[FieldInfo], struct_hidden: bool) -> proc_macro2::TokenStream {
|
||||||
let all_regular: Vec<_> = infos.iter().filter(|i| !i.is_option).map(|i| i.name).collect();
|
let all_regular: Vec<_> = infos
|
||||||
let all_option: Vec<_> = infos.iter().filter(|i| i.is_option).map(|i| i.name).collect();
|
.iter()
|
||||||
|
.filter(|i| !i.is_option)
|
||||||
|
.map(|i| i.name)
|
||||||
|
.collect();
|
||||||
|
let all_option: Vec<_> = infos
|
||||||
|
.iter()
|
||||||
|
.filter(|i| i.is_option)
|
||||||
|
.map(|i| i.name)
|
||||||
|
.collect();
|
||||||
|
|
||||||
let exportable_body = generate_iter_body(&all_regular, &all_option, "iter_any_exportable");
|
let exportable_body = generate_iter_body(&all_regular, &all_option, "iter_any_exportable");
|
||||||
|
|
||||||
let has_hidden_fields = infos.iter().any(|i| i.hidden);
|
|
||||||
|
|
||||||
let visible_impl = if struct_hidden {
|
let visible_impl = if struct_hidden {
|
||||||
// Entire struct is hidden — iter_any_visible returns nothing
|
// Entire struct is hidden — iter_any_visible returns nothing
|
||||||
quote! {
|
quote! {
|
||||||
@@ -585,9 +589,18 @@ fn generate_iterator_impl(infos: &[FieldInfo], struct_hidden: bool) -> proc_macr
|
|||||||
} else {
|
} else {
|
||||||
// Always generate iter_any_visible that calls iter_any_visible on children
|
// Always generate iter_any_visible that calls iter_any_visible on children
|
||||||
// (skipping hidden fields if any), so hidden propagates through the tree
|
// (skipping hidden fields if any), so hidden propagates through the tree
|
||||||
let visible_regular: Vec<_> = infos.iter().filter(|i| !i.is_option && !i.hidden).map(|i| i.name).collect();
|
let visible_regular: Vec<_> = infos
|
||||||
let visible_option: Vec<_> = infos.iter().filter(|i| i.is_option && !i.hidden).map(|i| i.name).collect();
|
.iter()
|
||||||
let visible_body = generate_iter_body(&visible_regular, &visible_option, "iter_any_visible");
|
.filter(|i| !i.is_option && !i.hidden)
|
||||||
|
.map(|i| i.name)
|
||||||
|
.collect();
|
||||||
|
let visible_option: Vec<_> = infos
|
||||||
|
.iter()
|
||||||
|
.filter(|i| i.is_option && !i.hidden)
|
||||||
|
.map(|i| i.name)
|
||||||
|
.collect();
|
||||||
|
let visible_body =
|
||||||
|
generate_iter_body(&visible_regular, &visible_option, "iter_any_visible");
|
||||||
quote! {
|
quote! {
|
||||||
fn iter_any_visible(&self) -> impl Iterator<Item = &dyn vecdb::AnyExportableVec> {
|
fn iter_any_visible(&self) -> impl Iterator<Item = &dyn vecdb::AnyExportableVec> {
|
||||||
#visible_body
|
#visible_body
|
||||||
|
|||||||
@@ -4,65 +4,66 @@ use bitcoin::ScriptBuf;
|
|||||||
use brk_error::Error;
|
use brk_error::Error;
|
||||||
use derive_more::Deref;
|
use derive_more::Deref;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize, Serializer};
|
use serde::{Deserialize, Serialize};
|
||||||
use vecdb::Formattable;
|
use vecdb::Formattable;
|
||||||
|
|
||||||
use crate::AddressBytes;
|
use crate::AddrBytes;
|
||||||
|
|
||||||
use super::OutputType;
|
use super::OutputType;
|
||||||
|
|
||||||
/// Bitcoin address string
|
/// Bitcoin address string
|
||||||
#[derive(Debug, Clone, Deref, Deserialize, JsonSchema)]
|
#[derive(Debug, Clone, Deref, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
#[schemars(
|
#[schemars(
|
||||||
example = &"04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f",
|
example = &"04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f",
|
||||||
example = &"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
|
example = &"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
|
||||||
example = &"bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq"
|
example = &"bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq"
|
||||||
)]
|
)]
|
||||||
pub struct Address(String);
|
pub struct Addr(String);
|
||||||
|
|
||||||
impl fmt::Display for Address {
|
impl Addr {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
/// Get the script for this address
|
||||||
f.write_str(&self.0)
|
pub fn script(&self) -> Result<ScriptBuf, Error> {
|
||||||
|
AddrBytes::addr_to_script(&self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<String> for Address {
|
impl From<String> for Addr {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(address: String) -> Self {
|
fn from(addr: String) -> Self {
|
||||||
Self(address)
|
Self(addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&ScriptBuf> for Address {
|
impl TryFrom<&ScriptBuf> for Addr {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
fn try_from(script: &ScriptBuf) -> Result<Self, Self::Error> {
|
fn try_from(script: &ScriptBuf) -> Result<Self, Self::Error> {
|
||||||
Self::try_from((script, OutputType::from(script)))
|
Self::try_from((script, OutputType::from(script)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<(&ScriptBuf, OutputType)> for Address {
|
impl TryFrom<(&ScriptBuf, OutputType)> for Addr {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
fn try_from((script, output_type): (&ScriptBuf, OutputType)) -> Result<Self, Self::Error> {
|
fn try_from((script, output_type): (&ScriptBuf, OutputType)) -> Result<Self, Self::Error> {
|
||||||
match output_type {
|
match output_type {
|
||||||
OutputType::P2PK65 | OutputType::P2PK33 => {
|
OutputType::P2PK65 | OutputType::P2PK33 => {
|
||||||
// P2PK has no standard address encoding, use raw pubkey hex
|
// P2PK has no standard address encoding, use raw pubkey hex
|
||||||
let bytes = AddressBytes::try_from((script, output_type))?;
|
let bytes = AddrBytes::try_from((script, output_type))?;
|
||||||
Ok(Self(bytes_to_hex(bytes.as_slice())))
|
Ok(Self(bytes_to_hex(bytes.as_slice())))
|
||||||
}
|
}
|
||||||
_ if output_type.is_address() => {
|
_ if output_type.is_addr() => {
|
||||||
let addr = bitcoin::Address::from_script(script, bitcoin::Network::Bitcoin)
|
let addr = bitcoin::Address::from_script(script, bitcoin::Network::Bitcoin)
|
||||||
.map_err(|_| Error::InvalidAddress)?;
|
.map_err(|_| Error::InvalidAddr)?;
|
||||||
Ok(Self(addr.to_string()))
|
Ok(Self(addr.to_string()))
|
||||||
}
|
}
|
||||||
_ => Err(Error::InvalidAddress),
|
_ => Err(Error::InvalidAddr),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&AddressBytes> for Address {
|
impl TryFrom<&AddrBytes> for Addr {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
fn try_from(bytes: &AddressBytes) -> Result<Self, Self::Error> {
|
fn try_from(bytes: &AddrBytes) -> Result<Self, Self::Error> {
|
||||||
Self::try_from(&bytes.to_script_pubkey())
|
Self::try_from(&bytes.to_script_pubkey())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,32 +77,16 @@ fn bytes_to_hex(bytes: &[u8]) -> String {
|
|||||||
hex_string
|
hex_string
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for Address {
|
impl FromStr for Addr {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: Serializer,
|
|
||||||
{
|
|
||||||
serializer.collect_str(&self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for Address {
|
|
||||||
type Err = Error;
|
type Err = Error;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
let _ = AddressBytes::address_to_script(s)?;
|
let _ = AddrBytes::addr_to_script(s)?;
|
||||||
Ok(Self(s.to_string()))
|
Ok(Self(s.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Address {
|
impl Formattable for Addr {
|
||||||
/// Get the script for this address
|
|
||||||
pub fn script(&self) -> Result<ScriptBuf, Error> {
|
|
||||||
AddressBytes::address_to_script(&self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Formattable for Address {
|
|
||||||
fn write_to(&self, buf: &mut Vec<u8>) {
|
fn write_to(&self, buf: &mut Vec<u8>) {
|
||||||
buf.extend_from_slice(self.0.as_bytes());
|
buf.extend_from_slice(self.0.as_bytes());
|
||||||
}
|
}
|
||||||
@@ -112,3 +97,9 @@ impl Formattable for Address {
|
|||||||
buf.push(b'"');
|
buf.push(b'"');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Addr {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_str(&self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@ use super::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub enum AddressBytes {
|
pub enum AddrBytes {
|
||||||
P2PK65(P2PK65Bytes), // 65
|
P2PK65(P2PK65Bytes), // 65
|
||||||
P2PK33(P2PK33Bytes), // 33
|
P2PK33(P2PK33Bytes), // 33
|
||||||
P2PKH(P2PKHBytes), // 20
|
P2PKH(P2PKHBytes), // 20
|
||||||
@@ -20,17 +20,17 @@ pub enum AddressBytes {
|
|||||||
P2A(P2ABytes), // 2
|
P2A(P2ABytes), // 2
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddressBytes {
|
impl AddrBytes {
|
||||||
pub fn as_slice(&self) -> &[u8] {
|
pub fn as_slice(&self) -> &[u8] {
|
||||||
match self {
|
match self {
|
||||||
AddressBytes::P2PK65(bytes) => &bytes[..],
|
AddrBytes::P2PK65(bytes) => &bytes[..],
|
||||||
AddressBytes::P2PK33(bytes) => &bytes[..],
|
AddrBytes::P2PK33(bytes) => &bytes[..],
|
||||||
AddressBytes::P2PKH(bytes) => &bytes[..],
|
AddrBytes::P2PKH(bytes) => &bytes[..],
|
||||||
AddressBytes::P2SH(bytes) => &bytes[..],
|
AddrBytes::P2SH(bytes) => &bytes[..],
|
||||||
AddressBytes::P2WPKH(bytes) => &bytes[..],
|
AddrBytes::P2WPKH(bytes) => &bytes[..],
|
||||||
AddressBytes::P2WSH(bytes) => &bytes[..],
|
AddrBytes::P2WSH(bytes) => &bytes[..],
|
||||||
AddressBytes::P2TR(bytes) => &bytes[..],
|
AddrBytes::P2TR(bytes) => &bytes[..],
|
||||||
AddressBytes::P2A(bytes) => &bytes[..],
|
AddrBytes::P2A(bytes) => &bytes[..],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,42 +41,42 @@ impl AddressBytes {
|
|||||||
/// Reconstruct the script_pubkey from the address bytes
|
/// Reconstruct the script_pubkey from the address bytes
|
||||||
pub fn to_script_pubkey(&self) -> ScriptBuf {
|
pub fn to_script_pubkey(&self) -> ScriptBuf {
|
||||||
match self {
|
match self {
|
||||||
AddressBytes::P2PK65(b) => Builder::new()
|
AddrBytes::P2PK65(b) => Builder::new()
|
||||||
.push_slice(***b)
|
.push_slice(***b)
|
||||||
.push_opcode(opcodes::all::OP_CHECKSIG)
|
.push_opcode(opcodes::all::OP_CHECKSIG)
|
||||||
.into_script(),
|
.into_script(),
|
||||||
AddressBytes::P2PK33(b) => Builder::new()
|
AddrBytes::P2PK33(b) => Builder::new()
|
||||||
.push_slice(***b)
|
.push_slice(***b)
|
||||||
.push_opcode(opcodes::all::OP_CHECKSIG)
|
.push_opcode(opcodes::all::OP_CHECKSIG)
|
||||||
.into_script(),
|
.into_script(),
|
||||||
AddressBytes::P2PKH(b) => Builder::new()
|
AddrBytes::P2PKH(b) => Builder::new()
|
||||||
.push_opcode(opcodes::all::OP_DUP)
|
.push_opcode(opcodes::all::OP_DUP)
|
||||||
.push_opcode(opcodes::all::OP_HASH160)
|
.push_opcode(opcodes::all::OP_HASH160)
|
||||||
.push_slice(***b)
|
.push_slice(***b)
|
||||||
.push_opcode(opcodes::all::OP_EQUALVERIFY)
|
.push_opcode(opcodes::all::OP_EQUALVERIFY)
|
||||||
.push_opcode(opcodes::all::OP_CHECKSIG)
|
.push_opcode(opcodes::all::OP_CHECKSIG)
|
||||||
.into_script(),
|
.into_script(),
|
||||||
AddressBytes::P2SH(b) => Builder::new()
|
AddrBytes::P2SH(b) => Builder::new()
|
||||||
.push_opcode(opcodes::all::OP_HASH160)
|
.push_opcode(opcodes::all::OP_HASH160)
|
||||||
.push_slice(***b)
|
.push_slice(***b)
|
||||||
.push_opcode(opcodes::all::OP_EQUAL)
|
.push_opcode(opcodes::all::OP_EQUAL)
|
||||||
.into_script(),
|
.into_script(),
|
||||||
AddressBytes::P2WPKH(b) => Builder::new().push_int(0).push_slice(***b).into_script(),
|
AddrBytes::P2WPKH(b) => Builder::new().push_int(0).push_slice(***b).into_script(),
|
||||||
AddressBytes::P2WSH(b) => Builder::new().push_int(0).push_slice(***b).into_script(),
|
AddrBytes::P2WSH(b) => Builder::new().push_int(0).push_slice(***b).into_script(),
|
||||||
AddressBytes::P2TR(b) => Builder::new().push_int(1).push_slice(***b).into_script(),
|
AddrBytes::P2TR(b) => Builder::new().push_int(1).push_slice(***b).into_script(),
|
||||||
AddressBytes::P2A(b) => Builder::new().push_int(1).push_slice(***b).into_script(),
|
AddrBytes::P2A(b) => Builder::new().push_int(1).push_slice(***b).into_script(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&ScriptBuf> for AddressBytes {
|
impl TryFrom<&ScriptBuf> for AddrBytes {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
fn try_from(script: &ScriptBuf) -> Result<Self, Self::Error> {
|
fn try_from(script: &ScriptBuf) -> Result<Self, Self::Error> {
|
||||||
Self::try_from((script, OutputType::from(script)))
|
Self::try_from((script, OutputType::from(script)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<(&ScriptBuf, OutputType)> for AddressBytes {
|
impl TryFrom<(&ScriptBuf, OutputType)> for AddrBytes {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
fn try_from(tuple: (&ScriptBuf, OutputType)) -> Result<Self, Self::Error> {
|
fn try_from(tuple: (&ScriptBuf, OutputType)) -> Result<Self, Self::Error> {
|
||||||
let (script, output_type) = tuple;
|
let (script, output_type) = tuple;
|
||||||
@@ -135,90 +135,90 @@ impl TryFrom<(&ScriptBuf, OutputType)> for AddressBytes {
|
|||||||
Ok(Self::P2A(P2ABytes::from(bytes)))
|
Ok(Self::P2A(P2ABytes::from(bytes)))
|
||||||
}
|
}
|
||||||
OutputType::P2MS | OutputType::Unknown | OutputType::Empty | OutputType::OpReturn => {
|
OutputType::P2MS | OutputType::Unknown | OutputType::Empty | OutputType::OpReturn => {
|
||||||
Err(Error::WrongAddressType)
|
Err(Error::WrongAddrType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<P2PK65Bytes> for AddressBytes {
|
impl From<P2PK65Bytes> for AddrBytes {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: P2PK65Bytes) -> Self {
|
fn from(value: P2PK65Bytes) -> Self {
|
||||||
Self::P2PK65(value)
|
Self::P2PK65(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<P2PK33Bytes> for AddressBytes {
|
impl From<P2PK33Bytes> for AddrBytes {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: P2PK33Bytes) -> Self {
|
fn from(value: P2PK33Bytes) -> Self {
|
||||||
Self::P2PK33(value)
|
Self::P2PK33(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<P2PKHBytes> for AddressBytes {
|
impl From<P2PKHBytes> for AddrBytes {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: P2PKHBytes) -> Self {
|
fn from(value: P2PKHBytes) -> Self {
|
||||||
Self::P2PKH(value)
|
Self::P2PKH(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<P2SHBytes> for AddressBytes {
|
impl From<P2SHBytes> for AddrBytes {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: P2SHBytes) -> Self {
|
fn from(value: P2SHBytes) -> Self {
|
||||||
Self::P2SH(value)
|
Self::P2SH(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<P2WPKHBytes> for AddressBytes {
|
impl From<P2WPKHBytes> for AddrBytes {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: P2WPKHBytes) -> Self {
|
fn from(value: P2WPKHBytes) -> Self {
|
||||||
Self::P2WPKH(value)
|
Self::P2WPKH(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<P2WSHBytes> for AddressBytes {
|
impl From<P2WSHBytes> for AddrBytes {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: P2WSHBytes) -> Self {
|
fn from(value: P2WSHBytes) -> Self {
|
||||||
Self::P2WSH(value)
|
Self::P2WSH(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<P2TRBytes> for AddressBytes {
|
impl From<P2TRBytes> for AddrBytes {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: P2TRBytes) -> Self {
|
fn from(value: P2TRBytes) -> Self {
|
||||||
Self::P2TR(value)
|
Self::P2TR(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<P2ABytes> for AddressBytes {
|
impl From<P2ABytes> for AddrBytes {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: P2ABytes) -> Self {
|
fn from(value: P2ABytes) -> Self {
|
||||||
Self::P2A(value)
|
Self::P2A(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddressBytes {
|
impl AddrBytes {
|
||||||
/// Parse an address string to a ScriptBuf
|
/// Parse an address string to a ScriptBuf
|
||||||
pub fn address_to_script(address: &str) -> Result<ScriptBuf, Error> {
|
pub fn addr_to_script(addr: &str) -> Result<ScriptBuf, Error> {
|
||||||
if let Ok(address) = bitcoin::Address::from_str(address) {
|
if let Ok(addr) = bitcoin::Address::from_str(addr) {
|
||||||
if !address.is_valid_for_network(Network::Bitcoin) {
|
if !addr.is_valid_for_network(Network::Bitcoin) {
|
||||||
return Err(Error::InvalidNetwork);
|
return Err(Error::InvalidNetwork);
|
||||||
}
|
}
|
||||||
let address = address.assume_checked();
|
let addr = addr.assume_checked();
|
||||||
Ok(address.script_pubkey())
|
Ok(addr.script_pubkey())
|
||||||
} else if let Ok(pubkey) = PublicKey::from_str(address) {
|
} else if let Ok(pubkey) = PublicKey::from_str(addr) {
|
||||||
Ok(ScriptBuf::new_p2pk(&pubkey))
|
Ok(ScriptBuf::new_p2pk(&pubkey))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::InvalidAddress)
|
Err(Error::InvalidAddr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for AddressBytes {
|
impl FromStr for AddrBytes {
|
||||||
type Err = Error;
|
type Err = Error;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
let script = Self::address_to_script(s)?;
|
let script = Self::addr_to_script(s)?;
|
||||||
let output_type = OutputType::from(&script);
|
let output_type = OutputType::from(&script);
|
||||||
Self::try_from((&script, output_type))
|
Self::try_from((&script, output_type))
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
///
|
///
|
||||||
/// Based on mempool.space's format with type_index extension.
|
/// Based on mempool.space's format with type_index extension.
|
||||||
#[derive(Debug, Default, Serialize, Deserialize, JsonSchema)]
|
#[derive(Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct AddressChainStats {
|
pub struct AddrChainStats {
|
||||||
/// Total number of transaction outputs that funded this address
|
/// Total number of transaction outputs that funded this address
|
||||||
#[schemars(example = 5)]
|
#[schemars(example = 5)]
|
||||||
pub funded_txo_count: u32,
|
pub funded_txo_count: u32,
|
||||||
@@ -2,33 +2,33 @@ use byteview::ByteView;
|
|||||||
use derive_more::Deref;
|
use derive_more::Deref;
|
||||||
use vecdb::Bytes;
|
use vecdb::Bytes;
|
||||||
|
|
||||||
use super::AddressBytes;
|
use super::AddrBytes;
|
||||||
|
|
||||||
#[derive(Debug, Deref, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Bytes, Hash)]
|
#[derive(Debug, Deref, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Bytes, Hash)]
|
||||||
pub struct AddressHash(u64);
|
pub struct AddrHash(u64);
|
||||||
|
|
||||||
impl From<&AddressBytes> for AddressHash {
|
impl From<&AddrBytes> for AddrHash {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(address_bytes: &AddressBytes) -> Self {
|
fn from(addr_bytes: &AddrBytes) -> Self {
|
||||||
Self(address_bytes.hash())
|
Self(addr_bytes.hash())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ByteView> for AddressHash {
|
impl From<ByteView> for AddrHash {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: ByteView) -> Self {
|
fn from(value: ByteView) -> Self {
|
||||||
Self(u64::from_be_bytes((&*value).try_into().unwrap()))
|
Self(u64::from_be_bytes((&*value).try_into().unwrap()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<AddressHash> for ByteView {
|
impl From<AddrHash> for ByteView {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: AddressHash) -> Self {
|
fn from(value: AddrHash) -> Self {
|
||||||
Self::from(&value)
|
Self::from(&value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<&AddressHash> for ByteView {
|
impl From<&AddrHash> for ByteView {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: &AddressHash) -> Self {
|
fn from(value: &AddrHash) -> Self {
|
||||||
Self::new(&value.0.to_be_bytes())
|
Self::new(&value.0.to_be_bytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,23 +4,23 @@ use schemars::JsonSchema;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use vecdb::{Bytes, Formattable};
|
use vecdb::{Bytes, Formattable};
|
||||||
|
|
||||||
use crate::{EmptyAddressIndex, FundedAddressIndex, TypeIndex};
|
use crate::{EmptyAddrIndex, FundedAddrIndex, TypeIndex};
|
||||||
|
|
||||||
const MIN_EMPTY_INDEX: u32 = u32::MAX - 4_000_000_000;
|
const MIN_EMPTY_INDEX: u32 = u32::MAX - 4_000_000_000;
|
||||||
|
|
||||||
/// Unified index for any address type (funded or empty)
|
/// Unified index for any address type (funded or empty)
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Bytes, JsonSchema)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Bytes, JsonSchema)]
|
||||||
pub struct AnyAddressIndex(TypeIndex);
|
pub struct AnyAddrIndex(TypeIndex);
|
||||||
|
|
||||||
impl AnyAddressIndex {
|
impl AnyAddrIndex {
|
||||||
pub fn to_enum(&self) -> AnyAddressDataIndexEnum {
|
pub fn to_enum(&self) -> AnyAddrDataIndexEnum {
|
||||||
AnyAddressDataIndexEnum::from(*self)
|
AnyAddrDataIndexEnum::from(*self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FundedAddressIndex> for AnyAddressIndex {
|
impl From<FundedAddrIndex> for AnyAddrIndex {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: FundedAddressIndex) -> Self {
|
fn from(value: FundedAddrIndex) -> Self {
|
||||||
if u32::from(value) >= MIN_EMPTY_INDEX {
|
if u32::from(value) >= MIN_EMPTY_INDEX {
|
||||||
panic!("{value} is higher than MIN_EMPTY_INDEX ({MIN_EMPTY_INDEX})")
|
panic!("{value} is higher than MIN_EMPTY_INDEX ({MIN_EMPTY_INDEX})")
|
||||||
}
|
}
|
||||||
@@ -28,14 +28,14 @@ impl From<FundedAddressIndex> for AnyAddressIndex {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<EmptyAddressIndex> for AnyAddressIndex {
|
impl From<EmptyAddrIndex> for AnyAddrIndex {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: EmptyAddressIndex) -> Self {
|
fn from(value: EmptyAddrIndex) -> Self {
|
||||||
Self(*value + MIN_EMPTY_INDEX)
|
Self(*value + MIN_EMPTY_INDEX)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for AnyAddressIndex {
|
impl Serialize for AnyAddrIndex {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: serde::Serializer,
|
S: serde::Serializer,
|
||||||
@@ -44,23 +44,23 @@ impl Serialize for AnyAddressIndex {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for AnyAddressIndex {
|
impl<'de> Deserialize<'de> for AnyAddrIndex {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
D: serde::Deserializer<'de>,
|
D: serde::Deserializer<'de>,
|
||||||
{
|
{
|
||||||
let variant = AnyAddressDataIndexEnum::deserialize(deserializer)?;
|
let variant = AnyAddrDataIndexEnum::deserialize(deserializer)?;
|
||||||
Ok(Self::from(variant))
|
Ok(Self::from(variant))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for AnyAddressIndex {
|
impl fmt::Display for AnyAddrIndex {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
self.0.fmt(f)
|
self.0.fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Formattable for AnyAddressIndex {
|
impl Formattable for AnyAddrIndex {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn write_to(&self, buf: &mut Vec<u8>) {
|
fn write_to(&self, buf: &mut Vec<u8>) {
|
||||||
self.0.write_to(buf);
|
self.0.write_to(buf);
|
||||||
@@ -69,29 +69,29 @@ impl Formattable for AnyAddressIndex {
|
|||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
pub enum AnyAddressDataIndexEnum {
|
pub enum AnyAddrDataIndexEnum {
|
||||||
Funded(FundedAddressIndex),
|
Funded(FundedAddrIndex),
|
||||||
Empty(EmptyAddressIndex),
|
Empty(EmptyAddrIndex),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<AnyAddressIndex> for AnyAddressDataIndexEnum {
|
impl From<AnyAddrIndex> for AnyAddrDataIndexEnum {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: AnyAddressIndex) -> Self {
|
fn from(value: AnyAddrIndex) -> Self {
|
||||||
let uvalue = u32::from(value.0);
|
let uvalue = u32::from(value.0);
|
||||||
if uvalue >= MIN_EMPTY_INDEX {
|
if uvalue >= MIN_EMPTY_INDEX {
|
||||||
Self::Empty(EmptyAddressIndex::from(uvalue - MIN_EMPTY_INDEX))
|
Self::Empty(EmptyAddrIndex::from(uvalue - MIN_EMPTY_INDEX))
|
||||||
} else {
|
} else {
|
||||||
Self::Funded(FundedAddressIndex::from(value.0))
|
Self::Funded(FundedAddrIndex::from(value.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<AnyAddressDataIndexEnum> for AnyAddressIndex {
|
impl From<AnyAddrDataIndexEnum> for AnyAddrIndex {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: AnyAddressDataIndexEnum) -> Self {
|
fn from(value: AnyAddrDataIndexEnum) -> Self {
|
||||||
match value {
|
match value {
|
||||||
AnyAddressDataIndexEnum::Funded(idx) => Self::from(idx),
|
AnyAddrDataIndexEnum::Funded(idx) => Self::from(idx),
|
||||||
AnyAddressDataIndexEnum::Empty(idx) => Self::from(idx),
|
AnyAddrDataIndexEnum::Empty(idx) => Self::from(idx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,21 +4,21 @@ use byteview::ByteView;
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use vecdb::Bytes;
|
use vecdb::Bytes;
|
||||||
|
|
||||||
use crate::{AddressIndexTxIndex, Vout};
|
use crate::{AddrIndexTxIndex, Vout};
|
||||||
|
|
||||||
use super::{OutPoint, TxIndex, TypeIndex};
|
use super::{OutPoint, TxIndex, TypeIndex};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Serialize)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Serialize)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct AddressIndexOutPoint {
|
pub struct AddrIndexOutPoint {
|
||||||
address_index_tx_index: AddressIndexTxIndex, // u64
|
addr_index_tx_index: AddrIndexTxIndex, // u64
|
||||||
vout: Vout, // u16
|
vout: Vout, // u16
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddressIndexOutPoint {
|
impl AddrIndexOutPoint {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn tx_index(&self) -> TxIndex {
|
pub fn tx_index(&self) -> TxIndex {
|
||||||
self.address_index_tx_index.tx_index()
|
self.addr_index_tx_index.tx_index()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -27,47 +27,47 @@ impl AddressIndexOutPoint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for AddressIndexOutPoint {
|
impl Hash for AddrIndexOutPoint {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
let mut buf = [0u8; 10];
|
let mut buf = [0u8; 10];
|
||||||
buf[0..8].copy_from_slice(&self.address_index_tx_index.to_bytes());
|
buf[0..8].copy_from_slice(&self.addr_index_tx_index.to_bytes());
|
||||||
buf[8..].copy_from_slice(&self.vout.to_bytes());
|
buf[8..].copy_from_slice(&self.vout.to_bytes());
|
||||||
state.write(&buf);
|
state.write(&buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<(TypeIndex, OutPoint)> for AddressIndexOutPoint {
|
impl From<(TypeIndex, OutPoint)> for AddrIndexOutPoint {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from((address_index, outpoint): (TypeIndex, OutPoint)) -> Self {
|
fn from((addr_index, outpoint): (TypeIndex, OutPoint)) -> Self {
|
||||||
Self {
|
Self {
|
||||||
address_index_tx_index: AddressIndexTxIndex::from((address_index, outpoint.tx_index())),
|
addr_index_tx_index: AddrIndexTxIndex::from((addr_index, outpoint.tx_index())),
|
||||||
vout: outpoint.vout(),
|
vout: outpoint.vout(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ByteView> for AddressIndexOutPoint {
|
impl From<ByteView> for AddrIndexOutPoint {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: ByteView) -> Self {
|
fn from(value: ByteView) -> Self {
|
||||||
Self {
|
Self {
|
||||||
address_index_tx_index: AddressIndexTxIndex::from(ByteView::new(&value[..8])),
|
addr_index_tx_index: AddrIndexTxIndex::from(ByteView::new(&value[..8])),
|
||||||
vout: Vout::from(u16::from_be_bytes([value[8], value[9]])),
|
vout: Vout::from(u16::from_be_bytes([value[8], value[9]])),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<AddressIndexOutPoint> for ByteView {
|
impl From<AddrIndexOutPoint> for ByteView {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: AddressIndexOutPoint) -> Self {
|
fn from(value: AddrIndexOutPoint) -> Self {
|
||||||
ByteView::from(&value)
|
ByteView::from(&value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<&AddressIndexOutPoint> for ByteView {
|
impl From<&AddrIndexOutPoint> for ByteView {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: &AddressIndexOutPoint) -> Self {
|
fn from(value: &AddrIndexOutPoint) -> Self {
|
||||||
ByteView::from(
|
ByteView::from(
|
||||||
[
|
[
|
||||||
&ByteView::from(value.address_index_tx_index),
|
&ByteView::from(value.addr_index_tx_index),
|
||||||
value.vout.to_be_bytes().as_slice(),
|
value.vout.to_be_bytes().as_slice(),
|
||||||
]
|
]
|
||||||
.concat(),
|
.concat(),
|
||||||
55
crates/brk_types/src/addr_index_tx_index.rs
Normal file
55
crates/brk_types/src/addr_index_tx_index.rs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
use byteview::ByteView;
|
||||||
|
use serde::Serialize;
|
||||||
|
use vecdb::Bytes;
|
||||||
|
|
||||||
|
use super::{TxIndex, TypeIndex};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Serialize, Bytes, Hash)]
|
||||||
|
pub struct AddrIndexTxIndex(u64);
|
||||||
|
|
||||||
|
impl AddrIndexTxIndex {
|
||||||
|
pub fn addr_index(&self) -> u32 {
|
||||||
|
(self.0 >> 32) as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tx_index(&self) -> TxIndex {
|
||||||
|
TxIndex::from(self.0 as u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn min_for_addr(addr_index: TypeIndex) -> Self {
|
||||||
|
Self(u64::from(addr_index) << 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn max_for_addr(addr_index: TypeIndex) -> Self {
|
||||||
|
Self((u64::from(addr_index) << 32) | u64::MAX >> 32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(TypeIndex, TxIndex)> for AddrIndexTxIndex {
|
||||||
|
#[inline]
|
||||||
|
fn from((addr_index, tx_index): (TypeIndex, TxIndex)) -> Self {
|
||||||
|
Self((u64::from(addr_index) << 32) | u64::from(tx_index))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ByteView> for AddrIndexTxIndex {
|
||||||
|
#[inline]
|
||||||
|
fn from(value: ByteView) -> Self {
|
||||||
|
Self(u64::from_be_bytes((&*value).try_into().unwrap()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<AddrIndexTxIndex> for ByteView {
|
||||||
|
#[inline]
|
||||||
|
fn from(value: AddrIndexTxIndex) -> Self {
|
||||||
|
ByteView::from(&value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<&AddrIndexTxIndex> for ByteView {
|
||||||
|
#[inline]
|
||||||
|
fn from(value: &AddrIndexTxIndex) -> Self {
|
||||||
|
ByteView::from(value.0.to_be_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
/// Based on mempool.space's format.
|
/// Based on mempool.space's format.
|
||||||
///
|
///
|
||||||
#[derive(Debug, Default, Clone, Hash, Serialize, Deserialize, JsonSchema)]
|
#[derive(Debug, Default, Clone, Hash, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct AddressMempoolStats {
|
pub struct AddrMempoolStats {
|
||||||
/// Number of unconfirmed transaction outputs funding this address
|
/// Number of unconfirmed transaction outputs funding this address
|
||||||
#[schemars(example = 0)]
|
#[schemars(example = 0)]
|
||||||
pub funded_txo_count: u32,
|
pub funded_txo_count: u32,
|
||||||
@@ -30,7 +30,7 @@ pub struct AddressMempoolStats {
|
|||||||
pub tx_count: u32,
|
pub tx_count: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddressMempoolStats {
|
impl AddrMempoolStats {
|
||||||
pub fn receiving(&mut self, txout: &TxOut) {
|
pub fn receiving(&mut self, txout: &TxOut) {
|
||||||
self.funded_txo_count += 1;
|
self.funded_txo_count += 1;
|
||||||
self.funded_txo_sum += txout.value;
|
self.funded_txo_sum += txout.value;
|
||||||
10
crates/brk_types/src/addr_param.rs
Normal file
10
crates/brk_types/src/addr_param.rs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
use crate::Addr;
|
||||||
|
|
||||||
|
#[derive(Deserialize, JsonSchema)]
|
||||||
|
pub struct AddrParam {
|
||||||
|
#[serde(rename = "address")]
|
||||||
|
pub addr: Addr,
|
||||||
|
}
|
||||||
@@ -1,19 +1,20 @@
|
|||||||
use crate::{Address, AddressChainStats, AddressMempoolStats};
|
use crate::{Addr, AddrChainStats, AddrMempoolStats};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Address information compatible with mempool.space API format
|
/// Address information compatible with mempool.space API format
|
||||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct AddressStats {
|
pub struct AddrStats {
|
||||||
/// Bitcoin address string
|
/// Bitcoin address string
|
||||||
#[schemars(
|
#[schemars(
|
||||||
example = "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"
|
example = "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"
|
||||||
)]
|
)]
|
||||||
pub address: Address,
|
#[serde(rename = "address")]
|
||||||
|
pub addr: Addr,
|
||||||
|
|
||||||
/// Statistics for confirmed transactions on the blockchain
|
/// Statistics for confirmed transactions on the blockchain
|
||||||
pub chain_stats: AddressChainStats,
|
pub chain_stats: AddrChainStats,
|
||||||
|
|
||||||
/// Statistics for unconfirmed transactions in the mempool
|
/// Statistics for unconfirmed transactions in the mempool
|
||||||
pub mempool_stats: Option<AddressMempoolStats>,
|
pub mempool_stats: Option<AddrMempoolStats>,
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ use serde::Deserialize;
|
|||||||
use crate::Txid;
|
use crate::Txid;
|
||||||
|
|
||||||
#[derive(Debug, Default, Deserialize, JsonSchema)]
|
#[derive(Debug, Default, Deserialize, JsonSchema)]
|
||||||
pub struct AddressTxidsParam {
|
pub struct AddrTxidsParam {
|
||||||
/// Txid to paginate from (return transactions before this one)
|
/// Txid to paginate from (return transactions before this one)
|
||||||
pub after_txid: Option<Txid>,
|
pub after_txid: Option<Txid>,
|
||||||
}
|
}
|
||||||
@@ -2,17 +2,18 @@ use bitcoin::hex::DisplayHex;
|
|||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{AddressBytes, OutputType};
|
use crate::{AddrBytes, OutputType};
|
||||||
|
|
||||||
/// Address validation result
|
/// Address validation result
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct AddressValidation {
|
pub struct AddrValidation {
|
||||||
/// Whether the address is valid
|
/// Whether the address is valid
|
||||||
pub isvalid: bool,
|
pub isvalid: bool,
|
||||||
|
|
||||||
/// The validated address
|
/// The validated address
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub address: Option<String>,
|
#[serde(rename = "address")]
|
||||||
|
pub addr: Option<String>,
|
||||||
|
|
||||||
/// The scriptPubKey in hex
|
/// The scriptPubKey in hex
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
@@ -36,12 +37,12 @@ pub struct AddressValidation {
|
|||||||
pub witness_program: Option<String>,
|
pub witness_program: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddressValidation {
|
impl AddrValidation {
|
||||||
/// Returns an invalid validation result
|
/// Returns an invalid validation result
|
||||||
pub fn invalid() -> Self {
|
pub fn invalid() -> Self {
|
||||||
Self {
|
Self {
|
||||||
isvalid: false,
|
isvalid: false,
|
||||||
address: None,
|
addr: None,
|
||||||
script_pub_key: None,
|
script_pub_key: None,
|
||||||
isscript: None,
|
isscript: None,
|
||||||
iswitness: None,
|
iswitness: None,
|
||||||
@@ -51,8 +52,8 @@ impl AddressValidation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Validate a Bitcoin address string and return details
|
/// Validate a Bitcoin address string and return details
|
||||||
pub fn from_address(address: &str) -> Self {
|
pub fn from_addr(addr: &str) -> Self {
|
||||||
let Ok(script) = AddressBytes::address_to_script(address) else {
|
let Ok(script) = AddrBytes::addr_to_script(addr) else {
|
||||||
return Self::invalid();
|
return Self::invalid();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -79,7 +80,7 @@ impl AddressValidation {
|
|||||||
|
|
||||||
Self {
|
Self {
|
||||||
isvalid: true,
|
isvalid: true,
|
||||||
address: Some(address.to_string()),
|
addr: Some(addr.to_string()),
|
||||||
script_pub_key: Some(script_hex),
|
script_pub_key: Some(script_hex),
|
||||||
isscript: Some(is_script),
|
isscript: Some(is_script),
|
||||||
iswitness: Some(is_witness),
|
iswitness: Some(is_witness),
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
use std::hash::Hash;
|
|
||||||
|
|
||||||
use byteview::ByteView;
|
|
||||||
use serde::Serialize;
|
|
||||||
use vecdb::Bytes;
|
|
||||||
|
|
||||||
use super::{TxIndex, TypeIndex};
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Serialize, Bytes, Hash)]
|
|
||||||
pub struct AddressIndexTxIndex(u64);
|
|
||||||
|
|
||||||
impl AddressIndexTxIndex {
|
|
||||||
pub fn address_index(&self) -> u32 {
|
|
||||||
(self.0 >> 32) as u32
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tx_index(&self) -> TxIndex {
|
|
||||||
TxIndex::from(self.0 as u32)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn min_for_address(address_index: TypeIndex) -> Self {
|
|
||||||
Self(u64::from(address_index) << 32)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn max_for_address(address_index: TypeIndex) -> Self {
|
|
||||||
Self((u64::from(address_index) << 32) | u64::MAX >> 32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<(TypeIndex, TxIndex)> for AddressIndexTxIndex {
|
|
||||||
#[inline]
|
|
||||||
fn from((address_index, tx_index): (TypeIndex, TxIndex)) -> Self {
|
|
||||||
Self((u64::from(address_index) << 32) | u64::from(tx_index))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ByteView> for AddressIndexTxIndex {
|
|
||||||
#[inline]
|
|
||||||
fn from(value: ByteView) -> Self {
|
|
||||||
Self(u64::from_be_bytes((&*value).try_into().unwrap()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<AddressIndexTxIndex> for ByteView {
|
|
||||||
#[inline]
|
|
||||||
fn from(value: AddressIndexTxIndex) -> Self {
|
|
||||||
ByteView::from(&value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<&AddressIndexTxIndex> for ByteView {
|
|
||||||
#[inline]
|
|
||||||
fn from(value: &AddressIndexTxIndex) -> Self {
|
|
||||||
ByteView::from(value.0.to_be_bytes())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
use schemars::JsonSchema;
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
use crate::Address;
|
|
||||||
|
|
||||||
#[derive(Deserialize, JsonSchema)]
|
|
||||||
pub struct AddressParam {
|
|
||||||
pub address: Address,
|
|
||||||
}
|
|
||||||
@@ -2,12 +2,12 @@ use schemars::JsonSchema;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use vecdb::{Bytes, Formattable};
|
use vecdb::{Bytes, Formattable};
|
||||||
|
|
||||||
use crate::{FundedAddressData, Sats};
|
use crate::{FundedAddrData, Sats};
|
||||||
|
|
||||||
/// Data of an empty address
|
/// Data of an empty address
|
||||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
|
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct EmptyAddressData {
|
pub struct EmptyAddrData {
|
||||||
/// Total transaction count
|
/// Total transaction count
|
||||||
pub tx_count: u32,
|
pub tx_count: u32,
|
||||||
/// Total funded/spent transaction output count (equal since address is empty)
|
/// Total funded/spent transaction output count (equal since address is empty)
|
||||||
@@ -16,16 +16,16 @@ pub struct EmptyAddressData {
|
|||||||
pub transfered: Sats,
|
pub transfered: Sats,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FundedAddressData> for EmptyAddressData {
|
impl From<FundedAddrData> for EmptyAddrData {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: FundedAddressData) -> Self {
|
fn from(value: FundedAddrData) -> Self {
|
||||||
Self::from(&value)
|
Self::from(&value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&FundedAddressData> for EmptyAddressData {
|
impl From<&FundedAddrData> for EmptyAddrData {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: &FundedAddressData) -> Self {
|
fn from(value: &FundedAddrData) -> Self {
|
||||||
if value.sent != value.received {
|
if value.sent != value.received {
|
||||||
dbg!(&value);
|
dbg!(&value);
|
||||||
panic!("Trying to convert not empty wallet to empty !");
|
panic!("Trying to convert not empty wallet to empty !");
|
||||||
@@ -38,7 +38,7 @@ impl From<&FundedAddressData> for EmptyAddressData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for EmptyAddressData {
|
impl std::fmt::Display for EmptyAddrData {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@@ -48,7 +48,7 @@ impl std::fmt::Display for EmptyAddressData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Formattable for EmptyAddressData {
|
impl Formattable for EmptyAddrData {
|
||||||
fn write_to(&self, buf: &mut Vec<u8>) {
|
fn write_to(&self, buf: &mut Vec<u8>) {
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
@@ -73,7 +73,7 @@ impl Formattable for EmptyAddressData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bytes for EmptyAddressData {
|
impl Bytes for EmptyAddrData {
|
||||||
type Array = [u8; size_of::<Self>()];
|
type Array = [u8; size_of::<Self>()];
|
||||||
|
|
||||||
fn to_bytes(&self) -> Self::Array {
|
fn to_bytes(&self) -> Self::Array {
|
||||||
@@ -22,65 +22,65 @@ use crate::TypeIndex;
|
|||||||
Pco,
|
Pco,
|
||||||
JsonSchema,
|
JsonSchema,
|
||||||
)]
|
)]
|
||||||
pub struct EmptyAddressIndex(TypeIndex);
|
pub struct EmptyAddrIndex(TypeIndex);
|
||||||
|
|
||||||
impl From<TypeIndex> for EmptyAddressIndex {
|
impl From<TypeIndex> for EmptyAddrIndex {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: TypeIndex) -> Self {
|
fn from(value: TypeIndex) -> Self {
|
||||||
Self(value)
|
Self(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<usize> for EmptyAddressIndex {
|
impl From<usize> for EmptyAddrIndex {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: usize) -> Self {
|
fn from(value: usize) -> Self {
|
||||||
Self(TypeIndex::from(value))
|
Self(TypeIndex::from(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<u32> for EmptyAddressIndex {
|
impl From<u32> for EmptyAddrIndex {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: u32) -> Self {
|
fn from(value: u32) -> Self {
|
||||||
Self(TypeIndex::from(value))
|
Self(TypeIndex::from(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<EmptyAddressIndex> for usize {
|
impl From<EmptyAddrIndex> for usize {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: EmptyAddressIndex) -> Self {
|
fn from(value: EmptyAddrIndex) -> Self {
|
||||||
usize::from(value.0)
|
usize::from(value.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Add<usize> for EmptyAddressIndex {
|
impl Add<usize> for EmptyAddrIndex {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
fn add(self, rhs: usize) -> Self::Output {
|
fn add(self, rhs: usize) -> Self::Output {
|
||||||
Self(self.0 + rhs)
|
Self(self.0 + rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CheckedSub<EmptyAddressIndex> for EmptyAddressIndex {
|
impl CheckedSub<EmptyAddrIndex> for EmptyAddrIndex {
|
||||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||||
self.0.checked_sub(rhs.0).map(Self)
|
self.0.checked_sub(rhs.0).map(Self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrintableIndex for EmptyAddressIndex {
|
impl PrintableIndex for EmptyAddrIndex {
|
||||||
fn to_string() -> &'static str {
|
fn to_string() -> &'static str {
|
||||||
"empty_address_index"
|
"empty_addr_index"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_possible_strings() -> &'static [&'static str] {
|
fn to_possible_strings() -> &'static [&'static str] {
|
||||||
&["emptyaddr", "empty_address_index"]
|
&["emptyaddr", "empty_addr_index"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for EmptyAddressIndex {
|
impl std::fmt::Display for EmptyAddrIndex {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
self.0.fmt(f)
|
self.0.fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Formattable for EmptyAddressIndex {
|
impl Formattable for EmptyAddrIndex {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn write_to(&self, buf: &mut Vec<u8>) {
|
fn write_to(&self, buf: &mut Vec<u8>) {
|
||||||
self.0.write_to(buf);
|
self.0.write_to(buf);
|
||||||
@@ -3,7 +3,7 @@ use schemars::JsonSchema;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use vecdb::{Bytes, Formattable};
|
use vecdb::{Bytes, Formattable};
|
||||||
|
|
||||||
use crate::{Cents, CentsSats, CentsSquaredSats, EmptyAddressData, Sats, SupplyState};
|
use crate::{Cents, CentsSats, CentsSquaredSats, EmptyAddrData, Sats, SupplyState};
|
||||||
|
|
||||||
/// Snapshot of cost basis related state.
|
/// Snapshot of cost basis related state.
|
||||||
/// Uses CentsSats (u64) for single-UTXO values, CentsSquaredSats (u128) for investor cap.
|
/// Uses CentsSats (u64) for single-UTXO values, CentsSquaredSats (u128) for investor cap.
|
||||||
@@ -34,7 +34,7 @@ impl CostBasisSnapshot {
|
|||||||
/// Data for a funded (non-empty) address with current balance
|
/// Data for a funded (non-empty) address with current balance
|
||||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
|
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct FundedAddressData {
|
pub struct FundedAddrData {
|
||||||
/// Total transaction count
|
/// Total transaction count
|
||||||
pub tx_count: u32,
|
pub tx_count: u32,
|
||||||
/// Number of transaction outputs funded to this address
|
/// Number of transaction outputs funded to this address
|
||||||
@@ -53,7 +53,7 @@ pub struct FundedAddressData {
|
|||||||
pub investor_cap_raw: CentsSquaredSats,
|
pub investor_cap_raw: CentsSquaredSats,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FundedAddressData {
|
impl FundedAddrData {
|
||||||
pub fn balance(&self) -> Sats {
|
pub fn balance(&self) -> Sats {
|
||||||
(u64::from(self.received) - u64::from(self.sent)).into()
|
(u64::from(self.received) - u64::from(self.sent)).into()
|
||||||
}
|
}
|
||||||
@@ -87,8 +87,8 @@ impl FundedAddressData {
|
|||||||
.checked_sub(self.spent_txo_count)
|
.checked_sub(self.spent_txo_count)
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
panic!(
|
panic!(
|
||||||
"FundedAddressData corruption: spent_txo_count ({}) > funded_txo_count ({}). \
|
"FundedAddrData corruption: spent_txo_count ({}) > funded_txo_count ({}). \
|
||||||
Address data: {:?}",
|
Addr data: {:?}",
|
||||||
self.spent_txo_count, self.funded_txo_count, self
|
self.spent_txo_count, self.funded_txo_count, self
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -129,16 +129,16 @@ impl FundedAddressData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<EmptyAddressData> for FundedAddressData {
|
impl From<EmptyAddrData> for FundedAddrData {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: EmptyAddressData) -> Self {
|
fn from(value: EmptyAddrData) -> Self {
|
||||||
Self::from(&value)
|
Self::from(&value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&EmptyAddressData> for FundedAddressData {
|
impl From<&EmptyAddrData> for FundedAddrData {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: &EmptyAddressData) -> Self {
|
fn from(value: &EmptyAddrData) -> Self {
|
||||||
Self {
|
Self {
|
||||||
tx_count: value.tx_count,
|
tx_count: value.tx_count,
|
||||||
funded_txo_count: value.funded_txo_count,
|
funded_txo_count: value.funded_txo_count,
|
||||||
@@ -152,7 +152,7 @@ impl From<&EmptyAddressData> for FundedAddressData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for FundedAddressData {
|
impl std::fmt::Display for FundedAddrData {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@@ -168,7 +168,7 @@ impl std::fmt::Display for FundedAddressData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Formattable for FundedAddressData {
|
impl Formattable for FundedAddrData {
|
||||||
fn write_to(&self, buf: &mut Vec<u8>) {
|
fn write_to(&self, buf: &mut Vec<u8>) {
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
@@ -193,7 +193,7 @@ impl Formattable for FundedAddressData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bytes for FundedAddressData {
|
impl Bytes for FundedAddrData {
|
||||||
type Array = [u8; size_of::<Self>()];
|
type Array = [u8; size_of::<Self>()];
|
||||||
|
|
||||||
fn to_bytes(&self) -> Self::Array {
|
fn to_bytes(&self) -> Self::Array {
|
||||||
@@ -22,61 +22,61 @@ use crate::TypeIndex;
|
|||||||
Pco,
|
Pco,
|
||||||
JsonSchema,
|
JsonSchema,
|
||||||
)]
|
)]
|
||||||
pub struct FundedAddressIndex(TypeIndex);
|
pub struct FundedAddrIndex(TypeIndex);
|
||||||
|
|
||||||
impl From<TypeIndex> for FundedAddressIndex {
|
impl From<TypeIndex> for FundedAddrIndex {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: TypeIndex) -> Self {
|
fn from(value: TypeIndex) -> Self {
|
||||||
Self(value)
|
Self(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<usize> for FundedAddressIndex {
|
impl From<usize> for FundedAddrIndex {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: usize) -> Self {
|
fn from(value: usize) -> Self {
|
||||||
Self(TypeIndex::from(value))
|
Self(TypeIndex::from(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<FundedAddressIndex> for usize {
|
impl From<FundedAddrIndex> for usize {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: FundedAddressIndex) -> Self {
|
fn from(value: FundedAddrIndex) -> Self {
|
||||||
usize::from(value.0)
|
usize::from(value.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<FundedAddressIndex> for u32 {
|
impl From<FundedAddrIndex> for u32 {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: FundedAddressIndex) -> Self {
|
fn from(value: FundedAddrIndex) -> Self {
|
||||||
u32::from(value.0)
|
u32::from(value.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Add<usize> for FundedAddressIndex {
|
impl Add<usize> for FundedAddrIndex {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
fn add(self, rhs: usize) -> Self::Output {
|
fn add(self, rhs: usize) -> Self::Output {
|
||||||
Self(self.0 + rhs)
|
Self(self.0 + rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl CheckedSub<FundedAddressIndex> for FundedAddressIndex {
|
impl CheckedSub<FundedAddrIndex> for FundedAddrIndex {
|
||||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||||
self.0.checked_sub(rhs.0).map(Self)
|
self.0.checked_sub(rhs.0).map(Self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl PrintableIndex for FundedAddressIndex {
|
impl PrintableIndex for FundedAddrIndex {
|
||||||
fn to_string() -> &'static str {
|
fn to_string() -> &'static str {
|
||||||
"funded_address_index"
|
"funded_addr_index"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_possible_strings() -> &'static [&'static str] {
|
fn to_possible_strings() -> &'static [&'static str] {
|
||||||
&["fundedaddr", "funded_address_index"]
|
&["fundedaddr", "funded_addr_index"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for FundedAddressIndex {
|
impl std::fmt::Display for FundedAddrIndex {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
self.0.fmt(f)
|
self.0.fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Formattable for FundedAddressIndex {
|
impl Formattable for FundedAddrIndex {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn write_to(&self, buf: &mut Vec<u8>) {
|
fn write_to(&self, buf: &mut Vec<u8>) {
|
||||||
self.0.write_to(buf);
|
self.0.write_to(buf);
|
||||||
@@ -6,10 +6,10 @@ use serde::{Deserialize, Serialize};
|
|||||||
use vecdb::PrintableIndex;
|
use vecdb::PrintableIndex;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
Date, Day1, Day3, EmptyAddressIndex, EmptyOutputIndex, Epoch, FundedAddressIndex, Halving,
|
Date, Day1, Day3, EmptyAddrIndex, EmptyOutputIndex, Epoch, FundedAddrIndex, Halving,
|
||||||
Height, Hour1, Hour4, Hour12, Minute10, Minute30, Month1, Month3, Month6, OpReturnIndex,
|
Height, Hour1, Hour4, Hour12, Minute10, Minute30, Month1, Month3, Month6, OpReturnIndex,
|
||||||
P2AAddressIndex, P2MSOutputIndex, P2PK33AddressIndex, P2PK65AddressIndex, P2PKHAddressIndex,
|
P2AAddrIndex, P2MSOutputIndex, P2PK33AddrIndex, P2PK65AddrIndex, P2PKHAddrIndex,
|
||||||
P2SHAddressIndex, P2TRAddressIndex, P2WPKHAddressIndex, P2WSHAddressIndex, Timestamp,
|
P2SHAddrIndex, P2TRAddrIndex, P2WPKHAddrIndex, P2WSHAddrIndex, Timestamp,
|
||||||
TxInIndex, TxIndex, TxOutIndex, UnknownOutputIndex, Week1, Year1, Year10,
|
TxInIndex, TxIndex, TxOutIndex, UnknownOutputIndex, Week1, Year1, Year10,
|
||||||
hour1::HOUR1_INTERVAL, hour4::HOUR4_INTERVAL, hour12::HOUR12_INTERVAL,
|
hour1::HOUR1_INTERVAL, hour4::HOUR4_INTERVAL, hour12::HOUR12_INTERVAL,
|
||||||
minute10::MINUTE10_INTERVAL, minute30::MINUTE30_INTERVAL, timestamp::INDEX_EPOCH,
|
minute10::MINUTE10_INTERVAL, minute30::MINUTE30_INTERVAL, timestamp::INDEX_EPOCH,
|
||||||
@@ -47,30 +47,30 @@ pub enum Index {
|
|||||||
EmptyOutputIndex,
|
EmptyOutputIndex,
|
||||||
#[serde(rename = "op_return_index")]
|
#[serde(rename = "op_return_index")]
|
||||||
OpReturnIndex,
|
OpReturnIndex,
|
||||||
#[serde(rename = "p2a_address_index")]
|
#[serde(rename = "p2a_addr_index")]
|
||||||
P2AAddressIndex,
|
P2AAddrIndex,
|
||||||
#[serde(rename = "p2ms_output_index")]
|
#[serde(rename = "p2ms_output_index")]
|
||||||
P2MSOutputIndex,
|
P2MSOutputIndex,
|
||||||
#[serde(rename = "p2pk33_address_index")]
|
#[serde(rename = "p2pk33_addr_index")]
|
||||||
P2PK33AddressIndex,
|
P2PK33AddrIndex,
|
||||||
#[serde(rename = "p2pk65_address_index")]
|
#[serde(rename = "p2pk65_addr_index")]
|
||||||
P2PK65AddressIndex,
|
P2PK65AddrIndex,
|
||||||
#[serde(rename = "p2pkh_address_index")]
|
#[serde(rename = "p2pkh_addr_index")]
|
||||||
P2PKHAddressIndex,
|
P2PKHAddrIndex,
|
||||||
#[serde(rename = "p2sh_address_index")]
|
#[serde(rename = "p2sh_addr_index")]
|
||||||
P2SHAddressIndex,
|
P2SHAddrIndex,
|
||||||
#[serde(rename = "p2tr_address_index")]
|
#[serde(rename = "p2tr_addr_index")]
|
||||||
P2TRAddressIndex,
|
P2TRAddrIndex,
|
||||||
#[serde(rename = "p2wpkh_address_index")]
|
#[serde(rename = "p2wpkh_addr_index")]
|
||||||
P2WPKHAddressIndex,
|
P2WPKHAddrIndex,
|
||||||
#[serde(rename = "p2wsh_address_index")]
|
#[serde(rename = "p2wsh_addr_index")]
|
||||||
P2WSHAddressIndex,
|
P2WSHAddrIndex,
|
||||||
#[serde(rename = "unknown_output_index")]
|
#[serde(rename = "unknown_output_index")]
|
||||||
UnknownOutputIndex,
|
UnknownOutputIndex,
|
||||||
#[serde(rename = "funded_address_index")]
|
#[serde(rename = "funded_addr_index")]
|
||||||
FundedAddressIndex,
|
FundedAddrIndex,
|
||||||
#[serde(rename = "empty_address_index")]
|
#[serde(rename = "empty_addr_index")]
|
||||||
EmptyAddressIndex,
|
EmptyAddrIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index {
|
impl Index {
|
||||||
@@ -97,18 +97,18 @@ impl Index {
|
|||||||
Self::TxOutIndex,
|
Self::TxOutIndex,
|
||||||
Self::EmptyOutputIndex,
|
Self::EmptyOutputIndex,
|
||||||
Self::OpReturnIndex,
|
Self::OpReturnIndex,
|
||||||
Self::P2AAddressIndex,
|
Self::P2AAddrIndex,
|
||||||
Self::P2MSOutputIndex,
|
Self::P2MSOutputIndex,
|
||||||
Self::P2PK33AddressIndex,
|
Self::P2PK33AddrIndex,
|
||||||
Self::P2PK65AddressIndex,
|
Self::P2PK65AddrIndex,
|
||||||
Self::P2PKHAddressIndex,
|
Self::P2PKHAddrIndex,
|
||||||
Self::P2SHAddressIndex,
|
Self::P2SHAddrIndex,
|
||||||
Self::P2TRAddressIndex,
|
Self::P2TRAddrIndex,
|
||||||
Self::P2WPKHAddressIndex,
|
Self::P2WPKHAddrIndex,
|
||||||
Self::P2WSHAddressIndex,
|
Self::P2WSHAddrIndex,
|
||||||
Self::UnknownOutputIndex,
|
Self::UnknownOutputIndex,
|
||||||
Self::FundedAddressIndex,
|
Self::FundedAddrIndex,
|
||||||
Self::EmptyAddressIndex,
|
Self::EmptyAddrIndex,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,18 +135,18 @@ impl Index {
|
|||||||
Self::TxOutIndex => TxOutIndex::to_possible_strings(),
|
Self::TxOutIndex => TxOutIndex::to_possible_strings(),
|
||||||
Self::EmptyOutputIndex => EmptyOutputIndex::to_possible_strings(),
|
Self::EmptyOutputIndex => EmptyOutputIndex::to_possible_strings(),
|
||||||
Self::OpReturnIndex => OpReturnIndex::to_possible_strings(),
|
Self::OpReturnIndex => OpReturnIndex::to_possible_strings(),
|
||||||
Self::P2AAddressIndex => P2AAddressIndex::to_possible_strings(),
|
Self::P2AAddrIndex => P2AAddrIndex::to_possible_strings(),
|
||||||
Self::P2MSOutputIndex => P2MSOutputIndex::to_possible_strings(),
|
Self::P2MSOutputIndex => P2MSOutputIndex::to_possible_strings(),
|
||||||
Self::P2PK33AddressIndex => P2PK33AddressIndex::to_possible_strings(),
|
Self::P2PK33AddrIndex => P2PK33AddrIndex::to_possible_strings(),
|
||||||
Self::P2PK65AddressIndex => P2PK65AddressIndex::to_possible_strings(),
|
Self::P2PK65AddrIndex => P2PK65AddrIndex::to_possible_strings(),
|
||||||
Self::P2PKHAddressIndex => P2PKHAddressIndex::to_possible_strings(),
|
Self::P2PKHAddrIndex => P2PKHAddrIndex::to_possible_strings(),
|
||||||
Self::P2SHAddressIndex => P2SHAddressIndex::to_possible_strings(),
|
Self::P2SHAddrIndex => P2SHAddrIndex::to_possible_strings(),
|
||||||
Self::P2TRAddressIndex => P2TRAddressIndex::to_possible_strings(),
|
Self::P2TRAddrIndex => P2TRAddrIndex::to_possible_strings(),
|
||||||
Self::P2WPKHAddressIndex => P2WPKHAddressIndex::to_possible_strings(),
|
Self::P2WPKHAddrIndex => P2WPKHAddrIndex::to_possible_strings(),
|
||||||
Self::P2WSHAddressIndex => P2WSHAddressIndex::to_possible_strings(),
|
Self::P2WSHAddrIndex => P2WSHAddrIndex::to_possible_strings(),
|
||||||
Self::UnknownOutputIndex => UnknownOutputIndex::to_possible_strings(),
|
Self::UnknownOutputIndex => UnknownOutputIndex::to_possible_strings(),
|
||||||
Self::FundedAddressIndex => FundedAddressIndex::to_possible_strings(),
|
Self::FundedAddrIndex => FundedAddrIndex::to_possible_strings(),
|
||||||
Self::EmptyAddressIndex => EmptyAddressIndex::to_possible_strings(),
|
Self::EmptyAddrIndex => EmptyAddrIndex::to_possible_strings(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,18 +180,18 @@ impl Index {
|
|||||||
Self::TxOutIndex => <TxOutIndex as PrintableIndex>::to_string(),
|
Self::TxOutIndex => <TxOutIndex as PrintableIndex>::to_string(),
|
||||||
Self::EmptyOutputIndex => <EmptyOutputIndex as PrintableIndex>::to_string(),
|
Self::EmptyOutputIndex => <EmptyOutputIndex as PrintableIndex>::to_string(),
|
||||||
Self::OpReturnIndex => <OpReturnIndex as PrintableIndex>::to_string(),
|
Self::OpReturnIndex => <OpReturnIndex as PrintableIndex>::to_string(),
|
||||||
Self::P2AAddressIndex => <P2AAddressIndex as PrintableIndex>::to_string(),
|
Self::P2AAddrIndex => <P2AAddrIndex as PrintableIndex>::to_string(),
|
||||||
Self::P2MSOutputIndex => <P2MSOutputIndex as PrintableIndex>::to_string(),
|
Self::P2MSOutputIndex => <P2MSOutputIndex as PrintableIndex>::to_string(),
|
||||||
Self::P2PK33AddressIndex => <P2PK33AddressIndex as PrintableIndex>::to_string(),
|
Self::P2PK33AddrIndex => <P2PK33AddrIndex as PrintableIndex>::to_string(),
|
||||||
Self::P2PK65AddressIndex => <P2PK65AddressIndex as PrintableIndex>::to_string(),
|
Self::P2PK65AddrIndex => <P2PK65AddrIndex as PrintableIndex>::to_string(),
|
||||||
Self::P2PKHAddressIndex => <P2PKHAddressIndex as PrintableIndex>::to_string(),
|
Self::P2PKHAddrIndex => <P2PKHAddrIndex as PrintableIndex>::to_string(),
|
||||||
Self::P2SHAddressIndex => <P2SHAddressIndex as PrintableIndex>::to_string(),
|
Self::P2SHAddrIndex => <P2SHAddrIndex as PrintableIndex>::to_string(),
|
||||||
Self::P2TRAddressIndex => <P2TRAddressIndex as PrintableIndex>::to_string(),
|
Self::P2TRAddrIndex => <P2TRAddrIndex as PrintableIndex>::to_string(),
|
||||||
Self::P2WPKHAddressIndex => <P2WPKHAddressIndex as PrintableIndex>::to_string(),
|
Self::P2WPKHAddrIndex => <P2WPKHAddrIndex as PrintableIndex>::to_string(),
|
||||||
Self::P2WSHAddressIndex => <P2WSHAddressIndex as PrintableIndex>::to_string(),
|
Self::P2WSHAddrIndex => <P2WSHAddrIndex as PrintableIndex>::to_string(),
|
||||||
Self::UnknownOutputIndex => <UnknownOutputIndex as PrintableIndex>::to_string(),
|
Self::UnknownOutputIndex => <UnknownOutputIndex as PrintableIndex>::to_string(),
|
||||||
Self::FundedAddressIndex => <FundedAddressIndex as PrintableIndex>::to_string(),
|
Self::FundedAddrIndex => <FundedAddrIndex as PrintableIndex>::to_string(),
|
||||||
Self::EmptyAddressIndex => <EmptyAddressIndex as PrintableIndex>::to_string(),
|
Self::EmptyAddrIndex => <EmptyAddrIndex as PrintableIndex>::to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user