mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-16 05:28:12 -07:00
global: snapshot
This commit is contained in:
Generated
+31
-15
@@ -1057,6 +1057,7 @@ name = "brk_server"
|
|||||||
version = "0.0.107"
|
version = "0.0.107"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
|
"bitcoin",
|
||||||
"bitcoincore-rpc",
|
"bitcoincore-rpc",
|
||||||
"brk_computer",
|
"brk_computer",
|
||||||
"brk_error",
|
"brk_error",
|
||||||
@@ -1066,6 +1067,7 @@ dependencies = [
|
|||||||
"brk_logger",
|
"brk_logger",
|
||||||
"brk_mcp",
|
"brk_mcp",
|
||||||
"brk_parser",
|
"brk_parser",
|
||||||
|
"brk_structs",
|
||||||
"jiff",
|
"jiff",
|
||||||
"log",
|
"log",
|
||||||
"quick_cache",
|
"quick_cache",
|
||||||
@@ -1085,6 +1087,7 @@ dependencies = [
|
|||||||
"byteview",
|
"byteview",
|
||||||
"fjall",
|
"fjall",
|
||||||
"log",
|
"log",
|
||||||
|
"parking_lot 0.12.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2590,9 +2593,9 @@ checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
version = "0.1.9"
|
version = "0.1.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3"
|
checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.4",
|
"bitflags 2.9.4",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -4122,12 +4125,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "seize"
|
name = "seize"
|
||||||
version = "0.5.0"
|
version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e4b8d813387d566f627f3ea1b914c068aac94c40ae27ec43f5f33bde65abefe7"
|
checksum = "5b55fb86dfd3a2f5f76ea78310a88f96c4ea21a3031f8d212443d56123fd0521"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.61.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4161,27 +4164,38 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.219"
|
version = "1.0.223"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
|
checksum = "a505d71960adde88e293da5cb5eda57093379f64e61cf77bf0e6a63af07a7bac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"serde_core",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_bytes"
|
name = "serde_bytes"
|
||||||
version = "0.11.17"
|
version = "0.11.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96"
|
checksum = "fe07b5d88710e3b807c16a06ccbc9dfecd5fff6a4d2745c59e3e26774f10de6a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_core"
|
||||||
|
version = "1.0.223"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20f57cbd357666aa7b3ac84a90b4ea328f1d4ddb6772b430caa5d9e1309bb9e9"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.219"
|
version = "1.0.223"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
checksum = "3d428d07faf17e306e699ec1e91996e5a165ba5d6bce5b5155173e91a8a01a56"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -4201,25 +4215,27 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.143"
|
version = "1.0.145"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a"
|
checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.11.1",
|
"indexmap 2.11.1",
|
||||||
"itoa",
|
"itoa",
|
||||||
"memchr",
|
"memchr",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_path_to_error"
|
name = "serde_path_to_error"
|
||||||
version = "0.1.17"
|
version = "0.1.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a"
|
checksum = "a30a8abed938137c7183c173848e3c9b3517f5e038226849a4ecc9b21a4b4e2a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
+4
-4
@@ -68,10 +68,10 @@ minreq = { version = "2.14.1", features = ["https", "serde_json"] }
|
|||||||
parking_lot = "0.12.4"
|
parking_lot = "0.12.4"
|
||||||
quick_cache = "0.6.16"
|
quick_cache = "0.6.16"
|
||||||
rayon = "1.11.0"
|
rayon = "1.11.0"
|
||||||
serde = "1.0.219"
|
serde = "1.0.223"
|
||||||
serde_bytes = "0.11.17"
|
serde_bytes = "0.11.18"
|
||||||
serde_derive = "1.0.219"
|
serde_derive = "1.0.223"
|
||||||
serde_json = { version = "1.0.143", features = ["float_roundtrip"] }
|
serde_json = { version = "1.0.145", features = ["float_roundtrip"] }
|
||||||
tokio = { version = "1.47.1", features = ["rt-multi-thread"] }
|
tokio = { version = "1.47.1", features = ["rt-multi-thread"] }
|
||||||
# vecdb = { path = "../seqdb/crates/vecdb", features = ["derive"]}
|
# vecdb = { path = "../seqdb/crates/vecdb", features = ["derive"]}
|
||||||
vecdb = { version = "0.2.14", features = ["derive"]}
|
vecdb = { version = "0.2.14", features = ["derive"]}
|
||||||
|
|||||||
@@ -1495,35 +1495,35 @@ impl Vecs {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mmap = addresstypeindex_to_anyaddressindex_reader_opt
|
let reader = addresstypeindex_to_anyaddressindex_reader_opt
|
||||||
.get_unwrap(address_type)
|
.get_unwrap(address_type)
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let anyaddressindex = match address_type {
|
let anyaddressindex = match address_type {
|
||||||
OutputType::P2PK33 => {
|
OutputType::P2PK33 => {
|
||||||
p2pk33addressindex_to_anyaddressindex.get_or_read(typeindex.into(), mmap)
|
p2pk33addressindex_to_anyaddressindex.get_or_read(typeindex.into(), reader)
|
||||||
}
|
}
|
||||||
OutputType::P2PK65 => {
|
OutputType::P2PK65 => {
|
||||||
p2pk65addressindex_to_anyaddressindex.get_or_read(typeindex.into(), mmap)
|
p2pk65addressindex_to_anyaddressindex.get_or_read(typeindex.into(), reader)
|
||||||
}
|
}
|
||||||
OutputType::P2PKH => {
|
OutputType::P2PKH => {
|
||||||
p2pkhaddressindex_to_anyaddressindex.get_or_read(typeindex.into(), mmap)
|
p2pkhaddressindex_to_anyaddressindex.get_or_read(typeindex.into(), reader)
|
||||||
}
|
}
|
||||||
OutputType::P2SH => {
|
OutputType::P2SH => {
|
||||||
p2shaddressindex_to_anyaddressindex.get_or_read(typeindex.into(), mmap)
|
p2shaddressindex_to_anyaddressindex.get_or_read(typeindex.into(), reader)
|
||||||
}
|
}
|
||||||
OutputType::P2TR => {
|
OutputType::P2TR => {
|
||||||
p2traddressindex_to_anyaddressindex.get_or_read(typeindex.into(), mmap)
|
p2traddressindex_to_anyaddressindex.get_or_read(typeindex.into(), reader)
|
||||||
}
|
}
|
||||||
OutputType::P2WPKH => {
|
OutputType::P2WPKH => {
|
||||||
p2wpkhaddressindex_to_anyaddressindex.get_or_read(typeindex.into(), mmap)
|
p2wpkhaddressindex_to_anyaddressindex.get_or_read(typeindex.into(), reader)
|
||||||
}
|
}
|
||||||
OutputType::P2WSH => {
|
OutputType::P2WSH => {
|
||||||
p2wshaddressindex_to_anyaddressindex.get_or_read(typeindex.into(), mmap)
|
p2wshaddressindex_to_anyaddressindex.get_or_read(typeindex.into(), reader)
|
||||||
}
|
}
|
||||||
OutputType::P2A => {
|
OutputType::P2A => {
|
||||||
p2aaddressindex_to_anyaddressindex.get_or_read(typeindex.into(), mmap)
|
p2aaddressindex_to_anyaddressindex.get_or_read(typeindex.into(), reader)
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -261,4 +261,12 @@ impl<'a> Interface<'a> {
|
|||||||
pub fn get_vecid_to_indexes(&self, id: String) -> Option<&Vec<&'static str>> {
|
pub fn get_vecid_to_indexes(&self, id: String) -> Option<&Vec<&'static str>> {
|
||||||
self.vecs.id_to_indexes(id)
|
self.vecs.id_to_indexes(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn indexer(&self) -> &Indexer {
|
||||||
|
self.indexer
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn computer(&self) -> &Computer {
|
||||||
|
self.computer
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ build = "build.rs"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
axum = { workspace = true }
|
axum = { workspace = true }
|
||||||
|
bitcoin = { workspace = true }
|
||||||
bitcoincore-rpc = { workspace = true }
|
bitcoincore-rpc = { workspace = true }
|
||||||
brk_computer = { workspace = true }
|
brk_computer = { workspace = true }
|
||||||
brk_error = { workspace = true }
|
brk_error = { workspace = true }
|
||||||
@@ -20,6 +21,7 @@ brk_interface = { workspace = true }
|
|||||||
brk_logger = { workspace = true }
|
brk_logger = { workspace = true }
|
||||||
brk_mcp = { workspace = true }
|
brk_mcp = { workspace = true }
|
||||||
brk_parser = { workspace = true }
|
brk_parser = { workspace = true }
|
||||||
|
brk_structs = { workspace = true }
|
||||||
vecdb = { workspace = true }
|
vecdb = { workspace = true }
|
||||||
jiff = { workspace = true }
|
jiff = { workspace = true }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
use axum::{
|
use axum::{
|
||||||
Json, Router,
|
Json, Router,
|
||||||
extract::{Path, Query, State},
|
extract::{Path, Query, State},
|
||||||
@@ -5,12 +7,20 @@ use axum::{
|
|||||||
response::{IntoResponse, Redirect, Response},
|
response::{IntoResponse, Redirect, Response},
|
||||||
routing::get,
|
routing::get,
|
||||||
};
|
};
|
||||||
|
use bitcoin::{Address, Network, absolute::LockTime};
|
||||||
|
use bitcoincore_rpc::bitcoin;
|
||||||
use brk_interface::{IdParam, Index, PaginatedIndexParam, PaginationParam, Params, ParamsOpt};
|
use brk_interface::{IdParam, Index, PaginatedIndexParam, PaginationParam, Params, ParamsOpt};
|
||||||
|
use brk_structs::{
|
||||||
|
AddressBytesHash, AnyAddressDataIndexEnum, Bitcoin, OutputType, Txid, TxidPrefix,
|
||||||
|
};
|
||||||
|
use serde_json::Number;
|
||||||
|
use tracing::info;
|
||||||
|
use vecdb::{AnyIterableVec, VecIterator};
|
||||||
|
|
||||||
use super::AppState;
|
use super::AppState;
|
||||||
|
|
||||||
mod explorer;
|
mod explorer;
|
||||||
mod interface;
|
mod vecs;
|
||||||
|
|
||||||
pub trait ApiRoutes {
|
pub trait ApiRoutes {
|
||||||
fn add_api_routes(self) -> Self;
|
fn add_api_routes(self) -> Self;
|
||||||
@@ -21,6 +31,160 @@ const TO_SEPARATOR: &str = "_to_";
|
|||||||
impl ApiRoutes for Router<AppState> {
|
impl ApiRoutes for Router<AppState> {
|
||||||
fn add_api_routes(self) -> Self {
|
fn add_api_routes(self) -> Self {
|
||||||
self.route(
|
self.route(
|
||||||
|
"/api/address/{address}",
|
||||||
|
get(
|
||||||
|
async |Path(address): Path<String>, state: State<AppState>| -> Response {
|
||||||
|
info!(address);
|
||||||
|
let address = Address::from_str(&address).unwrap();
|
||||||
|
if !address.is_valid_for_network(Network::Bitcoin) {
|
||||||
|
return "Invalid address".into_response();
|
||||||
|
}
|
||||||
|
let address = address.assume_checked();
|
||||||
|
let interface = state.interface;
|
||||||
|
let indexer = interface.indexer();
|
||||||
|
let computer = interface.computer();
|
||||||
|
let stores = &indexer.stores;
|
||||||
|
let hash = AddressBytesHash::from(&address);
|
||||||
|
dbg!(&hash);
|
||||||
|
dbg!(
|
||||||
|
&address,
|
||||||
|
address.address_type(),
|
||||||
|
address.script_pubkey(),
|
||||||
|
OutputType::from(&address)
|
||||||
|
);
|
||||||
|
let addri = stores
|
||||||
|
.addressbyteshash_to_typeindex
|
||||||
|
.get(&hash)
|
||||||
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
|
.into_owned();
|
||||||
|
println!("Script pubkey: {}", address.script_pubkey());
|
||||||
|
println!("Address type: {:?}", address.address_type());
|
||||||
|
let output_type = OutputType::from(&address);
|
||||||
|
let stateful = &computer.stateful;
|
||||||
|
let price = computer.price.as_ref().map(|v| {
|
||||||
|
*v.timeindexes_to_price_close
|
||||||
|
.dateindex
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.last()
|
||||||
|
.unwrap()
|
||||||
|
.1
|
||||||
|
.into_owned()
|
||||||
|
});
|
||||||
|
|
||||||
|
let anyaddri = match output_type {
|
||||||
|
OutputType::P2PK33 => stateful
|
||||||
|
.p2pk33addressindex_to_anyaddressindex
|
||||||
|
.iter()
|
||||||
|
.unwrap_get_inner(addri.into()),
|
||||||
|
OutputType::P2PK65 => stateful
|
||||||
|
.p2pk65addressindex_to_anyaddressindex
|
||||||
|
.iter()
|
||||||
|
.unwrap_get_inner(addri.into()),
|
||||||
|
OutputType::P2PKH => stateful
|
||||||
|
.p2pkhaddressindex_to_anyaddressindex
|
||||||
|
.iter()
|
||||||
|
.unwrap_get_inner(addri.into()),
|
||||||
|
OutputType::P2SH => stateful
|
||||||
|
.p2shaddressindex_to_anyaddressindex
|
||||||
|
.iter()
|
||||||
|
.unwrap_get_inner(addri.into()),
|
||||||
|
OutputType::P2TR => stateful
|
||||||
|
.p2traddressindex_to_anyaddressindex
|
||||||
|
.iter()
|
||||||
|
.unwrap_get_inner(addri.into()),
|
||||||
|
OutputType::P2WPKH => stateful
|
||||||
|
.p2wpkhaddressindex_to_anyaddressindex
|
||||||
|
.iter()
|
||||||
|
.unwrap_get_inner(addri.into()),
|
||||||
|
OutputType::P2WSH => stateful
|
||||||
|
.p2wshaddressindex_to_anyaddressindex
|
||||||
|
.iter()
|
||||||
|
.unwrap_get_inner(addri.into()),
|
||||||
|
OutputType::P2A => stateful
|
||||||
|
.p2aaddressindex_to_anyaddressindex
|
||||||
|
.iter()
|
||||||
|
.unwrap_get_inner(addri.into()),
|
||||||
|
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let addr_data = match anyaddri.to_enum() {
|
||||||
|
AnyAddressDataIndexEnum::Loaded(loadedi) => stateful
|
||||||
|
.loadedaddressindex_to_loadedaddressdata
|
||||||
|
.iter()
|
||||||
|
.unwrap_get_inner(loadedi),
|
||||||
|
AnyAddressDataIndexEnum::Empty(emptyi) => stateful
|
||||||
|
.emptyaddressindex_to_emptyaddressdata
|
||||||
|
.iter()
|
||||||
|
.unwrap_get_inner(emptyi)
|
||||||
|
.into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let amount = addr_data.amount();
|
||||||
|
Json(serde_json::json!({
|
||||||
|
"address": address,
|
||||||
|
"type": output_type,
|
||||||
|
"index": addri,
|
||||||
|
"chain_stats": {
|
||||||
|
"funded_txo_count": serde_json::Value::Null,
|
||||||
|
"funded_txo_sum": addr_data.received,
|
||||||
|
"spent_txo_count": serde_json::Value::Null,
|
||||||
|
"spent_txo_sum": addr_data.sent,
|
||||||
|
"utxo_count": addr_data.utxos,
|
||||||
|
"balance": amount,
|
||||||
|
"balance_usd": price.map_or(serde_json::Value::Null, |p| serde_json::Value::Number(Number::from_f64( *(p * Bitcoin::from(amount))).unwrap())),
|
||||||
|
"realized_value": addr_data.realized_cap,
|
||||||
|
"tx_count": serde_json::Value::Null,
|
||||||
|
"avg_cost_basis": addr_data.realized_price()
|
||||||
|
},
|
||||||
|
"mempool_stats": serde_json::Value::Null
|
||||||
|
}))
|
||||||
|
.into_response()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/api/tx/{txid}",
|
||||||
|
get(
|
||||||
|
async |Path(txid): Path<String>, state: State<AppState>| -> Response {
|
||||||
|
let txid = bitcoin::Txid::from_str(&txid).unwrap();
|
||||||
|
let txid = Txid::from(txid);
|
||||||
|
let prefix = TxidPrefix::from(&txid);
|
||||||
|
let interface = state.interface;
|
||||||
|
let indexer = interface.indexer();
|
||||||
|
let txindex = indexer
|
||||||
|
.stores
|
||||||
|
.txidprefix_to_txindex
|
||||||
|
.get(&prefix)
|
||||||
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
|
.into_owned();
|
||||||
|
let version = indexer
|
||||||
|
.vecs
|
||||||
|
.txindex_to_txversion
|
||||||
|
.iter()
|
||||||
|
.unwrap_get_inner(txindex);
|
||||||
|
let rawlocktime = indexer
|
||||||
|
.vecs
|
||||||
|
.txindex_to_rawlocktime
|
||||||
|
.iter()
|
||||||
|
.unwrap_get_inner(txindex);
|
||||||
|
let locktime = LockTime::from(rawlocktime);
|
||||||
|
|
||||||
|
Json(serde_json::json!({
|
||||||
|
"txid": txid,
|
||||||
|
"index": txindex,
|
||||||
|
"version": version,
|
||||||
|
"locktime": locktime
|
||||||
|
}))
|
||||||
|
.into_response()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
"/api/vecs/index-count",
|
"/api/vecs/index-count",
|
||||||
get(async |State(app_state): State<AppState>| -> Response {
|
get(async |State(app_state): State<AppState>| -> Response {
|
||||||
Json(app_state.interface.get_index_count()).into_response()
|
Json(app_state.interface.get_index_count()).into_response()
|
||||||
@@ -81,7 +245,7 @@ impl ApiRoutes for Router<AppState> {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
// .route("/api/vecs/variants", get(variants_handler))
|
// .route("/api/vecs/variants", get(variants_handler))
|
||||||
.route("/api/vecs/query", get(interface::handler))
|
.route("/api/vecs/query", get(vecs::handler))
|
||||||
.route(
|
.route(
|
||||||
"/api/vecs/{variant}",
|
"/api/vecs/{variant}",
|
||||||
get(
|
get(
|
||||||
@@ -99,7 +263,7 @@ impl ApiRoutes for Router<AppState> {
|
|||||||
(index, split.collect::<Vec<_>>().join(TO_SEPARATOR)),
|
(index, split.collect::<Vec<_>>().join(TO_SEPARATOR)),
|
||||||
params_opt,
|
params_opt,
|
||||||
));
|
));
|
||||||
interface::handler(uri, headers, Query(params), state).await
|
vecs::handler(uri, headers, Query(params), state).await
|
||||||
} else {
|
} else {
|
||||||
"Bad variant".into_response()
|
"Bad variant".into_response()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,3 +17,4 @@ brk_structs = { workspace = true }
|
|||||||
byteview = { workspace = true }
|
byteview = { workspace = true }
|
||||||
fjall = { workspace = true }
|
fjall = { workspace = true }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
|
parking_lot = { workspace = true }
|
||||||
|
|||||||
+15
-10
@@ -6,6 +6,7 @@ use std::{
|
|||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
fs, mem,
|
fs, mem,
|
||||||
path::Path,
|
path::Path,
|
||||||
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use brk_error::Result;
|
use brk_error::Result;
|
||||||
@@ -22,13 +23,13 @@ mod meta;
|
|||||||
pub use any::*;
|
pub use any::*;
|
||||||
use log::info;
|
use log::info;
|
||||||
use meta::*;
|
use meta::*;
|
||||||
|
use parking_lot::RwLock;
|
||||||
|
|
||||||
pub struct Store<Key, Value> {
|
pub struct Store<Key, Value> {
|
||||||
meta: StoreMeta,
|
meta: StoreMeta,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
keyspace: TransactionalKeyspace,
|
keyspace: TransactionalKeyspace,
|
||||||
// Arc it
|
partition: Arc<RwLock<Option<TransactionalPartitionHandle>>>,
|
||||||
partition: Option<TransactionalPartitionHandle>,
|
|
||||||
rtx: ReadTransaction,
|
rtx: ReadTransaction,
|
||||||
puts: BTreeMap<Key, Value>,
|
puts: BTreeMap<Key, Value>,
|
||||||
dels: BTreeSet<Key>,
|
dels: BTreeSet<Key>,
|
||||||
@@ -77,7 +78,7 @@ where
|
|||||||
meta,
|
meta,
|
||||||
name: Box::leak(Box::new(name.to_string())),
|
name: Box::leak(Box::new(name.to_string())),
|
||||||
keyspace: keyspace.clone(),
|
keyspace: keyspace.clone(),
|
||||||
partition: Some(partition),
|
partition: Arc::new(RwLock::new(Some(partition))),
|
||||||
rtx,
|
rtx,
|
||||||
puts: BTreeMap::new(),
|
puts: BTreeMap::new(),
|
||||||
dels: BTreeSet::new(),
|
dels: BTreeSet::new(),
|
||||||
@@ -90,7 +91,7 @@ where
|
|||||||
Ok(Some(Cow::Borrowed(v)))
|
Ok(Some(Cow::Borrowed(v)))
|
||||||
} else if let Some(slice) = self
|
} else if let Some(slice) = self
|
||||||
.rtx
|
.rtx
|
||||||
.get(self.partition.as_ref().unwrap(), ByteView::from(key))?
|
.get(self.partition.read().as_ref().unwrap(), ByteView::from(key))?
|
||||||
{
|
{
|
||||||
Ok(Some(Cow::Owned(V::from(ByteView::from(slice)))))
|
Ok(Some(Cow::Owned(V::from(ByteView::from(slice)))))
|
||||||
} else {
|
} else {
|
||||||
@@ -100,7 +101,7 @@ where
|
|||||||
|
|
||||||
pub fn is_empty(&self) -> Result<bool> {
|
pub fn is_empty(&self) -> Result<bool> {
|
||||||
self.rtx
|
self.rtx
|
||||||
.is_empty(self.partition.as_ref().unwrap())
|
.is_empty(self.partition.read().as_ref().unwrap())
|
||||||
.map_err(|e| e.into())
|
.map_err(|e| e.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +129,7 @@ where
|
|||||||
|
|
||||||
pub fn iter(&self) -> impl Iterator<Item = (K, V)> {
|
pub fn iter(&self) -> impl Iterator<Item = (K, V)> {
|
||||||
self.rtx
|
self.rtx
|
||||||
.iter(self.partition.as_ref().unwrap())
|
.iter(self.partition.read().as_ref().unwrap())
|
||||||
.map(|res| res.unwrap())
|
.map(|res| res.unwrap())
|
||||||
.map(|(k, v)| (K::from(ByteView::from(k)), V::from(ByteView::from(v))))
|
.map(|(k, v)| (K::from(ByteView::from(k)), V::from(ByteView::from(v))))
|
||||||
}
|
}
|
||||||
@@ -203,7 +204,9 @@ where
|
|||||||
|
|
||||||
let mut wtx = self.keyspace.write_tx();
|
let mut wtx = self.keyspace.write_tx();
|
||||||
|
|
||||||
let partition = self.partition.as_ref().unwrap();
|
let partition = self.partition.read();
|
||||||
|
|
||||||
|
let partition = partition.as_ref().unwrap();
|
||||||
|
|
||||||
remove.for_each(|key| wtx.remove(partition, ByteView::from(key)));
|
remove.for_each(|key| wtx.remove(partition, ByteView::from(key)));
|
||||||
|
|
||||||
@@ -262,7 +265,9 @@ where
|
|||||||
fn reset(&mut self) -> Result<()> {
|
fn reset(&mut self) -> Result<()> {
|
||||||
info!("Resetting {}...", self.name);
|
info!("Resetting {}...", self.name);
|
||||||
|
|
||||||
let partition: TransactionalPartitionHandle = self.partition.take().unwrap();
|
let mut opt = self.partition.write();
|
||||||
|
|
||||||
|
let partition = opt.take().unwrap();
|
||||||
|
|
||||||
self.keyspace.delete_partition(partition)?;
|
self.keyspace.delete_partition(partition)?;
|
||||||
|
|
||||||
@@ -270,7 +275,7 @@ where
|
|||||||
|
|
||||||
let partition = Self::open_partition_handle(&self.keyspace, self.name, self.bloom_filters)?;
|
let partition = Self::open_partition_handle(&self.keyspace, self.name, self.bloom_filters)?;
|
||||||
|
|
||||||
self.partition.replace(partition);
|
opt.replace(partition);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -301,7 +306,7 @@ where
|
|||||||
meta: self.meta.clone(),
|
meta: self.meta.clone(),
|
||||||
name: self.name,
|
name: self.name,
|
||||||
keyspace: self.keyspace.clone(),
|
keyspace: self.keyspace.clone(),
|
||||||
partition: None,
|
partition: self.partition.clone(),
|
||||||
rtx: self.keyspace.read_tx(),
|
rtx: self.keyspace.read_tx(),
|
||||||
puts: self.puts.clone(),
|
puts: self.puts.clone(),
|
||||||
dels: self.dels.clone(),
|
dels: self.dels.clone(),
|
||||||
|
|||||||
@@ -59,6 +59,12 @@ impl AddressBytes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&Address> for AddressBytes {
|
||||||
|
fn from(value: &Address) -> Self {
|
||||||
|
Self::try_from((&value.script_pubkey(), OutputType::from(value))).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<(&ScriptBuf, OutputType)> for AddressBytes {
|
impl TryFrom<(&ScriptBuf, OutputType)> for AddressBytes {
|
||||||
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> {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use bitcoin::Address;
|
||||||
use byteview::ByteView;
|
use byteview::ByteView;
|
||||||
use derive_deref::Deref;
|
use derive_deref::Deref;
|
||||||
use zerocopy::{FromBytes, IntoBytes};
|
use zerocopy::{FromBytes, IntoBytes};
|
||||||
@@ -21,6 +22,12 @@ use super::{AddressBytes, OutputType};
|
|||||||
)]
|
)]
|
||||||
pub struct AddressBytesHash([u8; 8]);
|
pub struct AddressBytesHash([u8; 8]);
|
||||||
|
|
||||||
|
impl From<&Address> for AddressBytesHash {
|
||||||
|
fn from(value: &Address) -> Self {
|
||||||
|
Self::from((&AddressBytes::from(value), OutputType::from(value)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<(&AddressBytes, OutputType)> for AddressBytesHash {
|
impl From<(&AddressBytes, OutputType)> for AddressBytesHash {
|
||||||
fn from((address_bytes, outputtype): (&AddressBytes, OutputType)) -> Self {
|
fn from((address_bytes, outputtype): (&AddressBytes, OutputType)) -> Self {
|
||||||
let mut slice = rapidhash::v3::rapidhash_v3(address_bytes.as_slice()).to_le_bytes();
|
let mut slice = rapidhash::v3::rapidhash_v3(address_bytes.as_slice()).to_le_bytes();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use bitcoin::{ScriptBuf, opcodes::all::OP_PUSHBYTES_2};
|
use bitcoin::{Address, AddressType, ScriptBuf, opcodes::all::OP_PUSHBYTES_2};
|
||||||
|
use brk_error::Error;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||||
|
|
||||||
@@ -380,3 +381,38 @@ impl From<&ScriptBuf> for OutputType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&Address> for OutputType {
|
||||||
|
fn from(value: &Address) -> Self {
|
||||||
|
Self::from(&value.script_pubkey())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<AddressType> for OutputType {
|
||||||
|
fn from(value: AddressType) -> Self {
|
||||||
|
match value {
|
||||||
|
AddressType::P2a => Self::P2A,
|
||||||
|
AddressType::P2pkh => Self::P2PKH,
|
||||||
|
AddressType::P2sh => Self::P2SH,
|
||||||
|
AddressType::P2tr => Self::P2TR,
|
||||||
|
AddressType::P2wpkh => Self::P2WPKH,
|
||||||
|
AddressType::P2wsh => Self::P2WSH,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<OutputType> for AddressType {
|
||||||
|
type Error = Error;
|
||||||
|
fn try_from(value: OutputType) -> Result<Self, Self::Error> {
|
||||||
|
Ok(match value {
|
||||||
|
OutputType::P2A => Self::P2a,
|
||||||
|
OutputType::P2PKH => Self::P2pkh,
|
||||||
|
OutputType::P2SH => Self::P2sh,
|
||||||
|
OutputType::P2TR => Self::P2tr,
|
||||||
|
OutputType::P2WPKH => Self::P2wpkh,
|
||||||
|
OutputType::P2WSH => Self::P2wsh,
|
||||||
|
_ => return Err(Error::Str("Bad output format")),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+8
-4
@@ -52,13 +52,12 @@
|
|||||||
- _LOGGER_
|
- _LOGGER_
|
||||||
- remove colors from file
|
- remove colors from file
|
||||||
- _PARSER_
|
- _PARSER_
|
||||||
- save `vec` file instead of `json`
|
- Stateless
|
||||||
- support lock file, process in read only if already opened in write mode
|
|
||||||
- if less than X (10 maybe ?) get block using rpc instead of parsing the block files
|
- if less than X (10 maybe ?) get block using rpc instead of parsing the block files
|
||||||
- support `None` output_dir
|
|
||||||
- _SERVER_
|
- _SERVER_
|
||||||
- api
|
- api
|
||||||
- copy mempool's rest api
|
- copy mempool's rest api
|
||||||
|
- https://mempool.space/docs/api/rest
|
||||||
- add extensions support (.json .csv …) instead of only format
|
- add extensions support (.json .csv …) instead of only format
|
||||||
- if format instead of extension then don't download file
|
- if format instead of extension then don't download file
|
||||||
- ddos protection
|
- ddos protection
|
||||||
@@ -89,6 +88,8 @@
|
|||||||
- _PACKAGES_
|
- _PACKAGES_
|
||||||
- move packages from `bitview` to `/packages` or `/websites/packages` or else
|
- move packages from `bitview` to `/packages` or `/websites/packages` or else
|
||||||
- move the fetching logic from `bitview` website to an independent `brk` package which could be published to npm
|
- move the fetching logic from `bitview` website to an independent `brk` package which could be published to npm
|
||||||
|
- https://www.npmjs.com/package/@mempool/mempool.js
|
||||||
|
- auto publish with github actions
|
||||||
- _BITVIEW_
|
- _BITVIEW_
|
||||||
- explorer
|
- explorer
|
||||||
- blocks (interval as length between)
|
- blocks (interval as length between)
|
||||||
@@ -126,7 +127,10 @@
|
|||||||
- global
|
- global
|
||||||
- improve behavior when local storage is unavailable
|
- improve behavior when local storage is unavailable
|
||||||
- by having a global state
|
- by having a global state
|
||||||
|
- font:
|
||||||
|
- https://fonts.google.com/specimen/Space+Mono
|
||||||
|
|
||||||
- keep as many files as possible [under 14kb](https://endtimes.dev/why-your-website-should-be-under-14kb-in-size/)
|
- keep as many files as possible [under 14kb](https://endtimes.dev/why-your-website-should-be-under-14kb-in-size/)
|
||||||
- __GLOBAL__
|
- __GLOBAL__
|
||||||
- check `TODO`s in codebase
|
- check `TODO`s in codebase
|
||||||
- rename `output` to `txout`, `input` to `txin`
|
- rename `output` to `txout` or `vout`, `input` to `txin` or `vin`
|
||||||
|
|||||||
Reference in New Issue
Block a user