diff --git a/src/builder.rs b/src/builder.rs index 4e859f5..0c97fcd 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -45,17 +45,17 @@ //! } //! ``` -use std::{collections::HashSet, path::PathBuf, time::Duration}; +use std::{path::PathBuf, time::Duration}; use bdk_chain::local_chain::MissingGenesisError; -use bdk_wallet::{KeychainKind, Wallet}; +use bdk_wallet::Wallet; use kyoto::NodeBuilder; pub use kyoto::{ db::error::SqlInitializationError, AddrV2, HeaderCheckpoint, ScriptBuf, ServiceFlags, TrustedPeer, }; -use crate::{EventReceiver, LightClient}; +use crate::{EventReceiver, LightClient, WalletExt}; const RECOMMENDED_PEERS: u8 = 2; @@ -155,21 +155,9 @@ impl<'a> LightClientBuilder<'a> { } node_builder = node_builder.num_required_peers(self.connections.unwrap_or(RECOMMENDED_PEERS)); - let mut spks: HashSet = HashSet::new(); - for keychain in [KeychainKind::External, KeychainKind::Internal] { - // The user may choose to recover a wallet with lookahead scripts - // or use the last revealed index plus some padding to find new transactions - let last_revealed = self - .wallet - .spk_index() - .last_revealed_index(keychain) - .unwrap_or(0); - let lookahead_index = last_revealed + self.wallet.spk_index().lookahead(); - for index in 0..=lookahead_index { - spks.insert(self.wallet.peek_address(keychain, index).script_pubkey()); - } - } - let (node, kyoto_client) = node_builder.add_scripts(spks).build_node()?; + let (node, kyoto_client) = node_builder + .add_scripts(self.wallet.peek_revealed_plus_lookahead().collect()) + .build_node()?; let (sender, receiver) = kyoto_client.split(); let event_receiver = EventReceiver::from_index( self.wallet.local_chain().tip(), diff --git a/src/lib.rs b/src/lib.rs index d7beb72..285a429 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -160,6 +160,8 @@ #![warn(missing_docs)] use core::fmt; use std::collections::BTreeMap; +#[cfg(feature = "wallet")] +use std::collections::HashSet; use bdk_chain::{ keychain_txout::KeychainTxOutIndex, @@ -183,7 +185,9 @@ pub use kyoto::{DisconnectedHeader, FailurePayload}; pub use kyoto::ClientSender as EventSender; use kyoto::{IndexedBlock, NodeMessage, RejectReason}; -pub use kyoto::{NodeState, Receiver, SyncUpdate, TxBroadcast, TxBroadcastPolicy, Txid, Warning}; +pub use kyoto::{ + NodeState, Receiver, ScriptBuf, SyncUpdate, TxBroadcast, TxBroadcastPolicy, Txid, Warning, +}; #[cfg(all(feature = "wallet", feature = "rusqlite"))] pub mod builder; @@ -487,6 +491,37 @@ pub enum LogLevel { Warning, } +/// Extend the functionality of [`Wallet`](bdk_wallet) for interoperablility +/// with the light client. +#[cfg(feature = "wallet")] +pub trait WalletExt { + /// Collect relevant scripts for addition to the node. Peeks scripts + /// `lookahead` + `last_revealed_index` for each keychain. + fn peek_revealed_plus_lookahead(&self) -> Box>; + + /// Get the current [`CheckPoint`] and [`KeychainTxOutIndex`](bdk_chain::keychain_txout) + /// for constructing an [`EventReceiver`]. + fn checkpoint_and_spk_index(&self) -> (CheckPoint, KeychainTxOutIndex); +} + +#[cfg(feature = "wallet")] +impl WalletExt for bdk_wallet::Wallet { + fn peek_revealed_plus_lookahead(&self) -> Box> { + let mut spks: HashSet = HashSet::new(); + for keychain in [KeychainKind::External, KeychainKind::Internal] { + let last_revealed = self.spk_index().last_revealed_index(keychain).unwrap_or(0); + let lookahead_index = last_revealed + self.spk_index().lookahead(); + for index in 0..=lookahead_index { + spks.insert(self.peek_address(keychain, index).script_pubkey()); + } + } + Box::new(spks.into_iter()) + } + + fn checkpoint_and_spk_index(&self) -> (CheckPoint, KeychainTxOutIndex) { + (self.local_chain().tip(), self.spk_index().clone()) + } +} trait StringExt { fn into_string(self) -> String; }