indexer: moved height to iterator

This commit is contained in:
nym21
2025-02-20 11:40:26 +01:00
parent 5e39510f21
commit f0d86f2392
19 changed files with 124 additions and 87 deletions
+7 -1
View File
@@ -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 }
+4 -4
View File
@@ -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() {
+6 -6
View File
@@ -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
}
+35
View File
@@ -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 {}
+188
View File
@@ -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
View File
@@ -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();
+2 -2
View File
@@ -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}");