mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-05-05 19:59:09 -07:00
global: snapshot + core: impl Display for bytes structs
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![doc = include_str!(concat!("../", env!("CARGO_PKG_README")))]
|
||||
|
||||
#[cfg(feature = "core")]
|
||||
|
||||
@@ -8,15 +8,19 @@ use crate::run::RunConfig;
|
||||
pub fn query(params: QueryParams) -> color_eyre::Result<()> {
|
||||
let config = RunConfig::import(None)?;
|
||||
|
||||
let mut indexer = Indexer::new(&config.indexeddir())?;
|
||||
let mut indexer = Indexer::new(config.indexeddir())?;
|
||||
indexer.import_vecs()?;
|
||||
|
||||
let mut computer = Computer::new(&config.computeddir());
|
||||
let mut computer = Computer::new(config.computeddir());
|
||||
computer.import_vecs()?;
|
||||
|
||||
let query = Query::build(&indexer, &computer);
|
||||
|
||||
let ids = params.values.iter().flat_map(|v| v.split(",")).collect::<Vec<_>>();
|
||||
let ids = params
|
||||
.values
|
||||
.iter()
|
||||
.flat_map(|v| v.split(","))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let index = Index::try_from(params.index.as_str())?;
|
||||
|
||||
@@ -36,7 +40,8 @@ pub fn query(params: QueryParams) -> color_eyre::Result<()> {
|
||||
Value::List(v) => vec![v],
|
||||
Value::Matrix(v) => v,
|
||||
};
|
||||
let mut table = v.to_table(ids.iter().map(|id| id.to_string()).collect::<Vec<_>>());
|
||||
let mut table =
|
||||
v.to_table(ids.iter().map(|id| id.to_string()).collect::<Vec<_>>());
|
||||
table.with(Style::psql());
|
||||
table.to_string()
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use std::{
|
||||
use brk_computer::Computer;
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_parser::rpc::{self, Auth, RpcApi};
|
||||
use brk_parser::rpc::{self, Auth, Client, RpcApi};
|
||||
use brk_server::tokio;
|
||||
use clap::{Parser, ValueEnum};
|
||||
use color_eyre::eyre::eyre;
|
||||
@@ -20,26 +20,17 @@ use crate::path_dot_brk;
|
||||
pub fn run(config: RunConfig) -> color_eyre::Result<()> {
|
||||
let config = RunConfig::import(Some(config))?;
|
||||
|
||||
let bitcoin_dir = config.bitcoindir();
|
||||
|
||||
let rpc = Box::leak(Box::new(rpc::Client::new(
|
||||
&format!(
|
||||
"http://{}:{}",
|
||||
config.rpcconnect().unwrap_or(&"localhost".to_string()),
|
||||
config.rpcport().unwrap_or(8332)
|
||||
),
|
||||
config.to_rpc_auth().unwrap(),
|
||||
)?));
|
||||
let rpc = config.rpc()?;
|
||||
|
||||
let exit = Exit::new();
|
||||
|
||||
let parser = brk_parser::Parser::new(bitcoin_dir.as_path(), rpc);
|
||||
let parser = brk_parser::Parser::new(config.bitcoindir(), rpc);
|
||||
|
||||
let mut indexer = Indexer::new(&config.indexeddir())?;
|
||||
let mut indexer = Indexer::new(config.indexeddir())?;
|
||||
indexer.import_stores()?;
|
||||
indexer.import_vecs()?;
|
||||
|
||||
let mut computer = Computer::new(&config.computeddir());
|
||||
let mut computer = Computer::new(config.computeddir());
|
||||
computer.import_stores()?;
|
||||
computer.import_vecs()?;
|
||||
|
||||
@@ -52,7 +43,9 @@ pub fn run(config: RunConfig) -> color_eyre::Result<()> {
|
||||
|
||||
let handle = if config.serve() {
|
||||
Some(tokio::spawn(async move {
|
||||
brk_server::main(served_indexer, served_computer).await.unwrap();
|
||||
brk_server::main(served_indexer, served_computer)
|
||||
.await
|
||||
.unwrap();
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
@@ -231,7 +224,7 @@ impl RunConfig {
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
if self.to_rpc_auth().is_err() {
|
||||
if self.rpc_auth().is_err() {
|
||||
println!(
|
||||
"No way found to authenticate the RPC client, please either set --rpccookiefile or --rpcuser and --rpcpassword.\nRun the program with '-h' for help."
|
||||
);
|
||||
@@ -249,7 +242,18 @@ impl RunConfig {
|
||||
fs::write(path, toml::to_string(self).unwrap())
|
||||
}
|
||||
|
||||
pub fn to_rpc_auth(&self) -> color_eyre::Result<Auth> {
|
||||
pub fn rpc(&self) -> color_eyre::Result<&'static Client> {
|
||||
Ok(Box::leak(Box::new(rpc::Client::new(
|
||||
&format!(
|
||||
"http://{}:{}",
|
||||
self.rpcconnect().unwrap_or(&"localhost".to_string()),
|
||||
self.rpcport().unwrap_or(8332)
|
||||
),
|
||||
self.rpc_auth().unwrap(),
|
||||
)?)))
|
||||
}
|
||||
|
||||
fn rpc_auth(&self) -> color_eyre::Result<Auth> {
|
||||
let cookie = self.path_cookiefile();
|
||||
|
||||
if cookie.is_file() {
|
||||
@@ -264,11 +268,11 @@ impl RunConfig {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rpcconnect(&self) -> Option<&String> {
|
||||
fn rpcconnect(&self) -> Option<&String> {
|
||||
self.rpcconnect.as_ref()
|
||||
}
|
||||
|
||||
pub fn rpcport(&self) -> Option<u16> {
|
||||
fn rpcport(&self) -> Option<u16> {
|
||||
self.rpcport
|
||||
}
|
||||
|
||||
@@ -297,11 +301,13 @@ impl RunConfig {
|
||||
}
|
||||
|
||||
pub fn process(&self) -> bool {
|
||||
self.mode.is_none_or(|m| m == Mode::All || m == Mode::Processor)
|
||||
self.mode
|
||||
.is_none_or(|m| m == Mode::All || m == Mode::Processor)
|
||||
}
|
||||
|
||||
pub fn serve(&self) -> bool {
|
||||
self.mode.is_none_or(|m| m == Mode::All || m == Mode::Server)
|
||||
self.mode
|
||||
.is_none_or(|m| m == Mode::All || m == Mode::Server)
|
||||
}
|
||||
|
||||
fn path_cookiefile(&self) -> PathBuf {
|
||||
@@ -314,7 +320,9 @@ impl RunConfig {
|
||||
fn fix_user_path(path: &str) -> PathBuf {
|
||||
let fix = move |pattern: &str| {
|
||||
if path.starts_with(pattern) {
|
||||
let path = &path.replace(&format!("{pattern}/"), "").replace(pattern, "");
|
||||
let path = &path
|
||||
.replace(&format!("{pattern}/"), "")
|
||||
.replace(pattern, "");
|
||||
|
||||
let home = std::env::var("HOME").unwrap();
|
||||
|
||||
@@ -328,7 +336,20 @@ impl RunConfig {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy, Parser, ValueEnum, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(
|
||||
Default,
|
||||
Debug,
|
||||
Clone,
|
||||
Copy,
|
||||
Parser,
|
||||
ValueEnum,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
)]
|
||||
pub enum Mode {
|
||||
#[default]
|
||||
All,
|
||||
|
||||
@@ -17,19 +17,19 @@ pub fn main() -> color_eyre::Result<()> {
|
||||
let bitcoin_dir = Path::new("../../../bitcoin");
|
||||
let rpc = Box::leak(Box::new(rpc::Client::new(
|
||||
"http://localhost:8332",
|
||||
rpc::Auth::CookieFile(Path::new(bitcoin_dir).join(".cookie")),
|
||||
rpc::Auth::CookieFile(bitcoin_dir.join(".cookie")),
|
||||
)?));
|
||||
let exit = Exit::new();
|
||||
|
||||
let parser = Parser::new(bitcoin_dir, rpc);
|
||||
let parser = Parser::new(bitcoin_dir.to_owned(), rpc);
|
||||
|
||||
let outputs_dir = Path::new("../../_outputs");
|
||||
|
||||
let mut indexer = Indexer::new(&outputs_dir.join("indexed"))?;
|
||||
let mut indexer = Indexer::new(outputs_dir.join("indexed"))?;
|
||||
indexer.import_stores()?;
|
||||
indexer.import_vecs()?;
|
||||
|
||||
let mut computer = Computer::new(&outputs_dir.join("computed"));
|
||||
let mut computer = Computer::new(outputs_dir.join("computed"));
|
||||
computer.import_stores()?;
|
||||
computer.import_vecs()?;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![doc = "\n## Example\n\n```rust"]
|
||||
#![doc = include_str!("main.rs")]
|
||||
#![doc = include_str!("../examples/main.rs")]
|
||||
#![doc = "```"]
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
@@ -23,9 +24,9 @@ pub struct Computer {
|
||||
}
|
||||
|
||||
impl Computer {
|
||||
pub fn new(computed_dir: &Path) -> Self {
|
||||
pub fn new(computed_dir: PathBuf) -> Self {
|
||||
Self {
|
||||
path: computed_dir.to_owned(),
|
||||
path: computed_dir,
|
||||
vecs: None,
|
||||
stores: None,
|
||||
}
|
||||
@@ -36,6 +37,8 @@ impl Computer {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Do NOT import multiple times are things will break !!!
|
||||
/// Clone struct instead
|
||||
pub fn import_stores(&mut self) -> color_eyre::Result<()> {
|
||||
self.stores = Some(Stores::import(&self.path.join("stores"))?);
|
||||
Ok(())
|
||||
@@ -43,7 +46,12 @@ impl Computer {
|
||||
}
|
||||
|
||||
impl Computer {
|
||||
pub fn compute(&mut self, indexer: &mut Indexer, starting_indexes: Indexes, exit: &Exit) -> color_eyre::Result<()> {
|
||||
pub fn compute(
|
||||
&mut self,
|
||||
indexer: &mut Indexer,
|
||||
starting_indexes: Indexes,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
info!("Computing...");
|
||||
|
||||
let height_count = indexer.vecs().height_to_size.len();
|
||||
|
||||
@@ -16,7 +16,7 @@ log = { workspace = true }
|
||||
rapidhash = "1.4.0"
|
||||
rlimit = "0.10.2"
|
||||
serde = { workspace = true }
|
||||
serde_bytes = "0.11.15"
|
||||
serde_bytes = "0.11.16"
|
||||
zerocopy = { workspace = true }
|
||||
|
||||
[package.metadata.cargo-machete]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![doc = include_str!("../README.md")]
|
||||
|
||||
mod error;
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
use bitcoin::ScriptBuf;
|
||||
use std::fmt;
|
||||
|
||||
use bitcoin::{
|
||||
Address, Network, ScriptBuf,
|
||||
hex::{Case, DisplayHex},
|
||||
opcodes,
|
||||
script::Builder,
|
||||
};
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use serde::Serialize;
|
||||
use serde::{Serialize, Serializer};
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::Error;
|
||||
@@ -89,64 +96,207 @@ impl TryFrom<(&ScriptBuf, Addresstype)> for Addressbytes {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2PK65AddressBytes(U8x65);
|
||||
|
||||
impl fmt::Display for P2PK65AddressBytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.to_hex_string(Case::Lower))
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2PK65AddressBytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.collect_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2PK65AddressBytes> for Addressbytes {
|
||||
fn from(value: P2PK65AddressBytes) -> Self {
|
||||
Self::P2PK65(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2PK33AddressBytes(U8x33);
|
||||
|
||||
impl fmt::Display for P2PK33AddressBytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.to_hex_string(Case::Lower))
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2PK33AddressBytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.collect_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2PK33AddressBytes> for Addressbytes {
|
||||
fn from(value: P2PK33AddressBytes) -> Self {
|
||||
Self::P2PK33(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2PKHAddressBytes(U8x20);
|
||||
|
||||
impl fmt::Display for P2PKHAddressBytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let script = Builder::new()
|
||||
.push_opcode(opcodes::all::OP_DUP)
|
||||
.push_opcode(opcodes::all::OP_HASH160)
|
||||
.push_slice(*self.0)
|
||||
.push_opcode(opcodes::all::OP_EQUALVERIFY)
|
||||
.push_opcode(opcodes::all::OP_CHECKSIG)
|
||||
.into_script();
|
||||
let address = Address::from_script(&script, Network::Bitcoin).unwrap();
|
||||
write!(f, "{}", address)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2PKHAddressBytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.collect_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2PKHAddressBytes> for Addressbytes {
|
||||
fn from(value: P2PKHAddressBytes) -> Self {
|
||||
Self::P2PKH(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2SHAddressBytes(U8x20);
|
||||
|
||||
impl fmt::Display for P2SHAddressBytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let script = Builder::new()
|
||||
.push_opcode(opcodes::all::OP_HASH160)
|
||||
.push_slice(*self.0)
|
||||
.push_opcode(opcodes::all::OP_EQUAL)
|
||||
.into_script();
|
||||
let address = Address::from_script(&script, Network::Bitcoin).unwrap();
|
||||
write!(f, "{}", address)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2SHAddressBytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.collect_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2SHAddressBytes> for Addressbytes {
|
||||
fn from(value: P2SHAddressBytes) -> Self {
|
||||
Self::P2SH(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2WPKHAddressBytes(U8x20);
|
||||
|
||||
impl fmt::Display for P2WPKHAddressBytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let script = Builder::new().push_int(0).push_slice(*self.0).into_script();
|
||||
let address = Address::from_script(&script, Network::Bitcoin).unwrap();
|
||||
write!(f, "{}", address)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2WPKHAddressBytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.collect_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2WPKHAddressBytes> for Addressbytes {
|
||||
fn from(value: P2WPKHAddressBytes) -> Self {
|
||||
Self::P2WPKH(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2WSHAddressBytes(U8x32);
|
||||
|
||||
impl fmt::Display for P2WSHAddressBytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let script = Builder::new().push_int(0).push_slice(*self.0).into_script();
|
||||
let address = Address::from_script(&script, Network::Bitcoin).unwrap();
|
||||
write!(f, "{}", address)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2WSHAddressBytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.collect_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2WSHAddressBytes> for Addressbytes {
|
||||
fn from(value: P2WSHAddressBytes) -> Self {
|
||||
Self::P2WSH(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct P2TRAddressBytes(U8x32);
|
||||
|
||||
impl fmt::Display for P2TRAddressBytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let script = Builder::new().push_int(1).push_slice(*self.0).into_script();
|
||||
let address = Address::from_script(&script, Network::Bitcoin).unwrap();
|
||||
write!(f, "{}", address)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for P2TRAddressBytes {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.collect_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P2TRAddressBytes> for Addressbytes {
|
||||
fn from(value: P2TRAddressBytes) -> Self {
|
||||
Self::P2TR(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes, Serialize)]
|
||||
pub struct P2PK65AddressBytes(U8x65);
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes, Serialize)]
|
||||
pub struct P2PK33AddressBytes(U8x33);
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes, Serialize)]
|
||||
pub struct P2PKHAddressBytes(U8x20);
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes, Serialize)]
|
||||
pub struct P2SHAddressBytes(U8x20);
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes, Serialize)]
|
||||
pub struct P2WPKHAddressBytes(U8x20);
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes, Serialize)]
|
||||
pub struct P2WSHAddressBytes(U8x32);
|
||||
|
||||
#[derive(Debug, Clone, Deref, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes, Serialize)]
|
||||
pub struct P2TRAddressBytes(U8x32);
|
||||
|
||||
#[derive(Debug, Clone, Deref, DerefMut, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes, Serialize)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Deref,
|
||||
DerefMut,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
FromBytes,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct U8x20([u8; 20]);
|
||||
impl From<&[u8]> for U8x20 {
|
||||
fn from(slice: &[u8]) -> Self {
|
||||
@@ -156,7 +306,19 @@ impl From<&[u8]> for U8x20 {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, DerefMut, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes, Serialize)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Deref,
|
||||
DerefMut,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
FromBytes,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct U8x32([u8; 32]);
|
||||
impl From<&[u8]> for U8x32 {
|
||||
fn from(slice: &[u8]) -> Self {
|
||||
@@ -166,7 +328,19 @@ impl From<&[u8]> for U8x32 {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, DerefMut, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes, Serialize)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Deref,
|
||||
DerefMut,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
FromBytes,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct U8x33(#[serde(with = "serde_bytes")] [u8; 33]);
|
||||
impl From<&[u8]> for U8x33 {
|
||||
fn from(slice: &[u8]) -> Self {
|
||||
@@ -176,7 +350,19 @@ impl From<&[u8]> for U8x33 {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, DerefMut, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes, Serialize)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Deref,
|
||||
DerefMut,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
FromBytes,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct U8x64(#[serde(with = "serde_bytes")] [u8; 64]);
|
||||
impl From<&[u8]> for U8x64 {
|
||||
fn from(slice: &[u8]) -> Self {
|
||||
@@ -186,7 +372,19 @@ impl From<&[u8]> for U8x64 {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deref, DerefMut, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes, Serialize)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Deref,
|
||||
DerefMut,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Immutable,
|
||||
IntoBytes,
|
||||
KnownLayout,
|
||||
FromBytes,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct U8x65(#[serde(with = "serde_bytes")] [u8; 65]);
|
||||
impl From<&[u8]> for U8x65 {
|
||||
fn from(slice: &[u8]) -> Self {
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
use std::mem;
|
||||
use std::{fmt, mem};
|
||||
|
||||
use bitcoin::hashes::Hash;
|
||||
use bitcoincore_rpc::{Client, RpcApi};
|
||||
use derive_deref::Deref;
|
||||
use serde::Serialize;
|
||||
use serde::{Serialize, Serializer};
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use super::Height;
|
||||
|
||||
#[derive(Debug, Deref, Clone, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes, Serialize)]
|
||||
#[derive(Debug, Deref, Clone, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct BlockHash([u8; 32]);
|
||||
|
||||
impl From<bitcoin::BlockHash> for BlockHash {
|
||||
@@ -22,9 +23,30 @@ impl From<BlockHash> for bitcoin::BlockHash {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&BlockHash> for bitcoin::BlockHash {
|
||||
fn from(value: &BlockHash) -> Self {
|
||||
bitcoin::BlockHash::from_slice(&value.0).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<(&Client, Height)> for BlockHash {
|
||||
type Error = bitcoincore_rpc::Error;
|
||||
fn try_from((rpc, height): (&Client, Height)) -> Result<Self, Self::Error> {
|
||||
Ok(Self::from(rpc.get_block_hash(u64::from(height))?))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for BlockHash {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", bitcoin::BlockHash::from(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for BlockHash {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use jiff::{Span, civil::Date as Date_, tz::TimeZone};
|
||||
use serde::Serialize;
|
||||
use serde::{Serialize, Serializer};
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use super::{Dateindex, Timestamp};
|
||||
|
||||
#[derive(
|
||||
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, FromBytes, Immutable, IntoBytes, KnownLayout, Serialize,
|
||||
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, FromBytes, Immutable, IntoBytes, KnownLayout,
|
||||
)]
|
||||
pub struct Date(u32);
|
||||
|
||||
@@ -52,7 +52,9 @@ impl From<Date> for Date_ {
|
||||
|
||||
impl From<Timestamp> for Date {
|
||||
fn from(value: Timestamp) -> Self {
|
||||
Self::from(Date_::from(jiff::Timestamp::from(value).to_zoned(TimeZone::UTC)))
|
||||
Self::from(Date_::from(
|
||||
jiff::Timestamp::from(value).to_zoned(TimeZone::UTC),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +70,20 @@ impl From<Dateindex> for Date {
|
||||
|
||||
impl std::fmt::Display for Date {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(&format!("{}-{}-{}", self.year(), self.month(), self.day()))
|
||||
f.write_str(&format!(
|
||||
"{}-{:0>2}-{:0>2}",
|
||||
self.year(),
|
||||
self.month(),
|
||||
self.day()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Date {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use std::mem;
|
||||
use std::{fmt, mem};
|
||||
|
||||
use bitcoin::hashes::Hash;
|
||||
use derive_deref::Deref;
|
||||
use serde::Serialize;
|
||||
use serde::{Serialize, Serializer};
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
#[derive(Debug, Deref, Clone, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes, Serialize)]
|
||||
#[derive(Debug, Deref, Clone, PartialEq, Eq, Immutable, IntoBytes, KnownLayout, FromBytes)]
|
||||
pub struct Txid([u8; 32]);
|
||||
|
||||
impl From<bitcoin::Txid> for Txid {
|
||||
@@ -18,3 +19,24 @@ impl From<Txid> for bitcoin::Txid {
|
||||
unsafe { mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Txid> for bitcoin::Txid {
|
||||
fn from(value: &Txid) -> Self {
|
||||
bitcoin::Txid::from_slice(&value.0).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Txid {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", bitcoin::Txid::from(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Txid {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![doc = include_str!("../README.md")]
|
||||
|
||||
use std::{
|
||||
|
||||
@@ -9,7 +9,11 @@ fn main() -> color_eyre::Result<()> {
|
||||
let mut fetcher = Fetcher::import(None)?;
|
||||
|
||||
dbg!(fetcher.get_date(Date::new(2025, 1, 1))?);
|
||||
dbg!(fetcher.get_height(885604_u32.into(), 1740683986.into(), Some(1740683000.into()))?);
|
||||
dbg!(fetcher.get_height(
|
||||
880_000_u32.into(),
|
||||
1740683986.into(),
|
||||
Some(1740683000.into())
|
||||
)?);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -30,12 +30,19 @@ impl Kibo {
|
||||
pub fn get_from_height(&mut self, height: Height) -> color_eyre::Result<OHLCCents> {
|
||||
#[allow(clippy::map_entry)]
|
||||
if !self.height_to_ohlc_vec.contains_key(&height)
|
||||
|| ((usize::from(height) + self.height_to_ohlc_vec.get(&height).unwrap().len()) <= usize::from(height))
|
||||
|| ((usize::from(height) + self.height_to_ohlc_vec.get(&height).unwrap().len())
|
||||
<= usize::from(height))
|
||||
{
|
||||
self.height_to_ohlc_vec
|
||||
.insert(height, Self::fetch_height_prices(height)?);
|
||||
self.height_to_ohlc_vec.insert(
|
||||
height,
|
||||
Self::fetch_height_prices(height).inspect_err(|e| {
|
||||
dbg!(e);
|
||||
})?,
|
||||
);
|
||||
}
|
||||
|
||||
dbg!(&self.height_to_ohlc_vec.keys());
|
||||
|
||||
self.height_to_ohlc_vec
|
||||
.get(&height)
|
||||
.unwrap()
|
||||
@@ -51,9 +58,9 @@ impl Kibo {
|
||||
|try_index| {
|
||||
let base_url = Self::get_base_url(try_index);
|
||||
|
||||
let body: Value = minreq::get(format!("{base_url}/height-to-price?chunk={}", height))
|
||||
.send()?
|
||||
.json()?;
|
||||
let url = format!("{base_url}/height-to-price?chunk={}", height);
|
||||
|
||||
let body: Value = minreq::get(url).send()?.json()?;
|
||||
|
||||
let vec = body
|
||||
.as_object()
|
||||
@@ -91,7 +98,8 @@ impl Kibo {
|
||||
.0
|
||||
< date
|
||||
{
|
||||
self.year_to_date_to_ohlc.insert(year, Self::fetch_date_prices(year)?);
|
||||
self.year_to_date_to_ohlc
|
||||
.insert(year, Self::fetch_date_prices(year)?);
|
||||
}
|
||||
|
||||
self.year_to_date_to_ohlc
|
||||
@@ -125,7 +133,8 @@ impl Kibo {
|
||||
.context("Expect to be an object")?
|
||||
.iter()
|
||||
.map(|(serialized_date, value)| -> color_eyre::Result<_> {
|
||||
let date = Date::from(jiff::civil::Date::from_str(serialized_date).unwrap());
|
||||
let date =
|
||||
Date::from(jiff::civil::Date::from_str(serialized_date).unwrap());
|
||||
Ok((date, Self::value_to_ohlc(value)?))
|
||||
})
|
||||
.collect::<Result<BTreeMap<_, _>, _>>()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::{thread::sleep, time::Duration};
|
||||
use std::{fmt::Debug, thread::sleep, time::Duration};
|
||||
|
||||
use log::info;
|
||||
|
||||
@@ -6,7 +6,10 @@ pub fn retry<T>(
|
||||
function: impl Fn(usize) -> color_eyre::Result<T>,
|
||||
sleep_in_s: u64,
|
||||
retries: usize,
|
||||
) -> color_eyre::Result<T> {
|
||||
) -> color_eyre::Result<T>
|
||||
where
|
||||
T: Debug,
|
||||
{
|
||||
let mut i = 0;
|
||||
|
||||
loop {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![doc = "\n## Example\n\n```rust"]
|
||||
#![doc = include_str!("main.rs")]
|
||||
#![doc = include_str!("../examples/main.rs")]
|
||||
#![doc = "```"]
|
||||
|
||||
use std::{collections::BTreeMap, fs, path::Path};
|
||||
@@ -93,9 +94,10 @@ impl Fetcher {
|
||||
previous_timestamp: Option<Timestamp>,
|
||||
name: &str,
|
||||
) -> color_eyre::Result<OHLCCents> {
|
||||
let previous_ohlc = previous_timestamp.map_or(Some(OHLCCents::default()), |previous_timestamp| {
|
||||
tree.get(&previous_timestamp).cloned()
|
||||
});
|
||||
let previous_ohlc = previous_timestamp
|
||||
.map_or(Some(OHLCCents::default()), |previous_timestamp| {
|
||||
tree.get(&previous_timestamp).cloned()
|
||||
});
|
||||
|
||||
let last_ohlc = tree.get(×tamp);
|
||||
|
||||
|
||||
@@ -16,13 +16,13 @@ fn main() -> color_eyre::Result<()> {
|
||||
let bitcoin_dir = Path::new("../../../bitcoin");
|
||||
let rpc = Box::leak(Box::new(rpc::Client::new(
|
||||
"http://localhost:8332",
|
||||
rpc::Auth::CookieFile(Path::new(bitcoin_dir).join(".cookie")),
|
||||
rpc::Auth::CookieFile(bitcoin_dir.join(".cookie")),
|
||||
)?));
|
||||
let exit = Exit::new();
|
||||
|
||||
let parser = Parser::new(bitcoin_dir, rpc);
|
||||
let parser = Parser::new(bitcoin_dir.to_owned(), rpc);
|
||||
|
||||
let mut indexer = Indexer::new(Path::new("../../_outputs/indexed"))?;
|
||||
let mut indexer = Indexer::new(Path::new("../../_outputs/indexed").to_owned())?;
|
||||
indexer.import_stores()?;
|
||||
indexer.import_vecs()?;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![doc = "\n## Example\n\n```rust"]
|
||||
#![doc = include_str!("main.rs")]
|
||||
#![doc = include_str!("../examples/main.rs")]
|
||||
#![doc = "```"]
|
||||
|
||||
use std::{
|
||||
@@ -11,8 +12,8 @@ use std::{
|
||||
};
|
||||
|
||||
use brk_core::{
|
||||
AddressHash, Addressbytes, Addressindex, Addresstype, BlockHash, BlockHashPrefix, Height, Sats, Timestamp, Txid,
|
||||
TxidPrefix, Txindex, Txinindex, Txoutindex, Vin, Vout, setrlimit,
|
||||
AddressHash, Addressbytes, Addressindex, Addresstype, BlockHash, BlockHashPrefix, Height, Sats,
|
||||
Timestamp, Txid, TxidPrefix, Txindex, Txinindex, Txoutindex, Vin, Vout, setrlimit,
|
||||
};
|
||||
pub use brk_parser::*;
|
||||
|
||||
@@ -39,10 +40,10 @@ pub struct Indexer {
|
||||
}
|
||||
|
||||
impl Indexer {
|
||||
pub fn new(indexes_dir: &Path) -> color_eyre::Result<Self> {
|
||||
pub fn new(indexes_dir: PathBuf) -> color_eyre::Result<Self> {
|
||||
setrlimit()?;
|
||||
Ok(Self {
|
||||
path: indexes_dir.to_owned(),
|
||||
path: indexes_dir,
|
||||
vecs: None,
|
||||
stores: None,
|
||||
})
|
||||
@@ -53,27 +54,40 @@ impl Indexer {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Do NOT import multiple times are things will break !!!
|
||||
pub fn import_stores(&mut self) -> color_eyre::Result<()> {
|
||||
self.stores = Some(Stores::import(&self.path.join("stores"))?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn index(&mut self, parser: &Parser, rpc: &'static rpc::Client, exit: &Exit) -> color_eyre::Result<Indexes> {
|
||||
pub fn index(
|
||||
&mut self,
|
||||
parser: &Parser,
|
||||
rpc: &'static rpc::Client,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<Indexes> {
|
||||
let check_collisions = true;
|
||||
|
||||
let starting_indexes = Indexes::try_from((self.vecs.as_mut().unwrap(), self.stores.as_ref().unwrap(), rpc))
|
||||
.unwrap_or_else(|_| {
|
||||
let indexes = Indexes::default();
|
||||
indexes.push_if_needed(self.vecs.as_mut().unwrap()).unwrap();
|
||||
indexes
|
||||
});
|
||||
let starting_indexes = Indexes::try_from((
|
||||
self.vecs.as_mut().unwrap(),
|
||||
self.stores.as_ref().unwrap(),
|
||||
rpc,
|
||||
))
|
||||
.unwrap_or_else(|_| {
|
||||
let indexes = Indexes::default();
|
||||
indexes.push_if_needed(self.vecs.as_mut().unwrap()).unwrap();
|
||||
indexes
|
||||
});
|
||||
|
||||
exit.block();
|
||||
self.stores
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.rollback_if_needed(self.vecs.as_ref().unwrap(), &starting_indexes)?;
|
||||
self.vecs.as_mut().unwrap().rollback_if_needed(&starting_indexes)?;
|
||||
self.vecs
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.rollback_if_needed(&starting_indexes)?;
|
||||
exit.release();
|
||||
|
||||
let vecs = self.vecs.as_mut().unwrap();
|
||||
@@ -84,25 +98,31 @@ impl Indexer {
|
||||
let start = Some(idxs.height);
|
||||
let end = None; //Some(Height::new(400_000));
|
||||
|
||||
if starting_indexes.height > Height::try_from(rpc)? || end.is_some_and(|end| starting_indexes.height > end) {
|
||||
if starting_indexes.height > Height::try_from(rpc)?
|
||||
|| end.is_some_and(|end| starting_indexes.height > end)
|
||||
{
|
||||
return Ok(starting_indexes);
|
||||
}
|
||||
|
||||
info!("Started indexing...");
|
||||
|
||||
let export_if_needed =
|
||||
|stores: &mut Stores, vecs: &mut Vecs, height: Height, rem: bool, exit: &Exit| -> color_eyre::Result<()> {
|
||||
if height == 0 || (height % SNAPSHOT_BLOCK_RANGE != 0) != rem || exit.triggered() {
|
||||
return Ok(());
|
||||
}
|
||||
let export_if_needed = |stores: &mut Stores,
|
||||
vecs: &mut Vecs,
|
||||
height: Height,
|
||||
rem: bool,
|
||||
exit: &Exit|
|
||||
-> color_eyre::Result<()> {
|
||||
if height == 0 || (height % SNAPSHOT_BLOCK_RANGE != 0) != rem || exit.triggered() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
info!("Exporting...");
|
||||
exit.block();
|
||||
stores.commit(height)?;
|
||||
vecs.flush(height)?;
|
||||
exit.release();
|
||||
Ok(())
|
||||
};
|
||||
info!("Exporting...");
|
||||
exit.block();
|
||||
stores.commit(height)?;
|
||||
vecs.flush(height)?;
|
||||
exit.release();
|
||||
Ok(())
|
||||
};
|
||||
|
||||
parser.parse(start, None).iter().try_for_each(
|
||||
|(height, block, blockhash)| -> color_eyre::Result<()> {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![doc = "\n## Example\n\n```rust"]
|
||||
#![doc = include_str!("main.rs")]
|
||||
#![doc = include_str!("../examples/main.rs")]
|
||||
#![doc = "```"]
|
||||
|
||||
use std::{
|
||||
@@ -18,7 +19,11 @@ use jiff::{Timestamp, tz};
|
||||
pub fn init(path: Option<&Path>) {
|
||||
let file = path.map(|path| {
|
||||
let _ = fs::remove_file(path);
|
||||
OpenOptions::new().create(true).append(true).open(path).unwrap()
|
||||
OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open(path)
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
Builder::from_env(Env::default().default_filter_or("info,fjall=off,lsm_tree=off"))
|
||||
@@ -34,7 +39,14 @@ pub fn init(path: Option<&Path>) {
|
||||
let args = record.args();
|
||||
|
||||
if let Some(file) = file.as_ref() {
|
||||
let _ = write(file.try_clone().unwrap(), &date_time, target, &level, dash, args);
|
||||
let _ = write(
|
||||
file.try_clone().unwrap(),
|
||||
&date_time,
|
||||
target,
|
||||
&level,
|
||||
dash,
|
||||
args,
|
||||
);
|
||||
}
|
||||
|
||||
let colored_date_time = date_time.bright_black();
|
||||
@@ -48,7 +60,14 @@ pub fn init(path: Option<&Path>) {
|
||||
};
|
||||
let colored_dash = dash.bright_black();
|
||||
|
||||
write(buf, colored_date_time, target, colored_level, colored_dash, args)
|
||||
write(
|
||||
buf,
|
||||
colored_date_time,
|
||||
target,
|
||||
colored_level,
|
||||
colored_dash,
|
||||
args,
|
||||
)
|
||||
})
|
||||
.init();
|
||||
}
|
||||
|
||||
58
crates/brk_parser/examples/main.rs
Normal file
58
crates/brk_parser/examples/main.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
use std::path::Path;
|
||||
|
||||
use bitcoincore_rpc::{Auth, Client};
|
||||
use brk_core::Height;
|
||||
use brk_parser::Parser;
|
||||
|
||||
fn main() {
|
||||
let i = std::time::Instant::now();
|
||||
|
||||
let bitcoin_dir = Path::new("../../../bitcoin");
|
||||
let rpc = Box::leak(Box::new(
|
||||
Client::new(
|
||||
"http://localhost:8332",
|
||||
Auth::CookieFile(bitcoin_dir.join(".cookie")),
|
||||
)
|
||||
.unwrap(),
|
||||
));
|
||||
|
||||
// let start = None;
|
||||
// let end = None;
|
||||
|
||||
let parser = Parser::new(bitcoin_dir.to_owned(), rpc);
|
||||
|
||||
// parser
|
||||
// .parse(start, end)
|
||||
// .iter()
|
||||
// .for_each(|(height, _block, hash)| {
|
||||
// println!("{height}: {hash}");
|
||||
// });
|
||||
|
||||
println!(
|
||||
"{}",
|
||||
parser
|
||||
.get(Height::new(0))
|
||||
.txdata
|
||||
.first()
|
||||
.unwrap()
|
||||
.output
|
||||
.first()
|
||||
.unwrap()
|
||||
.script_pubkey
|
||||
);
|
||||
|
||||
println!(
|
||||
"{}",
|
||||
parser
|
||||
.get(Height::new(840_000))
|
||||
.txdata
|
||||
.first()
|
||||
.unwrap()
|
||||
.output
|
||||
.first()
|
||||
.unwrap()
|
||||
.value
|
||||
);
|
||||
|
||||
dbg!(i.elapsed());
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![doc = "\n## Example\n\n```rust"]
|
||||
#![doc = include_str!("main.rs")]
|
||||
#![doc = include_str!("../examples/main.rs")]
|
||||
#![doc = "```"]
|
||||
|
||||
use std::{
|
||||
@@ -8,7 +9,7 @@ use std::{
|
||||
collections::BTreeMap,
|
||||
fs::{self},
|
||||
ops::ControlFlow,
|
||||
path::{Path, PathBuf},
|
||||
path::PathBuf,
|
||||
thread,
|
||||
};
|
||||
|
||||
@@ -52,15 +53,16 @@ pub struct Parser {
|
||||
}
|
||||
|
||||
impl Parser {
|
||||
pub fn new(bitcoin_dir: &Path, rpc: &'static bitcoincore_rpc::Client) -> Self {
|
||||
Self {
|
||||
bitcoin_dir: bitcoin_dir.to_owned(),
|
||||
rpc,
|
||||
}
|
||||
pub fn new(bitcoin_dir: PathBuf, rpc: &'static bitcoincore_rpc::Client) -> Self {
|
||||
Self { bitcoin_dir, rpc }
|
||||
}
|
||||
|
||||
pub fn get(&self, height: Height) -> Block {
|
||||
self.parse(Some(height), Some(height)).iter().next().unwrap().1
|
||||
self.parse(Some(height), Some(height))
|
||||
.iter()
|
||||
.next()
|
||||
.unwrap()
|
||||
.1
|
||||
}
|
||||
|
||||
///
|
||||
@@ -68,7 +70,11 @@ impl Parser {
|
||||
///
|
||||
/// For an example checkout `./main.rs`
|
||||
///
|
||||
pub fn parse(&self, start: Option<Height>, end: Option<Height>) -> Receiver<(Height, Block, BlockHash)> {
|
||||
pub fn parse(
|
||||
&self,
|
||||
start: Option<Height>,
|
||||
end: Option<Height>,
|
||||
) -> Receiver<(Height, Block, BlockHash)> {
|
||||
let bitcoin_dir = self.bitcoin_dir.as_path();
|
||||
let rpc = self.rpc;
|
||||
|
||||
@@ -119,9 +125,12 @@ impl Parser {
|
||||
}
|
||||
}
|
||||
|
||||
let len =
|
||||
u32::from_le_bytes(xor_i.bytes(&mut blk_bytes[i..(i + 4)], &xor_bytes).try_into().unwrap())
|
||||
as usize;
|
||||
let len = u32::from_le_bytes(
|
||||
xor_i
|
||||
.bytes(&mut blk_bytes[i..(i + 4)], &xor_bytes)
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
) as usize;
|
||||
i += 4;
|
||||
|
||||
let block_bytes = (blk_bytes[i..(i + len)]).to_vec();
|
||||
@@ -152,18 +161,19 @@ impl Parser {
|
||||
BlockState::decode(block_state, xor_i, &xor_bytes);
|
||||
});
|
||||
|
||||
bulk.drain(..).try_for_each(|(blk_metadata, block_state, _)| {
|
||||
let block = match block_state {
|
||||
BlockState::Decoded(block) => block,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
bulk.drain(..)
|
||||
.try_for_each(|(blk_metadata, block_state, _)| {
|
||||
let block = match block_state {
|
||||
BlockState::Decoded(block) => block,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
if send_block.send((blk_metadata, block)).is_err() {
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
if send_block.send((blk_metadata, block)).is_err() {
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
|
||||
ControlFlow::Continue(())
|
||||
})
|
||||
ControlFlow::Continue(())
|
||||
})
|
||||
};
|
||||
|
||||
recv_bytes.iter().try_for_each(|tuple| {
|
||||
@@ -230,7 +240,9 @@ impl Parser {
|
||||
let mut opt = if current_height == height {
|
||||
Some((block, hash))
|
||||
} else {
|
||||
if start.is_none_or(|start| start <= height) && end.is_none_or(|end| end >= height) {
|
||||
if start.is_none_or(|start| start <= height)
|
||||
&& end.is_none_or(|end| end >= height)
|
||||
{
|
||||
future_blocks.insert(height, (block, hash));
|
||||
}
|
||||
None
|
||||
@@ -247,7 +259,9 @@ impl Parser {
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
|
||||
send_height_block_hash.send((current_height, block, hash)).unwrap();
|
||||
send_height_block_hash
|
||||
.send((current_height, block, hash))
|
||||
.unwrap();
|
||||
|
||||
if end.is_some_and(|end| end == current_height) {
|
||||
return ControlFlow::Break(());
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
use std::path::Path;
|
||||
|
||||
use bitcoincore_rpc::{Auth, Client};
|
||||
use brk_core::Height;
|
||||
use brk_parser::Parser;
|
||||
|
||||
fn main() {
|
||||
let i = std::time::Instant::now();
|
||||
|
||||
let bitcoin_dir = Path::new("../../../bitcoin");
|
||||
let rpc = Box::leak(Box::new(
|
||||
Client::new(
|
||||
"http://localhost:8332",
|
||||
Auth::CookieFile(Path::new(bitcoin_dir).join(".cookie")),
|
||||
)
|
||||
.unwrap(),
|
||||
));
|
||||
|
||||
let start = None;
|
||||
let end = None;
|
||||
|
||||
let parser = Parser::new(bitcoin_dir, rpc);
|
||||
|
||||
parser.parse(start, end).iter().for_each(|(height, _block, hash)| {
|
||||
println!("{height}: {hash}");
|
||||
});
|
||||
|
||||
parser.get(Height::new(0));
|
||||
parser.get(Height::new(840_000));
|
||||
|
||||
dbg!(i.elapsed());
|
||||
}
|
||||
@@ -9,10 +9,10 @@ pub fn main() -> color_eyre::Result<()> {
|
||||
|
||||
let outputs_dir = Path::new("../../_outputs");
|
||||
|
||||
let mut indexer = Indexer::new(&outputs_dir.join("indexed"))?;
|
||||
let mut indexer = Indexer::new(outputs_dir.join("indexed"))?;
|
||||
indexer.import_vecs()?;
|
||||
|
||||
let mut computer = Computer::new(&outputs_dir.join("computed"));
|
||||
let mut computer = Computer::new(outputs_dir.join("computed"));
|
||||
computer.import_vecs()?;
|
||||
|
||||
let query = Query::build(&indexer, &computer);
|
||||
@@ -38,7 +38,8 @@ impl Index {
|
||||
]
|
||||
}
|
||||
|
||||
pub fn self_to_ids(&self) -> &[&str] {
|
||||
pub fn possible_values(&self) -> &[&str] {
|
||||
// Always have the "correct" id at the end
|
||||
match self {
|
||||
Self::Dateindex => &["d", "date", "dateindex"],
|
||||
Self::Height => &["h", "height"],
|
||||
@@ -56,10 +57,10 @@ impl Index {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn possible_values() -> Vec<String> {
|
||||
pub fn all_possible_values() -> Vec<String> {
|
||||
Self::all()
|
||||
.iter()
|
||||
.flat_map(|i| i.self_to_ids().iter().map(|s| s.to_string()))
|
||||
.flat_map(|i| i.possible_values().iter().map(|s| s.to_string()))
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
@@ -68,19 +69,19 @@ impl TryFrom<&str> for Index {
|
||||
type Error = color_eyre::Report;
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
Ok(match value {
|
||||
v if (Self::Dateindex).self_to_ids().contains(&v) => Self::Dateindex,
|
||||
v if (Self::Height).self_to_ids().contains(&v) => Self::Height,
|
||||
v if (Self::Txindex).self_to_ids().contains(&v) => Self::Txindex,
|
||||
v if (Self::Txinindex).self_to_ids().contains(&v) => Self::Txinindex,
|
||||
v if (Self::Txoutindex).self_to_ids().contains(&v) => Self::Txoutindex,
|
||||
v if (Self::Addressindex).self_to_ids().contains(&v) => Self::Addressindex,
|
||||
v if (Self::P2PK33index).self_to_ids().contains(&v) => Self::P2PK33index,
|
||||
v if (Self::P2PK65index).self_to_ids().contains(&v) => Self::P2PK65index,
|
||||
v if (Self::P2PKHindex).self_to_ids().contains(&v) => Self::P2PKHindex,
|
||||
v if (Self::P2SHindex).self_to_ids().contains(&v) => Self::P2SHindex,
|
||||
v if (Self::P2TRindex).self_to_ids().contains(&v) => Self::P2TRindex,
|
||||
v if (Self::P2WPKHindex).self_to_ids().contains(&v) => Self::P2WPKHindex,
|
||||
v if (Self::P2WSHindex).self_to_ids().contains(&v) => Self::P2WSHindex,
|
||||
v if (Self::Dateindex).possible_values().contains(&v) => Self::Dateindex,
|
||||
v if (Self::Height).possible_values().contains(&v) => Self::Height,
|
||||
v if (Self::Txindex).possible_values().contains(&v) => Self::Txindex,
|
||||
v if (Self::Txinindex).possible_values().contains(&v) => Self::Txinindex,
|
||||
v if (Self::Txoutindex).possible_values().contains(&v) => Self::Txoutindex,
|
||||
v if (Self::Addressindex).possible_values().contains(&v) => Self::Addressindex,
|
||||
v if (Self::P2PK33index).possible_values().contains(&v) => Self::P2PK33index,
|
||||
v if (Self::P2PK65index).possible_values().contains(&v) => Self::P2PK65index,
|
||||
v if (Self::P2PKHindex).possible_values().contains(&v) => Self::P2PKHindex,
|
||||
v if (Self::P2SHindex).possible_values().contains(&v) => Self::P2SHindex,
|
||||
v if (Self::P2TRindex).possible_values().contains(&v) => Self::P2TRindex,
|
||||
v if (Self::P2WPKHindex).possible_values().contains(&v) => Self::P2WPKHindex,
|
||||
v if (Self::P2WSHindex).possible_values().contains(&v) => Self::P2WSHindex,
|
||||
_ => return Err(eyre!("Bad index")),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![doc = "\n## Example\n\n```rust"]
|
||||
#![doc = include_str!("main.rs")]
|
||||
#![doc = include_str!("../examples/main.rs")]
|
||||
#![doc = "```"]
|
||||
|
||||
use brk_computer::Computer;
|
||||
@@ -61,10 +62,15 @@ impl<'a> Query<'a> {
|
||||
let tuples = ids
|
||||
.iter()
|
||||
.map(|s| {
|
||||
(
|
||||
s.to_owned(),
|
||||
self.vecid_to_index_to_vec.get(&s.to_lowercase().replace("_", "-")),
|
||||
)
|
||||
let mut id = s.to_lowercase().replace("_", "-");
|
||||
let mut res = self.vecid_to_index_to_vec.get(&id);
|
||||
if res.is_none() {
|
||||
if let Ok(index) = Index::try_from(id.as_str()) {
|
||||
id = index.possible_values().last().unwrap().to_string();
|
||||
res = self.vecid_to_index_to_vec.get(&id)
|
||||
}
|
||||
}
|
||||
(id, res)
|
||||
})
|
||||
.filter(|(_, opt)| opt.is_some())
|
||||
.map(|(id, vec)| (id, vec.unwrap()))
|
||||
@@ -77,7 +83,9 @@ impl<'a> Query<'a> {
|
||||
let mut values = tuples
|
||||
.iter()
|
||||
.flat_map(|(_, i_to_v)| i_to_v.get(&index))
|
||||
.map(|vec| -> brk_vec::Result<Vec<serde_json::Value>> { vec.collect_range_values(from, to) })
|
||||
.map(|vec| -> brk_vec::Result<Vec<serde_json::Value>> {
|
||||
vec.collect_range_values(from, to)
|
||||
})
|
||||
.collect::<brk_vec::Result<Vec<_>>>()?;
|
||||
|
||||
if values.is_empty() {
|
||||
@@ -88,7 +96,11 @@ impl<'a> Query<'a> {
|
||||
|
||||
Ok(match format {
|
||||
Some(Format::CSV) | Some(Format::TSV) => {
|
||||
let delimiter = if format == Some(Format::CSV) { ',' } else { '\t' };
|
||||
let delimiter = if format == Some(Format::CSV) {
|
||||
','
|
||||
} else {
|
||||
'\t'
|
||||
};
|
||||
|
||||
let mut text = tuples
|
||||
.into_iter()
|
||||
@@ -120,7 +132,8 @@ impl<'a> Query<'a> {
|
||||
}
|
||||
}
|
||||
Some(Format::MD) => {
|
||||
let mut table = values.to_table(ids.iter().map(|s| s.to_string()).collect::<Vec<_>>());
|
||||
let mut table =
|
||||
values.to_table(tuples.iter().map(|(s, _)| s.to_owned()).collect::<Vec<_>>());
|
||||
|
||||
table.with(Style::markdown());
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::{Format, Index};
|
||||
|
||||
#[derive(Debug, Deserialize, Parser)]
|
||||
pub struct Params {
|
||||
#[clap(short, long, value_parser = PossibleValuesParser::new(Index::possible_values()))]
|
||||
#[clap(short, long, value_parser = PossibleValuesParser::new(Index::all_possible_values()))]
|
||||
/// Index of the values requested
|
||||
pub index: String,
|
||||
#[clap(short, long, value_delimiter = ' ', num_args = 1..)]
|
||||
|
||||
@@ -18,7 +18,7 @@ brk_vec = { workspace = true }
|
||||
color-eyre = { workspace = true }
|
||||
jiff = { workspace = true }
|
||||
log = { workspace = true }
|
||||
oxc = { version = "0.53.0", features = ["codegen", "minifier"] }
|
||||
oxc = { version = "0.54.0", features = ["codegen", "minifier"] }
|
||||
serde_json = { workspace = true }
|
||||
tokio = { version = "1.43.0", features = ["full"] }
|
||||
tower-http = { version = "0.6.2", features = ["compression-full"] }
|
||||
|
||||
@@ -17,19 +17,19 @@ pub fn main() -> color_eyre::Result<()> {
|
||||
let bitcoin_dir = Path::new("../../../bitcoin");
|
||||
let rpc = Box::leak(Box::new(rpc::Client::new(
|
||||
"http://localhost:8332",
|
||||
rpc::Auth::CookieFile(Path::new(bitcoin_dir).join(".cookie")),
|
||||
rpc::Auth::CookieFile(bitcoin_dir.join(".cookie")),
|
||||
)?));
|
||||
let exit = Exit::new();
|
||||
|
||||
let parser = Parser::new(bitcoin_dir, rpc);
|
||||
let parser = Parser::new(bitcoin_dir.to_owned(), rpc);
|
||||
|
||||
let outputs_dir = Path::new("../../_outputs");
|
||||
|
||||
let mut indexer = Indexer::new(&outputs_dir.join("indexed"))?;
|
||||
let mut indexer = Indexer::new(outputs_dir.join("indexed"))?;
|
||||
indexer.import_stores()?;
|
||||
indexer.import_vecs()?;
|
||||
|
||||
let mut computer = Computer::new(&outputs_dir.join("computed"));
|
||||
let mut computer = Computer::new(outputs_dir.join("computed"));
|
||||
computer.import_stores()?;
|
||||
computer.import_vecs()?;
|
||||
|
||||
@@ -41,7 +41,9 @@ pub fn main() -> color_eyre::Result<()> {
|
||||
let served_computer = computer.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
brk_server::main(served_indexer, served_computer).await.unwrap();
|
||||
brk_server::main(served_indexer, served_computer)
|
||||
.await
|
||||
.unwrap();
|
||||
});
|
||||
|
||||
loop {
|
||||
@@ -1,6 +1,7 @@
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![doc = "\n## Example\n\n```rust"]
|
||||
#![doc = include_str!("main.rs")]
|
||||
#![doc = include_str!("../examples/main.rs")]
|
||||
#![doc = "```"]
|
||||
|
||||
use std::time::Instant;
|
||||
@@ -37,7 +38,11 @@ pub async fn main(indexer: Indexer, computer: Computer) -> color_eyre::Result<()
|
||||
|
||||
let state = AppState { query };
|
||||
|
||||
let compression_layer = CompressionLayer::new().br(true).deflate(true).gzip(true).zstd(true);
|
||||
let compression_layer = CompressionLayer::new()
|
||||
.br(true)
|
||||
.deflate(true)
|
||||
.gzip(true)
|
||||
.zstd(true);
|
||||
|
||||
let router = Router::new()
|
||||
.add_api_routes()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![doc = "\n## Example\n\n```rust"]
|
||||
#![doc = include_str!("main.rs")]
|
||||
#![doc = include_str!("../examples/main.rs")]
|
||||
#![doc = "```"]
|
||||
|
||||
use std::{
|
||||
@@ -81,7 +82,11 @@ where
|
||||
pub fn forced_import(path: &Path, version: Version) -> Result<Self> {
|
||||
let res = Self::import(path, version);
|
||||
match res {
|
||||
Err(Error::WrongEndian) | Err(Error::DifferentVersion { found: _, expected: _ }) => {
|
||||
Err(Error::WrongEndian)
|
||||
| Err(Error::DifferentVersion {
|
||||
found: _,
|
||||
expected: _,
|
||||
}) => {
|
||||
fs::remove_dir_all(path)?;
|
||||
Self::import(path, version)
|
||||
}
|
||||
@@ -243,7 +248,9 @@ where
|
||||
return Ok(Some(Value::Ref(T::try_ref_from_bytes(slice)?)));
|
||||
}
|
||||
|
||||
Ok(self.open_then_read_(index).map_or(None, |v| Some(Value::Owned(v))))
|
||||
Ok(self
|
||||
.open_then_read_(index)
|
||||
.map_or(None, |v| Some(Value::Owned(v))))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -289,7 +296,10 @@ where
|
||||
let disk_len = I::from(Self::read_disk_len_(&file)?);
|
||||
let pushed_len = I::from(self.pushed_len());
|
||||
|
||||
Self::seek_(&mut file, Self::index_to_byte_index(Self::i_to_usize(index)?))?;
|
||||
Self::seek_(
|
||||
&mut file,
|
||||
Self::index_to_byte_index(Self::i_to_usize(index)?),
|
||||
)?;
|
||||
|
||||
let mut buf = Self::create_buffer();
|
||||
|
||||
@@ -301,7 +311,10 @@ where
|
||||
let disk_len = Self::i_to_usize(disk_len)?;
|
||||
let mut i = I::default();
|
||||
while i < pushed_len {
|
||||
f((i + disk_len, self.pushed.get(Self::i_to_usize(i)?).as_ref().unwrap()))?;
|
||||
f((
|
||||
i + disk_len,
|
||||
self.pushed.get(Self::i_to_usize(i)?).as_ref().unwrap(),
|
||||
))?;
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
@@ -525,7 +538,12 @@ where
|
||||
}
|
||||
|
||||
pub fn file_name(&self) -> String {
|
||||
self.path().file_name().unwrap().to_str().unwrap().to_owned()
|
||||
self.path()
|
||||
.file_name()
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -567,10 +585,14 @@ where
|
||||
A: StoredType,
|
||||
F: Fn(&A, I) -> T,
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(Version::from(0) + self.version + other.version)?;
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::from(0) + self.version + other.version,
|
||||
)?;
|
||||
|
||||
let index = max_from.min(I::from(self.len()));
|
||||
other.iter_from(index, |(i, a)| self.push_and_flush_if_needed(i, t(a, i), exit))?;
|
||||
other.iter_from(index, |(i, a)| {
|
||||
self.push_and_flush_if_needed(i, t(a, i), exit)
|
||||
})?;
|
||||
|
||||
Ok(self.safe_flush(exit)?)
|
||||
}
|
||||
@@ -585,7 +607,9 @@ where
|
||||
I: StoredType + StoredIndex,
|
||||
T: StoredIndex,
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(Version::from(0) + self.version + other.version)?;
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::from(0) + self.version + other.version,
|
||||
)?;
|
||||
|
||||
let index = max_from.min(self.read_last()?.cloned().unwrap_or_default());
|
||||
other.iter_from(index, |(v, i)| self.push_and_flush_if_needed(*i, v, exit))?;
|
||||
@@ -612,7 +636,8 @@ where
|
||||
first_indexes.iter_from(index, |(value, first_index)| {
|
||||
let first_index = Self::i_to_usize(*first_index)?;
|
||||
let last_index = Self::i_to_usize(*last_indexes.read(value)?.unwrap())?;
|
||||
(first_index..last_index).try_for_each(|index| self.push_and_flush_if_needed(I::from(index), value, exit))
|
||||
(first_index..last_index)
|
||||
.try_for_each(|index| self.push_and_flush_if_needed(I::from(index), value, exit))
|
||||
})?;
|
||||
|
||||
Ok(self.safe_flush(exit)?)
|
||||
@@ -628,7 +653,9 @@ where
|
||||
where
|
||||
T: Copy + From<usize> + Sub<T, Output = T> + StoredIndex,
|
||||
{
|
||||
self.validate_computed_version_or_reset_file(Version::from(0) + self.version + first_indexes.version)?;
|
||||
self.validate_computed_version_or_reset_file(
|
||||
Version::from(0) + self.version + first_indexes.version,
|
||||
)?;
|
||||
|
||||
let index = max_from.min(I::from(self.len()));
|
||||
let one = T::from(1);
|
||||
@@ -691,7 +718,11 @@ where
|
||||
|
||||
let index = max_from.min(I::from(self.len()));
|
||||
self_to_other.iter_from(index, |(i, other)| {
|
||||
self.push_and_flush_if_needed(i, T::from(other_to_self.read(*other)?.unwrap() == &i), exit)
|
||||
self.push_and_flush_if_needed(
|
||||
i,
|
||||
T::from(other_to_self.read(*other)?.unwrap() == &i),
|
||||
exit,
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(self.safe_flush(exit)?)
|
||||
|
||||
Reference in New Issue
Block a user