1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
//! niebla-158: a compact-filter (BIP-158) client engine for wallets.
//!
//! ## What you implement
//! - [`FilterSource`]: fetch cfheaders batches, per-block filters, and raw blocks.
//! - [`WalletHooks`]: provide a **watchlist** and handle **on_block_match** callbacks.
//! - [`Store`]: keep a couple of integers (verified tip + last scanned).
//! - [`HeaderSource`]: return block header info by height (used to scan ranges).
//!
//! ## What the engine does
//! - Validates **cfheaders** against optional checkpoints (defense-in-depth).
//! - Iterates new heights, pulls **filters**, tests against your watchlist.
//! - On a hit, fetches the **block**, decodes transactions, and notifies you.
//!
//! ## Minimal usage
//! ```rust,ignore
//! use niebla_158::prelude::*;
//! use bitcoin::{BlockHash, ScriptBuf, hashes::{sha256d, Hash as _}};
//! use async_trait::async_trait;
//!
//! // --- Your implementations ---
//! struct MySource;
//! #[async_trait]
//! impl FilterSource for MySource {
//! async fn get_cfheaders(&self, _start: u32, _stop: BlockHash) -> anyhow::Result<CfHeadersBatch> {
//! Ok(CfHeadersBatch { start_height: 0, headers: vec![] })
//! }
//! async fn get_cfilter(&self, _block: BlockHash) -> anyhow::Result<Vec<u8>> { Ok(vec![]) }
//! async fn get_block(&self, _block: BlockHash) -> anyhow::Result<Vec<u8>> { Ok(vec![]) }
//! }
//!
//! struct MyHeaders;
//! #[async_trait]
//! impl HeaderSource for MyHeaders {
//! async fn tip_height(&self) -> anyhow::Result<u32> { Ok(0) }
//! async fn hash_at_height(&self, _h: u32) -> anyhow::Result<BlockHash> {
//! Ok(BlockHash::from_raw_hash(sha256d::Hash::all_zeros()))
//! }
//! }
//!
//! struct MyStore;
//! #[async_trait]
//! impl Store for MyStore {
//! async fn load_cf_tip(&self) -> anyhow::Result<Option<(u32, BlockHash)>> { Ok(None) }
//! async fn save_cf_tip(&self, _h: u32, _cf: BlockHash) -> anyhow::Result<()> { Ok(()) }
//! async fn get_last_scanned(&self) -> anyhow::Result<u32> { Ok(0) }
//! async fn set_last_scanned(&self, _h: u32) -> anyhow::Result<()> { Ok(()) }
//! async fn get_birth_height(&self) -> anyhow::Result<Option<u32>> { Ok(None) }
//! async fn set_birth_height(&self, _h: u32) -> anyhow::Result<()> { Ok(()) }
//! }
//!
//! struct MyWallet;
//! #[async_trait]
//! impl WalletHooks for MyWallet {
//! async fn watchlist(&self) -> anyhow::Result<Vec<ScriptBuf>> { Ok(vec![]) }
//! async fn on_block_match(
//! &self, _h: u32, _b: BlockHash, _txs: Vec<bitcoin::Transaction>
//! ) -> anyhow::Result<()> { Ok(()) }
//! }
//!
//! // --- Wire it up ---
//! async fn run() -> anyhow::Result<()> {
//! let engine = Niebla158::new(MyStore, MyWallet, MySource, MyHeaders);
//! // Drive with an iterator of (height, header_hash); here empty:
//! engine.run_to_tip(std::iter::empty()).await?;
//! Ok(())
//! }
//! ```
/// Engine that verifies cfheaders, scans filters, and fetches matching blocks.
/// Traits and types for fetching cfheaders, cfilters, and blocks from the network.
/// Wallet callbacks: provide a watchlist and receive matches.
/// Block header lookup abstraction (height → hash).
// Internal helpers:
/// Persistence layer (traits and SQLite implementation).
// Public re-exports
pub use Niebla158;
pub use FilterSource;
pub use WalletHooks;
pub use ;
/// Convenience prelude for end users.