mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-24 06:39:58 -07:00
global: snapshot
This commit is contained in:
@@ -20,14 +20,17 @@ full = [
|
||||
"fetcher",
|
||||
"grouper",
|
||||
"indexer",
|
||||
"interface",
|
||||
"iterator",
|
||||
"logger",
|
||||
"mcp",
|
||||
"parser",
|
||||
"monitor",
|
||||
"query",
|
||||
"reader",
|
||||
"rpc",
|
||||
"server",
|
||||
"store",
|
||||
"types",
|
||||
"traversable",
|
||||
"types",
|
||||
]
|
||||
binder = ["brk_binder"]
|
||||
bundler = ["brk_bundler"]
|
||||
@@ -37,14 +40,17 @@ error = ["brk_error"]
|
||||
fetcher = ["brk_fetcher"]
|
||||
grouper = ["brk_grouper"]
|
||||
indexer = ["brk_indexer"]
|
||||
interface = ["brk_query"]
|
||||
iterator = ["brk_iterator"]
|
||||
logger = ["brk_logger"]
|
||||
mcp = ["brk_mcp"]
|
||||
parser = ["brk_reader"]
|
||||
monitor = ["brk_monitor"]
|
||||
query = ["brk_query"]
|
||||
reader = ["brk_reader"]
|
||||
rpc = ["brk_rpc"]
|
||||
server = ["brk_server"]
|
||||
store = ["brk_store"]
|
||||
types = ["brk_types"]
|
||||
traversable = ["brk_traversable"]
|
||||
types = ["brk_types"]
|
||||
|
||||
[dependencies]
|
||||
brk_binder = { workspace = true, optional = true }
|
||||
@@ -55,14 +61,17 @@ brk_error = { workspace = true, optional = true }
|
||||
brk_fetcher = { workspace = true, optional = true }
|
||||
brk_grouper = { workspace = true, optional = true }
|
||||
brk_indexer = { workspace = true, optional = true }
|
||||
brk_query = { workspace = true, optional = true }
|
||||
brk_iterator = { workspace = true, optional = true }
|
||||
brk_logger = { workspace = true, optional = true }
|
||||
brk_mcp = { workspace = true, optional = true }
|
||||
brk_monitor = { workspace = true, optional = true }
|
||||
brk_query = { workspace = true, optional = true }
|
||||
brk_reader = { workspace = true, optional = true }
|
||||
brk_rpc = { workspace = true, optional = true }
|
||||
brk_server = { workspace = true, optional = true }
|
||||
brk_store = { workspace = true, optional = true }
|
||||
brk_types = { workspace = true, optional = true }
|
||||
brk_traversable = { workspace = true, optional = true }
|
||||
brk_types = { workspace = true, optional = true }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
@@ -32,9 +32,9 @@ pub use brk_grouper as grouper;
|
||||
#[doc(inline)]
|
||||
pub use brk_indexer as indexer;
|
||||
|
||||
#[cfg(feature = "interface")]
|
||||
#[cfg(feature = "iterator")]
|
||||
#[doc(inline)]
|
||||
pub use brk_query as interface;
|
||||
pub use brk_query as iterator;
|
||||
|
||||
#[cfg(feature = "logger")]
|
||||
#[doc(inline)]
|
||||
@@ -44,9 +44,21 @@ pub use brk_logger as logger;
|
||||
#[doc(inline)]
|
||||
pub use brk_mcp as mcp;
|
||||
|
||||
#[cfg(feature = "parser")]
|
||||
#[cfg(feature = "monitor")]
|
||||
#[doc(inline)]
|
||||
pub use brk_reader as parser;
|
||||
pub use brk_monitor as monitor;
|
||||
|
||||
#[cfg(feature = "query")]
|
||||
#[doc(inline)]
|
||||
pub use brk_query as query;
|
||||
|
||||
#[cfg(feature = "reader")]
|
||||
#[doc(inline)]
|
||||
pub use brk_reader as reader;
|
||||
|
||||
#[cfg(feature = "rpc")]
|
||||
#[doc(inline)]
|
||||
pub use brk_rpc as reader;
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
#[doc(inline)]
|
||||
@@ -56,10 +68,10 @@ pub use brk_server as server;
|
||||
#[doc(inline)]
|
||||
pub use brk_store as store;
|
||||
|
||||
#[cfg(feature = "types")]
|
||||
#[doc(inline)]
|
||||
pub use brk_types as types;
|
||||
|
||||
#[cfg(feature = "traversable")]
|
||||
#[doc(inline)]
|
||||
pub use brk_traversable as traversable;
|
||||
|
||||
#[cfg(feature = "types")]
|
||||
#[doc(inline)]
|
||||
pub use brk_types as types;
|
||||
|
||||
@@ -134,13 +134,13 @@ pub fn run() -> color_eyre::Result<()> {
|
||||
|
||||
info!("{} blocks found.", block_count + 1);
|
||||
|
||||
let starting_indexes = indexer
|
||||
.index(&reader, rpc, &exit, config.check_collisions())
|
||||
.unwrap();
|
||||
let starting_indexes = if config.check_collisions() {
|
||||
indexer.checked_index(&reader, rpc, &exit)?;
|
||||
} else {
|
||||
indexer.index(&reader, rpc, &exit)?;
|
||||
};
|
||||
|
||||
computer
|
||||
.compute(&indexer, starting_indexes, &reader, &exit)
|
||||
.unwrap();
|
||||
computer.compute(&indexer, starting_indexes, &reader, &exit)?;
|
||||
|
||||
info!("Waiting for new blocks...");
|
||||
|
||||
|
||||
@@ -16,11 +16,13 @@ brk_error = { workspace = true }
|
||||
brk_fetcher = { workspace = true }
|
||||
brk_grouper = { workspace = true }
|
||||
brk_indexer = { workspace = true }
|
||||
brk_iterator = { workspace = true }
|
||||
brk_logger = { workspace = true }
|
||||
brk_reader = { workspace = true }
|
||||
brk_rpc = { workspace = true }
|
||||
brk_store = { workspace = true }
|
||||
brk_types = { workspace = true }
|
||||
brk_traversable = { workspace = true }
|
||||
brk_types = { workspace = true }
|
||||
derive_deref = { workspace = true }
|
||||
log = { workspace = true }
|
||||
pco = "0.4.7"
|
||||
|
||||
@@ -8,7 +8,9 @@ use brk_computer::Computer;
|
||||
use brk_error::Result;
|
||||
use brk_fetcher::Fetcher;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_iterator::Blocks;
|
||||
use brk_reader::Reader;
|
||||
use brk_rpc::{Auth, Client};
|
||||
use vecdb::Exit;
|
||||
|
||||
pub fn main() -> Result<()> {
|
||||
@@ -20,10 +22,22 @@ pub fn main() -> Result<()> {
|
||||
.join("Bitcoin");
|
||||
// let bitcoin_dir = Path::new("/Volumes/WD_BLACK/bitcoin");
|
||||
|
||||
let rpc = Box::leak(Box::new(bitcoincore_rpc::Client::new(
|
||||
let client = Client::new(
|
||||
"http://localhost:8332",
|
||||
bitcoincore_rpc::Auth::CookieFile(bitcoin_dir.join(".cookie")),
|
||||
)?));
|
||||
Auth::CookieFile(bitcoin_dir.join(".cookie")),
|
||||
)?;
|
||||
|
||||
let reader = Reader::new(bitcoin_dir.join("blocks"), &client);
|
||||
|
||||
let blocks = Blocks::new(&client, &reader);
|
||||
|
||||
let outputs_dir = Path::new(&std::env::var("HOME").unwrap()).join(".brk");
|
||||
// let outputs_dir = Path::new("../../_outputs");
|
||||
|
||||
let mut indexer = Indexer::forced_import(&outputs_dir)?;
|
||||
|
||||
let fetcher = Fetcher::import(true, None)?;
|
||||
|
||||
let exit = Exit::new();
|
||||
exit.set_ctrlc_handler();
|
||||
|
||||
@@ -31,20 +45,11 @@ pub fn main() -> Result<()> {
|
||||
thread::Builder::new()
|
||||
.stack_size(256 * 1024 * 1024)
|
||||
.spawn(move || -> Result<()> {
|
||||
let outputs_dir = Path::new(&std::env::var("HOME").unwrap()).join(".brk");
|
||||
// let outputs_dir = Path::new("../../_outputs");
|
||||
|
||||
let reader = Reader::new(bitcoin_dir.join("blocks"), rpc);
|
||||
|
||||
let mut indexer = Indexer::forced_import(&outputs_dir)?;
|
||||
|
||||
let fetcher = Fetcher::import(true, None)?;
|
||||
|
||||
let mut computer = Computer::forced_import(&outputs_dir, &indexer, Some(fetcher))?;
|
||||
|
||||
loop {
|
||||
let i = Instant::now();
|
||||
let starting_indexes = indexer.index(&reader, rpc, &exit, true)?;
|
||||
let starting_indexes = indexer.checked_index(&blocks, &client, &exit)?;
|
||||
computer.compute(&indexer, starting_indexes, &reader, &exit)?;
|
||||
dbg!(i.elapsed());
|
||||
sleep(Duration::from_secs(10));
|
||||
|
||||
@@ -161,7 +161,7 @@ impl Vecs {
|
||||
let txinindex_to_value = LazyVecFrom2::init(
|
||||
"value",
|
||||
version + Version::ZERO,
|
||||
indexer.vecs.txinindex_to_txoutindex.boxed_clone(),
|
||||
indexes.txinindex_to_txoutindex.boxed_clone(),
|
||||
indexer.vecs.txoutindex_to_value.boxed_clone(),
|
||||
|index: TxInIndex, txinindex_to_txoutindex_iter, txoutindex_to_value_iter| {
|
||||
txinindex_to_txoutindex_iter.next_at(index.to_usize()).map(
|
||||
@@ -224,7 +224,7 @@ impl Vecs {
|
||||
let txindex_to_is_coinbase = LazyVecFrom2::init(
|
||||
"is_coinbase",
|
||||
version + Version::ZERO,
|
||||
indexes.txindex_to_height.boxed_clone(),
|
||||
indexer.vecs.txindex_to_height.boxed_clone(),
|
||||
indexer.vecs.height_to_first_txindex.boxed_clone(),
|
||||
|index: TxIndex, txindex_to_height_iter, height_to_first_txindex_iter| {
|
||||
txindex_to_height_iter
|
||||
|
||||
@@ -233,10 +233,6 @@ impl Computer {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn static_clone(&self) -> &'static Self {
|
||||
Box::leak(Box::new(self.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
// pub fn generate_allocation_files(monitored: &pools::Vecs) -> Result<()> {
|
||||
|
||||
@@ -542,7 +542,8 @@ impl Vecs {
|
||||
let height_to_first_p2wshaddressindex = &indexer.vecs.height_to_first_p2wshaddressindex;
|
||||
let height_to_output_count = chain.indexes_to_output_count.height.unwrap_sum();
|
||||
let height_to_input_count = chain.indexes_to_input_count.height.unwrap_sum();
|
||||
let txinindex_to_txoutindex = &indexer.vecs.txinindex_to_txoutindex;
|
||||
let txinindex_to_outpoint = &indexer.vecs.txinindex_to_outpoint;
|
||||
let txindex_to_first_txoutindex = &indexer.vecs.txindex_to_first_txoutindex;
|
||||
let txoutindex_to_value = &indexer.vecs.txoutindex_to_value;
|
||||
let txindex_to_height = &indexer.vecs.txindex_to_height;
|
||||
let height_to_timestamp_fixed = &indexes.height_to_timestamp_fixed;
|
||||
@@ -582,9 +583,10 @@ impl Vecs {
|
||||
+ height_to_timestamp_fixed.version()
|
||||
+ height_to_output_count.version()
|
||||
+ height_to_input_count.version()
|
||||
+ txinindex_to_txoutindex.version()
|
||||
+ txinindex_to_outpoint.version()
|
||||
+ txoutindex_to_value.version()
|
||||
+ txindex_to_height.version()
|
||||
+ txindex_to_first_txoutindex.version()
|
||||
+ txoutindex_to_txindex.version()
|
||||
+ txoutindex_to_outputtype.version()
|
||||
+ txoutindex_to_typeindex.version()
|
||||
@@ -790,7 +792,8 @@ impl Vecs {
|
||||
|
||||
starting_indexes.update_from_height(starting_height, indexes);
|
||||
|
||||
let txinindex_to_txoutindex_reader = txinindex_to_txoutindex.create_reader();
|
||||
let txinindex_to_outpoint_reader = txinindex_to_outpoint.create_reader();
|
||||
let txindex_to_first_txoutindex_reader = txindex_to_first_txoutindex.create_reader();
|
||||
let txoutindex_to_value_reader = txoutindex_to_value.create_reader();
|
||||
let txoutindex_to_outputtype_reader = txoutindex_to_outputtype.create_reader();
|
||||
let txoutindex_to_typeindex_reader = txoutindex_to_typeindex.create_reader();
|
||||
@@ -1029,8 +1032,9 @@ impl Vecs {
|
||||
.into_par_iter()
|
||||
.map(TxInIndex::from)
|
||||
.map(|txinindex| {
|
||||
let txoutindex =
|
||||
txinindex_to_txoutindex.unwrap_read(txinindex, &txinindex_to_txoutindex_reader);
|
||||
let outpoint = txinindex_to_outpoint.unwrap_read(txinindex, &txinindex_to_outpoint_reader);
|
||||
|
||||
let txoutindex = txindex_to_first_txoutindex.unwrap_read(outpoint.txindex(), &txindex_to_first_txoutindex_reader) + outpoint.vout();
|
||||
|
||||
let value = txoutindex_to_value
|
||||
.unwrap_read(txoutindex, &txoutindex_to_value_reader);
|
||||
@@ -2005,7 +2009,7 @@ impl HeightToAddressTypeToVec<(TypeIndex, Sats)> {
|
||||
|
||||
let amount = prev_amount.checked_sub(value).unwrap();
|
||||
|
||||
let will_be_empty = addressdata.utxo_count - 1 == 0;
|
||||
let will_be_empty = addressdata.has_1_utxos();
|
||||
|
||||
if will_be_empty
|
||||
|| vecs.amount_range.get_mut(amount).0.clone()
|
||||
|
||||
@@ -44,14 +44,14 @@ impl AddressCohortState {
|
||||
|
||||
let prev_realized_price = compute_price.then(|| addressdata.realized_price());
|
||||
let prev_supply_state = SupplyState {
|
||||
utxo_count: addressdata.utxo_count as u64,
|
||||
utxo_count: addressdata.utxo_count() as u64,
|
||||
value: addressdata.balance(),
|
||||
};
|
||||
|
||||
addressdata.send(value, prev_price)?;
|
||||
|
||||
let supply_state = SupplyState {
|
||||
utxo_count: addressdata.utxo_count as u64,
|
||||
utxo_count: addressdata.utxo_count() as u64,
|
||||
value: addressdata.balance(),
|
||||
};
|
||||
|
||||
@@ -82,14 +82,14 @@ impl AddressCohortState {
|
||||
|
||||
let prev_realized_price = compute_price.then(|| address_data.realized_price());
|
||||
let prev_supply_state = SupplyState {
|
||||
utxo_count: address_data.utxo_count as u64,
|
||||
utxo_count: address_data.utxo_count() as u64,
|
||||
value: address_data.balance(),
|
||||
};
|
||||
|
||||
address_data.receive(value, price);
|
||||
|
||||
let supply_state = SupplyState {
|
||||
utxo_count: address_data.utxo_count as u64,
|
||||
utxo_count: address_data.utxo_count() as u64,
|
||||
value: address_data.balance(),
|
||||
};
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ impl SubAssign<&SupplyState> for SupplyState {
|
||||
impl From<&LoadedAddressData> for SupplyState {
|
||||
fn from(value: &LoadedAddressData) -> Self {
|
||||
Self {
|
||||
utxo_count: value.utxo_count as u64,
|
||||
utxo_count: value.utxo_count() as u64,
|
||||
value: value.balance(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,20 +30,14 @@ fn main() -> Result<()> {
|
||||
Auth::CookieFile(bitcoin_dir.join(".cookie")),
|
||||
)?;
|
||||
|
||||
let reader = Reader::new(bitcoin_dir.join("blocks"), client.clone());
|
||||
let reader = Reader::new(bitcoin_dir.join("blocks"), &client);
|
||||
|
||||
let blocks = Blocks::new(client.clone(), reader);
|
||||
let blocks = Blocks::new(&client, &reader);
|
||||
|
||||
fs::create_dir_all(&outputs_dir)?;
|
||||
|
||||
let mut indexer = Indexer::forced_import(&outputs_dir)?;
|
||||
|
||||
// 44
|
||||
// let vecs = indexer.vecs.iter_any_collectable().collect::<Vec<_>>();
|
||||
// dbg!(indexer.vecs.to_tree_node());
|
||||
// dbg!(vecs.len());
|
||||
// std::process::exit(0);
|
||||
|
||||
let exit = Exit::new();
|
||||
exit.set_ctrlc_handler();
|
||||
|
||||
|
||||
@@ -812,10 +812,6 @@ impl Indexer {
|
||||
|
||||
Ok(starting_indexes)
|
||||
}
|
||||
|
||||
pub fn static_clone(&self) -> &'static Self {
|
||||
Box::leak(Box::new(self.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -17,9 +17,9 @@ fn main() -> Result<()> {
|
||||
Auth::CookieFile(bitcoin_dir.join(".cookie")),
|
||||
)?;
|
||||
|
||||
let reader = Reader::new(bitcoin_dir.join("blocks"), client.clone());
|
||||
let reader = Reader::new(bitcoin_dir.join("blocks"), &client);
|
||||
|
||||
let blocks = Blocks::new(client, reader);
|
||||
let blocks = Blocks::new(&client, &reader);
|
||||
|
||||
let i = Instant::now();
|
||||
blocks
|
||||
|
||||
@@ -28,18 +28,25 @@ pub struct Blocks(Arc<Source>);
|
||||
|
||||
impl Blocks {
|
||||
/// Create with smart mode (auto-select source based on range size)
|
||||
pub fn new(client: Client, reader: Reader) -> Self {
|
||||
Self::new_inner(Source::Smart { client, reader })
|
||||
pub fn new(client: &Client, reader: &Reader) -> Self {
|
||||
Self::new_inner(Source::Smart {
|
||||
client: client.clone(),
|
||||
reader: reader.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Create with RPC-only mode
|
||||
pub fn new_rpc(client: Client) -> Self {
|
||||
Self::new_inner(Source::Rpc { client })
|
||||
pub fn new_rpc(client: &Client) -> Self {
|
||||
Self::new_inner(Source::Rpc {
|
||||
client: client.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Create with Reader-only mode
|
||||
pub fn new_reader(reader: Reader) -> Self {
|
||||
Self::new_inner(Source::Reader { reader })
|
||||
pub fn new_reader(reader: &Reader) -> Self {
|
||||
Self::new_inner(Source::Reader {
|
||||
reader: reader.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn new_inner(source: Source) -> Self {
|
||||
|
||||
@@ -16,7 +16,7 @@ pub mod route;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MCP {
|
||||
query: &'static Query<'static>,
|
||||
query: Query,
|
||||
tool_router: ToolRouter<MCP>,
|
||||
}
|
||||
|
||||
@@ -24,9 +24,9 @@ const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
#[tool_router]
|
||||
impl MCP {
|
||||
pub fn new(query: &'static Query<'static>) -> Self {
|
||||
pub fn new(query: &Query) -> Self {
|
||||
Self {
|
||||
query,
|
||||
query: query.clone(),
|
||||
tool_router: Self::tool_router(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,20 +10,21 @@ use log::info;
|
||||
use crate::MCP;
|
||||
|
||||
pub trait MCPRoutes {
|
||||
fn add_mcp_routes(self, query: &'static Query<'static>, mcp: bool) -> Self;
|
||||
fn add_mcp_routes(self, query: &Query, mcp: bool) -> Self;
|
||||
}
|
||||
|
||||
impl<T> MCPRoutes for ApiRouter<T>
|
||||
where
|
||||
T: Clone + Send + Sync + 'static,
|
||||
{
|
||||
fn add_mcp_routes(self, query: &'static Query<'static>, mcp: bool) -> Self {
|
||||
fn add_mcp_routes(self, query: &Query, mcp: bool) -> Self {
|
||||
if !mcp {
|
||||
return self;
|
||||
}
|
||||
|
||||
let query = query.clone();
|
||||
let service = StreamableHttpService::new(
|
||||
move || Ok(MCP::new(query)),
|
||||
move || Ok(MCP::new(&query)),
|
||||
LocalSessionManager::default().into(),
|
||||
StreamableHttpServerConfig {
|
||||
stateful_mode: false,
|
||||
|
||||
@@ -15,8 +15,9 @@ brk_computer = { workspace = true }
|
||||
brk_error = { workspace = true }
|
||||
brk_indexer = { workspace = true }
|
||||
brk_reader = { workspace = true }
|
||||
brk_types = { workspace = true }
|
||||
brk_rpc = { workspace = true }
|
||||
brk_traversable = { workspace = true }
|
||||
brk_types = { workspace = true }
|
||||
derive_deref = { workspace = true }
|
||||
# quickmatch = { path = "../../../quickmatch" }
|
||||
quickmatch = "0.1.8"
|
||||
|
||||
@@ -5,6 +5,7 @@ use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_query::{Params, ParamsOpt, Query};
|
||||
use brk_reader::Reader;
|
||||
use brk_rpc::{Auth, Client};
|
||||
use brk_types::Index;
|
||||
use vecdb::Exit;
|
||||
|
||||
@@ -21,15 +22,18 @@ pub fn main() -> Result<()> {
|
||||
fs::create_dir_all(&outputs_dir)?;
|
||||
// let outputs_dir = Path::new("/Volumes/WD_BLACK1/brk");
|
||||
|
||||
let rpc = Box::leak(Box::new(bitcoincore_rpc::Client::new(
|
||||
let client = Client::new(
|
||||
"http://localhost:8332",
|
||||
bitcoincore_rpc::Auth::CookieFile(bitcoin_dir.join(".cookie")),
|
||||
)?));
|
||||
Auth::CookieFile(bitcoin_dir.join(".cookie")),
|
||||
)?;
|
||||
|
||||
let outputs_dir = Path::new(&std::env::var("HOME").unwrap()).join(".brk");
|
||||
// let outputs_dir = Path::new("../../_outputs");
|
||||
|
||||
let exit = Exit::new();
|
||||
exit.set_ctrlc_handler();
|
||||
|
||||
let reader = Reader::new(blocks_dir, rpc);
|
||||
let reader = Reader::new(blocks_dir, &client);
|
||||
|
||||
let indexer = Indexer::forced_import(&outputs_dir)?;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ use bitcoin::{Network, PublicKey, ScriptBuf};
|
||||
use brk_error::{Error, Result};
|
||||
use brk_types::{
|
||||
Address, AddressBytes, AddressBytesHash, AddressChainStats, AddressMempoolStats, AddressStats,
|
||||
AnyAddressDataIndexEnum, Bitcoin, OutputType,
|
||||
AnyAddressDataIndexEnum, OutputType,
|
||||
};
|
||||
use vecdb::{AnyIterableVec, VecIterator};
|
||||
|
||||
@@ -31,7 +31,7 @@ pub fn get_address(Address { address }: Address, query: &Query) -> Result<Addres
|
||||
let Ok(bytes) = AddressBytes::try_from((&script, type_)) else {
|
||||
return Err(Error::Str("Failed to convert the address to bytes"));
|
||||
};
|
||||
let hash = AddressBytesHash::from((&bytes, type_));
|
||||
let hash = AddressBytesHash::from(&bytes);
|
||||
|
||||
let Ok(Some(type_index)) = stores
|
||||
.addressbyteshash_to_typeindex
|
||||
|
||||
@@ -31,7 +31,7 @@ pub fn get_transaction_info(TxidPath { txid }: TxidPath, query: &Query) -> Resul
|
||||
|
||||
let txid = indexer.vecs.txindex_to_txid.iter().unwrap_get_inner(index);
|
||||
|
||||
let reader = query.parser();
|
||||
let reader = query.reader();
|
||||
let computer = query.computer();
|
||||
|
||||
let position = computer
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#![doc = include_str!("../README.md")]
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::{collections::BTreeMap, sync::Arc};
|
||||
|
||||
use brk_computer::Computer;
|
||||
use brk_error::Result;
|
||||
@@ -30,31 +30,32 @@ use crate::{
|
||||
vecs::{IndexToVec, MetricToVec},
|
||||
};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct Query<'a> {
|
||||
vecs: Vecs<'a>,
|
||||
parser: &'a Reader,
|
||||
#[derive(Clone)]
|
||||
pub struct Query(Arc<QueryInner<'static>>);
|
||||
struct QueryInner<'a> {
|
||||
vecs: &'a Vecs<'a>,
|
||||
reader: Reader,
|
||||
indexer: &'a Indexer,
|
||||
computer: &'a Computer,
|
||||
}
|
||||
|
||||
impl<'a> Query<'a> {
|
||||
pub fn build(parser: &Reader, indexer: &Indexer, computer: &Computer) -> Self {
|
||||
let reader = parser.static_clone();
|
||||
let indexer = indexer.static_clone();
|
||||
let computer = computer.static_clone();
|
||||
let vecs = Vecs::build(indexer, computer);
|
||||
impl Query {
|
||||
pub fn build(reader: &Reader, indexer: &Indexer, computer: &Computer) -> Self {
|
||||
let reader = reader.clone();
|
||||
let indexer = Box::leak(Box::new(indexer.clone()));
|
||||
let computer = Box::leak(Box::new(computer.clone()));
|
||||
let vecs = Box::leak(Box::new(Vecs::build(indexer, computer)));
|
||||
|
||||
Self {
|
||||
Self(Arc::new(QueryInner {
|
||||
vecs,
|
||||
parser: reader,
|
||||
reader,
|
||||
indexer,
|
||||
computer,
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn get_height(&self) -> Height {
|
||||
Height::from(self.indexer.vecs.height_to_blockhash.stamp())
|
||||
Height::from(self.indexer().vecs.height_to_blockhash.stamp())
|
||||
}
|
||||
|
||||
pub fn get_address(&self, address: Address) -> Result<AddressStats> {
|
||||
@@ -66,7 +67,7 @@ impl<'a> Query<'a> {
|
||||
}
|
||||
|
||||
pub fn match_metric(&self, metric: &Metric, limit: Limit) -> Vec<&str> {
|
||||
self.vecs.matches(metric, limit)
|
||||
self.vecs().matches(metric, limit)
|
||||
}
|
||||
|
||||
pub fn search_metric_with_index(
|
||||
@@ -212,11 +213,11 @@ impl<'a> Query<'a> {
|
||||
}
|
||||
|
||||
pub fn metric_to_index_to_vec(&self) -> &BTreeMap<&str, IndexToVec<'_>> {
|
||||
&self.vecs.metric_to_index_to_vec
|
||||
&self.vecs().metric_to_index_to_vec
|
||||
}
|
||||
|
||||
pub fn index_to_metric_to_vec(&self) -> &BTreeMap<Index, MetricToVec<'_>> {
|
||||
&self.vecs.index_to_metric_to_vec
|
||||
&self.vecs().index_to_metric_to_vec
|
||||
}
|
||||
|
||||
pub fn metric_count(&self) -> MetricCount {
|
||||
@@ -227,42 +228,50 @@ impl<'a> Query<'a> {
|
||||
}
|
||||
|
||||
pub fn distinct_metric_count(&self) -> usize {
|
||||
self.vecs.distinct_metric_count
|
||||
self.vecs().distinct_metric_count
|
||||
}
|
||||
|
||||
pub fn total_metric_count(&self) -> usize {
|
||||
self.vecs.total_metric_count
|
||||
self.vecs().total_metric_count
|
||||
}
|
||||
|
||||
pub fn get_indexes(&self) -> &[IndexInfo] {
|
||||
&self.vecs.indexes
|
||||
&self.vecs().indexes
|
||||
}
|
||||
|
||||
pub fn get_metrics(&'static self, pagination: PaginationParam) -> PaginatedMetrics {
|
||||
self.vecs.metrics(pagination)
|
||||
pub fn get_metrics(&self, pagination: PaginationParam) -> PaginatedMetrics {
|
||||
self.vecs().metrics(pagination)
|
||||
}
|
||||
|
||||
pub fn get_metrics_catalog(&self) -> &TreeNode {
|
||||
self.vecs.catalog()
|
||||
self.vecs().catalog()
|
||||
}
|
||||
|
||||
pub fn get_index_to_vecids(&self, paginated_index: PaginatedIndexParam) -> Vec<&str> {
|
||||
self.vecs.index_to_ids(paginated_index)
|
||||
self.vecs().index_to_ids(paginated_index)
|
||||
}
|
||||
|
||||
pub fn metric_to_indexes(&self, metric: String) -> Option<&Vec<Index>> {
|
||||
self.vecs.metric_to_indexes(metric)
|
||||
self.vecs().metric_to_indexes(metric)
|
||||
}
|
||||
|
||||
pub fn parser(&self) -> &Reader {
|
||||
self.parser
|
||||
#[inline]
|
||||
pub fn reader(&self) -> &Reader {
|
||||
&self.0.reader
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn indexer(&self) -> &Indexer {
|
||||
self.indexer
|
||||
self.0.indexer
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn computer(&self) -> &Computer {
|
||||
self.computer
|
||||
self.0.computer
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn vecs(&self) -> &'static Vecs<'static> {
|
||||
self.0.vecs
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ fn main() -> Result<()> {
|
||||
|
||||
let blocks_dir = bitcoin_dir.join("blocks");
|
||||
|
||||
let reader = Reader::new(blocks_dir, client);
|
||||
let reader = Reader::new(blocks_dir, &client);
|
||||
|
||||
let start = None;
|
||||
// let start = Some(916037_u32.into());
|
||||
|
||||
@@ -46,8 +46,8 @@ const BOUND_CAP: usize = 50;
|
||||
pub struct Reader(Arc<ReaderInner>);
|
||||
|
||||
impl Reader {
|
||||
pub fn new(blocks_dir: PathBuf, client: Client) -> Self {
|
||||
Self(Arc::new(ReaderInner::new(blocks_dir, client)))
|
||||
pub fn new(blocks_dir: PathBuf, client: &Client) -> Self {
|
||||
Self(Arc::new(ReaderInner::new(blocks_dir, client.clone())))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,11 @@ impl Client {
|
||||
self.call(|c| c.get_block(hash.into())).map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Returns the numbers of block in the longest chain.
|
||||
pub fn get_block_count(&self) -> Result<u64> {
|
||||
self.call(|c| c.get_block_count()).map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Returns the numbers of block in the longest chain.
|
||||
pub fn get_last_height(&self) -> Result<Height> {
|
||||
self.call(|c| c.get_block_count())
|
||||
|
||||
@@ -17,10 +17,12 @@ brk_computer = { workspace = true }
|
||||
brk_error = { workspace = true }
|
||||
brk_fetcher = { workspace = true }
|
||||
brk_indexer = { workspace = true }
|
||||
brk_query = { workspace = true }
|
||||
brk_iterator = { workspace = true }
|
||||
brk_logger = { workspace = true }
|
||||
brk_mcp = { workspace = true }
|
||||
brk_query = { workspace = true }
|
||||
brk_reader = { workspace = true }
|
||||
brk_rpc = { workspace = true }
|
||||
brk_types = { workspace = true }
|
||||
brk_traversable = { workspace = true }
|
||||
vecdb = { workspace = true }
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
use std::{path::Path, thread::sleep, time::Duration};
|
||||
|
||||
use bitcoincore_rpc::RpcApi;
|
||||
use brk_computer::Computer;
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_fetcher::Fetcher;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_iterator::Blocks;
|
||||
use brk_query::Query;
|
||||
use brk_reader::Reader;
|
||||
use brk_rpc::{Auth, Client};
|
||||
use brk_server::Server;
|
||||
use vecdb::Exit;
|
||||
|
||||
@@ -18,14 +19,14 @@ pub fn main() -> Result<()> {
|
||||
|
||||
let bitcoin_dir = Path::new("");
|
||||
|
||||
let rpc = Box::leak(Box::new(bitcoincore_rpc::Client::new(
|
||||
let client = Client::new(
|
||||
"http://localhost:8332",
|
||||
bitcoincore_rpc::Auth::CookieFile(bitcoin_dir.join(".cookie")),
|
||||
)?));
|
||||
let exit = Exit::new();
|
||||
exit.set_ctrlc_handler();
|
||||
Auth::CookieFile(bitcoin_dir.join(".cookie")),
|
||||
)?;
|
||||
|
||||
let reader = Reader::new(bitcoin_dir.join("blocks"), rpc);
|
||||
let reader = Reader::new(bitcoin_dir.join("blocks"), &client);
|
||||
|
||||
let blocks = Blocks::new(&client, &reader);
|
||||
|
||||
let outputs_dir = Path::new("../../_outputs");
|
||||
|
||||
@@ -35,13 +36,16 @@ pub fn main() -> Result<()> {
|
||||
|
||||
let mut computer = Computer::forced_import(outputs_dir, &indexer, fetcher)?;
|
||||
|
||||
let exit = Exit::new();
|
||||
exit.set_ctrlc_handler();
|
||||
|
||||
tokio::runtime::Builder::new_multi_thread()
|
||||
.enable_all()
|
||||
.build()?
|
||||
.block_on(async {
|
||||
let query = Query::build(&reader, &indexer, &computer);
|
||||
|
||||
let server = Server::new(query, None);
|
||||
let server = Server::new(&query, None);
|
||||
|
||||
let server = tokio::spawn(async move {
|
||||
server.serve(true).await.unwrap();
|
||||
@@ -49,13 +53,13 @@ pub fn main() -> Result<()> {
|
||||
|
||||
if process {
|
||||
loop {
|
||||
let block_count = rpc.get_block_count()?;
|
||||
let last_height = client.get_last_height()?;
|
||||
|
||||
let starting_indexes = indexer.checked_index(&reader, rpc, &exit)?;
|
||||
let starting_indexes = indexer.checked_index(&blocks, &client, &exit)?;
|
||||
|
||||
computer.compute(&indexer, starting_indexes, &reader, &exit)?;
|
||||
|
||||
while block_count == rpc.get_block_count()? {
|
||||
while last_height == client.get_last_height()? {
|
||||
sleep(Duration::from_secs(1))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,13 +37,13 @@ use crate::api::create_openapi;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppState {
|
||||
query: &'static Query<'static>,
|
||||
query: Query,
|
||||
path: Option<PathBuf>,
|
||||
cache: Arc<Cache<String, Bytes>>,
|
||||
}
|
||||
|
||||
impl Deref for AppState {
|
||||
type Target = &'static Query<'static>;
|
||||
type Target = Query;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.query
|
||||
}
|
||||
@@ -54,9 +54,9 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
pub struct Server(AppState);
|
||||
|
||||
impl Server {
|
||||
pub fn new(query: Query<'static>, files_path: Option<PathBuf>) -> Self {
|
||||
pub fn new(query: &Query, files_path: Option<PathBuf>) -> Self {
|
||||
Self(AppState {
|
||||
query: Box::leak(Box::new(query)),
|
||||
query: query.clone(),
|
||||
path: files_path,
|
||||
cache: Arc::new(Cache::new(5_000)),
|
||||
})
|
||||
@@ -106,7 +106,7 @@ impl Server {
|
||||
|
||||
let router = ApiRouter::new()
|
||||
.add_api_routes()
|
||||
.add_mcp_routes(state.query, mcp)
|
||||
.add_mcp_routes(&state.query, mcp)
|
||||
.add_files_routes(state.path.as_ref())
|
||||
.route(
|
||||
"/discord",
|
||||
|
||||
@@ -15,4 +15,4 @@ proc-macro = true
|
||||
[dependencies]
|
||||
syn = "2.0"
|
||||
quote = "1.0"
|
||||
proc-macro2 = "1.0.102"
|
||||
proc-macro2 = "1.0.103"
|
||||
|
||||
@@ -49,6 +49,16 @@ impl LoadedAddressData {
|
||||
self.balance() == Sats::ZERO
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn utxo_count(&self) -> u32 {
|
||||
self.funded_txo_count - self.spent_txo_count
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_1_utxos(&self) -> bool {
|
||||
self.utxo_count() == 1
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_0_utxos(&self) -> bool {
|
||||
self.funded_txo_count == self.spent_txo_count
|
||||
|
||||
@@ -23,7 +23,7 @@ use crate::{TxIndex, Vout};
|
||||
JsonSchema,
|
||||
Hash,
|
||||
)]
|
||||
pub struct OutPoint(pub u64);
|
||||
pub struct OutPoint(u64);
|
||||
|
||||
impl OutPoint {
|
||||
pub const COINBASE: Self = Self(u64::MAX);
|
||||
|
||||
Reference in New Issue
Block a user