global: snapshot

This commit is contained in:
nym21
2025-09-14 23:13:18 +02:00
parent ce50b14591
commit 17dc4bde5e
13 changed files with 295 additions and 46 deletions
Generated
+31 -15
View File
@@ -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
View File
@@ -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"]}
+9 -9
View File
@@ -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!(),
} }
+8
View File
@@ -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
}
} }
+2
View File
@@ -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 }
+167 -3
View File
@@ -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()
} }
+1
View File
@@ -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
View File
@@ -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();
+37 -1
View File
@@ -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
View File
@@ -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`