mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-20 11:44:20 -07:00
indexer: moved height to iterator
This commit is contained in:
+7
-1
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "biter"
|
||||
name = "biterator"
|
||||
description = "A very fast Bitcoin block iterator built on top of bitcoin-rust"
|
||||
version = "0.2.3"
|
||||
repository = "https://github.com/kibo-money/kibo/tree/main/src/crates/biter"
|
||||
@@ -8,11 +8,17 @@ categories = ["cryptography::cryptocurrencies", "encoding"]
|
||||
edition = { workspace = true }
|
||||
license = { workspace = true }
|
||||
|
||||
[features]
|
||||
fjall = ["dep:fjall"]
|
||||
zerocopy = ["dep:zerocopy"]
|
||||
|
||||
[dependencies]
|
||||
bitcoin = { workspace = true }
|
||||
rayon = { workspace = true }
|
||||
crossbeam = { version = "0.8.4", features = ["crossbeam-channel"] }
|
||||
fjall = { workspace = true, optional = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
derive_deref = { workspace = true }
|
||||
bitcoincore-rpc = "0.19.0"
|
||||
zerocopy = { workspace = true, optional = true }
|
||||
|
||||
@@ -6,7 +6,7 @@ use std::{
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use crate::{blk_recap::BlkRecap, BlkIndexToBlkPath, BlkMetadataAndBlock};
|
||||
use crate::{blk_recap::BlkRecap, BlkIndexToBlkPath, BlkMetadataAndBlock, Height};
|
||||
|
||||
const TARGET_BLOCKS_PER_MONTH: usize = 144 * 30;
|
||||
|
||||
@@ -14,7 +14,7 @@ const TARGET_BLOCKS_PER_MONTH: usize = 144 * 30;
|
||||
pub struct BlkIndexToBlkRecap {
|
||||
path: PathBuf,
|
||||
tree: BTreeMap<usize, BlkRecap>,
|
||||
last_safe_height: Option<usize>,
|
||||
last_safe_height: Option<Height>,
|
||||
}
|
||||
|
||||
impl BlkIndexToBlkRecap {
|
||||
@@ -66,7 +66,7 @@ impl BlkIndexToBlkRecap {
|
||||
self.last_safe_height = self.tree.values().map(|recap| recap.height()).max();
|
||||
}
|
||||
|
||||
pub fn get_start_recap(&mut self, start: Option<usize>) -> Option<(usize, BlkRecap)> {
|
||||
pub fn get_start_recap(&mut self, start: Option<Height>) -> Option<(usize, BlkRecap)> {
|
||||
if let Some(start) = start {
|
||||
let (last_key, last_value) = self.tree.last_key_value()?;
|
||||
|
||||
@@ -88,7 +88,7 @@ impl BlkIndexToBlkRecap {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn update(&mut self, blk_metadata_and_block: &BlkMetadataAndBlock, height: usize) {
|
||||
pub fn update(&mut self, blk_metadata_and_block: &BlkMetadataAndBlock, height: Height) {
|
||||
let blk_index = blk_metadata_and_block.blk_metadata.index;
|
||||
|
||||
if let Some(last_entry) = self.tree.last_entry() {
|
||||
|
||||
@@ -3,11 +3,11 @@ use std::path::PathBuf;
|
||||
use bitcoin::{hashes::Hash, BlockHash};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{path_to_modified_time, BlkMetadataAndBlock};
|
||||
use crate::{path_to_modified_time, BlkMetadataAndBlock, Height};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub struct BlkRecap {
|
||||
min_continuous_height: usize,
|
||||
min_continuous_height: Height,
|
||||
min_continuous_prev_hash: BlockHash,
|
||||
modified_time: u64,
|
||||
}
|
||||
@@ -15,13 +15,13 @@ pub struct BlkRecap {
|
||||
impl BlkRecap {
|
||||
pub fn first(blk_metadata_and_block: &BlkMetadataAndBlock) -> Self {
|
||||
Self {
|
||||
min_continuous_height: 0,
|
||||
min_continuous_height: Height::default(),
|
||||
min_continuous_prev_hash: BlockHash::all_zeros(),
|
||||
modified_time: blk_metadata_and_block.blk_metadata.modified_time,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from(height: usize, blk_metadata_and_block: &BlkMetadataAndBlock) -> Self {
|
||||
pub fn from(height: Height, blk_metadata_and_block: &BlkMetadataAndBlock) -> Self {
|
||||
Self {
|
||||
min_continuous_height: height,
|
||||
min_continuous_prev_hash: blk_metadata_and_block.block.header.prev_blockhash,
|
||||
@@ -36,11 +36,11 @@ impl BlkRecap {
|
||||
self.modified_time != path_to_modified_time(blk_path)
|
||||
}
|
||||
|
||||
pub fn is_younger_than(&self, height: usize) -> bool {
|
||||
pub fn is_younger_than(&self, height: Height) -> bool {
|
||||
self.min_continuous_height > height
|
||||
}
|
||||
|
||||
pub fn height(&self) -> usize {
|
||||
pub fn height(&self) -> Height {
|
||||
self.min_continuous_height
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
use std::{
|
||||
fmt::{self, Debug},
|
||||
io,
|
||||
};
|
||||
|
||||
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
IO(io::Error),
|
||||
ZeroCopyError,
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(value: io::Error) -> Self {
|
||||
Self::IO(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B> From<zerocopy::error::SizeError<A, B>> for Error {
|
||||
fn from(_: zerocopy::error::SizeError<A, B>) -> Self {
|
||||
Self::ZeroCopyError
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Error::IO(error) => Debug::fmt(&error, f),
|
||||
Error::ZeroCopyError => write!(f, "Zero copy convert error"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {}
|
||||
@@ -0,0 +1,188 @@
|
||||
use std::{
|
||||
fmt::{self, Debug},
|
||||
fs, io,
|
||||
ops::{Add, AddAssign, Rem, Sub},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::{
|
||||
rpc::{self, RpcApi},
|
||||
Error,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deref, DerefMut, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "zerocopy", derive(FromBytes, Immutable, IntoBytes, KnownLayout))]
|
||||
pub struct Height(u32);
|
||||
|
||||
impl Height {
|
||||
const ZERO: Self = Height(0);
|
||||
|
||||
pub fn write(&self, path: &Path) -> Result<(), io::Error> {
|
||||
fs::write(path, self.as_bytes())
|
||||
}
|
||||
|
||||
pub fn increment(&mut self) {
|
||||
self.0 += 1;
|
||||
}
|
||||
|
||||
pub fn incremented(self) -> Self {
|
||||
Self(self.0 + 1)
|
||||
}
|
||||
|
||||
pub fn decrement(&mut self) {
|
||||
self.0 -= 1;
|
||||
}
|
||||
|
||||
pub fn decremented(self) -> Self {
|
||||
Self(self.0.checked_sub(1).unwrap_or_default())
|
||||
}
|
||||
|
||||
pub fn is_zero(self) -> bool {
|
||||
self == Self::ZERO
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<u64> for Height {
|
||||
fn eq(&self, other: &u64) -> bool {
|
||||
**self == *other as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Height> for Height {
|
||||
type Output = Height;
|
||||
|
||||
fn add(self, rhs: Height) -> Self::Output {
|
||||
Self::from(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<u32> for Height {
|
||||
type Output = Height;
|
||||
|
||||
fn add(self, rhs: u32) -> Self::Output {
|
||||
Self::from(self.0 + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Height {
|
||||
type Output = Height;
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
Self::from(*self + rhs as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<Height> for Height {
|
||||
type Output = Height;
|
||||
fn sub(self, rhs: Height) -> Self::Output {
|
||||
Self::from(*self - *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<i32> for Height {
|
||||
type Output = Height;
|
||||
fn sub(self, rhs: i32) -> Self::Output {
|
||||
Self::from(*self - rhs as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<u32> for Height {
|
||||
type Output = Height;
|
||||
fn sub(self, rhs: u32) -> Self::Output {
|
||||
Self::from(*self - rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<usize> for Height {
|
||||
type Output = Height;
|
||||
fn sub(self, rhs: usize) -> Self::Output {
|
||||
Self::from(*self - rhs as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<usize> for Height {
|
||||
fn add_assign(&mut self, rhs: usize) {
|
||||
*self = self.add(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl Rem<usize> for Height {
|
||||
type Output = Height;
|
||||
fn rem(self, rhs: usize) -> Self::Output {
|
||||
Self(self.abs_diff(Height::from(rhs).0))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Height {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", **self)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for Height {
|
||||
fn from(value: u32) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Height {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value as u32)
|
||||
}
|
||||
}
|
||||
impl From<Height> for usize {
|
||||
fn from(value: Height) -> Self {
|
||||
value.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Height> for u64 {
|
||||
fn from(value: Height) -> Self {
|
||||
value.0 as u64
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&rpc::Client> for Height {
|
||||
type Error = rpc::Error;
|
||||
fn try_from(value: &rpc::Client) -> Result<Self, Self::Error> {
|
||||
Ok((value.get_blockchain_info()?.blocks as usize - 1).into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bitcoin::locktime::absolute::Height> for Height {
|
||||
fn from(value: bitcoin::locktime::absolute::Height) -> Self {
|
||||
Self(value.to_consensus_u32())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Height> for bitcoin::locktime::absolute::Height {
|
||||
fn from(value: Height) -> Self {
|
||||
bitcoin::locktime::absolute::Height::from_consensus(*value).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "zerocopy")]
|
||||
impl TryFrom<&Path> for Height {
|
||||
type Error = Error;
|
||||
fn try_from(value: &Path) -> Result<Self, Self::Error> {
|
||||
Ok(Self::read_from_bytes(fs::read(value)?.as_slice())?.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "fjall")]
|
||||
impl TryFrom<fjall::Slice> for Height {
|
||||
type Error = Error;
|
||||
fn try_from(value: fjall::Slice) -> Result<Self, Self::Error> {
|
||||
Ok(Self::read_from_bytes(&value)?)
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "fjall")]
|
||||
impl From<Height> for fjall::Slice {
|
||||
fn from(value: Height) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
+8
-4
@@ -25,11 +25,15 @@ mod blk_index_to_blk_recap;
|
||||
mod blk_metadata;
|
||||
mod blk_metadata_and_block;
|
||||
mod blk_recap;
|
||||
mod error;
|
||||
mod height;
|
||||
mod utils;
|
||||
|
||||
use blk_index_to_blk_recap::*;
|
||||
use blk_metadata::*;
|
||||
use blk_metadata_and_block::*;
|
||||
pub use error::*;
|
||||
pub use height::*;
|
||||
use utils::*;
|
||||
|
||||
pub const NUMBER_OF_UNSAFE_BLOCKS: usize = 1000;
|
||||
@@ -75,10 +79,10 @@ const BOUND_CAP: usize = 210;
|
||||
///
|
||||
pub fn new(
|
||||
data_dir: &Path,
|
||||
start: Option<usize>,
|
||||
end: Option<usize>,
|
||||
start: Option<Height>,
|
||||
end: Option<Height>,
|
||||
rpc: &'static bitcoincore_rpc::Client,
|
||||
) -> Receiver<(usize, Block, BlockHash)> {
|
||||
) -> Receiver<(Height, Block, BlockHash)> {
|
||||
let (send_block_reader, recv_block_reader) = bounded(BOUND_CAP);
|
||||
let (send_block, recv_block) = bounded(BOUND_CAP);
|
||||
let (send_height_block_hash, recv_height_block_hash) = bounded(BOUND_CAP);
|
||||
@@ -189,7 +193,7 @@ pub fn new(
|
||||
});
|
||||
|
||||
thread::spawn(move || {
|
||||
let mut height = start_recap.map_or(0, |(_, recap)| recap.height());
|
||||
let mut height = start_recap.map_or(Height::default(), |(_, recap)| recap.height());
|
||||
|
||||
let mut future_blocks = BTreeMap::default();
|
||||
let mut recent_chain: VecDeque<(BlockHash, BlkMetadataAndBlock)> = VecDeque::default();
|
||||
|
||||
@@ -14,10 +14,10 @@ fn main() {
|
||||
.unwrap(),
|
||||
));
|
||||
|
||||
let start = Some(460_001);
|
||||
let start = Some(460_001_u32.into());
|
||||
let end = None;
|
||||
|
||||
biter::new(data_dir, start, end, rpc)
|
||||
biterator::new(data_dir, start, end, rpc)
|
||||
.iter()
|
||||
.for_each(|(height, _block, hash)| {
|
||||
println!("{height}: {hash}");
|
||||
|
||||
Reference in New Issue
Block a user