use std::{collections::BTreeMap, fmt::Display};
use bdk_wallet::{chain::IndexedTxGraph, Wallet};
use kyoto::HeaderCheckpoint;
pub use kyoto::{db::error::SqlInitializationError, NodeBuilder};
use crate::{LightClient, ScanType, UpdateSubscriber, WalletExt};
pub trait NodeBuilderExt {
fn build_with_wallet(
self,
wallet: &Wallet,
scan_type: ScanType,
) -> Result<LightClient, BuilderError>;
}
impl NodeBuilderExt for NodeBuilder {
fn build_with_wallet(
mut self,
wallet: &Wallet,
scan_type: ScanType,
) -> Result<LightClient, BuilderError> {
let network = wallet.network();
if self.network().ne(&network) {
return Err(BuilderError::NetworkMismatch);
}
let scripts = wallet.peek_revealed_plus_lookahead();
self = self.add_scripts(scripts);
match scan_type {
ScanType::New => (),
ScanType::Sync => {
let block_id = wallet.local_chain().tip();
let header_cp = HeaderCheckpoint::new(block_id.height(), block_id.hash());
self = self.after_checkpoint(header_cp);
}
ScanType::Recovery { from_height } => {
let birthday = from_height.saturating_sub(1);
let header_cp =
HeaderCheckpoint::closest_checkpoint_below_height(birthday, network);
self = self.after_checkpoint(header_cp);
}
};
let (node, client) = self.build()?;
let kyoto::Client {
requester,
log_rx,
info_rx,
warn_rx,
event_rx,
} = client;
let indexed_graph = IndexedTxGraph::new(wallet.spk_index().clone());
let update_subscriber = UpdateSubscriber {
receiver: event_rx,
chain: wallet.local_chain().clone(),
graph: indexed_graph,
chain_changeset: BTreeMap::new(),
};
Ok(LightClient {
requester,
log_subscriber: log_rx,
info_subscriber: info_rx,
warning_subscriber: warn_rx,
update_subscriber,
node,
})
}
}
#[derive(Debug)]
pub enum BuilderError {
IO(SqlInitializationError),
NetworkMismatch,
}
impl Display for BuilderError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
BuilderError::IO(e) => write!(f, "failed to initialize the db: {e}"),
BuilderError::NetworkMismatch => {
write!(f, "wallet network and node network do not match")
}
}
}
}
impl std::error::Error for BuilderError {}
impl From<SqlInitializationError> for BuilderError {
fn from(value: SqlInitializationError) -> Self {
BuilderError::IO(value)
}
}