global: address -> addr rename

This commit is contained in:
nym21
2026-03-17 11:01:21 +01:00
parent 5609e6c010
commit f62943199c
141 changed files with 3788 additions and 3754 deletions

152
Cargo.lock generated
View File

@@ -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",

View File

@@ -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"

View File

@@ -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

View File

@@ -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,

View File

@@ -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)?,

View File

@@ -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();

View File

@@ -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",
} }
} }

View File

@@ -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(_))

View File

@@ -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::*;

View File

@@ -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());

View File

@@ -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);
} }
} }

View File

@@ -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)?;

View File

@@ -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())

View File

@@ -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,
} }
} }
} }

View File

@@ -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());

View 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};

View File

@@ -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)?)

View File

@@ -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

View File

@@ -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()
} }
} }

View File

@@ -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) => {

View File

@@ -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
} }
} }

View File

@@ -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};

View 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())
}
}))
}

View File

@@ -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())
}
}))
}

View File

@@ -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.

View File

@@ -1,5 +1,5 @@
mod address; mod addr;
mod lookup; mod lookup;
pub use address::*; pub use addr::*;
pub use lookup::*; pub use lookup::*;

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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::*;

View File

@@ -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,

View File

@@ -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 {

View File

@@ -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)
{ {

View File

@@ -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()),
} }
} }
} }

View File

@@ -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,
}) })
} }

View File

@@ -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,
}) })
} }

View File

@@ -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;

View File

@@ -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,

View File

@@ -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;

View File

@@ -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());
} }

View File

@@ -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()
} }
} }

View File

@@ -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);

View File

@@ -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());

View File

@@ -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};

View File

@@ -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
) )
}); });

View File

@@ -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,

View File

@@ -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::*;

View File

@@ -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()))
} }
} }

View File

@@ -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 {

View File

@@ -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,

View File

@@ -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,

View File

@@ -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);

View File

@@ -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,
)?) )?)
})?; })?;

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,
)?; )?;

View File

@@ -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,

View File

@@ -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(())

View File

@@ -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);
} }
} }

View File

@@ -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>,
} }

View File

@@ -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(),
} }
} }
} }

View File

@@ -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)));
} }
} }

View File

@@ -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);

View File

@@ -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())
} }

View File

@@ -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----------------------------------------");
} }

View File

@@ -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;
}; };

View File

@@ -1,4 +1,4 @@
mod addresses; mod addrs;
mod block_builder; mod block_builder;
mod entry; mod entry;
mod entry_pool; mod entry_pool;

View File

@@ -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);

View File

@@ -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()
))); )));

View File

@@ -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

View File

@@ -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))

View File

@@ -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;

View File

@@ -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)));

View File

@@ -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()
), ),
) )

View File

@@ -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")))

View File

@@ -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",

View File

@@ -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")
} }

View File

@@ -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

View File

@@ -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)
}
}

View File

@@ -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))
} }

View File

@@ -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,

View File

@@ -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())
} }
} }

View File

@@ -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),
} }
} }
} }

View File

@@ -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(),

View 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())
}
}

View File

@@ -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;

View 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,
}

View File

@@ -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>,
} }

View File

@@ -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>,
} }

View File

@@ -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),

View File

@@ -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())
}
}

View File

@@ -1,9 +0,0 @@
use schemars::JsonSchema;
use serde::Deserialize;
use crate::Address;
#[derive(Deserialize, JsonSchema)]
pub struct AddressParam {
pub address: Address,
}

View File

@@ -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 {

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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);

View File

@@ -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