Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow getting multiple Receiver #52

Merged
merged 1 commit into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
//!
//! ## Details
//!
//! The node has a number of configurations. Notably, the height of in the blockchain to start a wallet recovery
//! and the nodes on the peer-to-peer network are both configurable.
//! The node has a number of configurations. Notably, the height of in the blockchain to start a
//! wallet recovery and the nodes on the peer-to-peer network are both configurable.
//!
//! ```no_run
//! # const RECEIVE: &str = "tr([7d94197e/86'/1'/0']tpubDCyQVJj8KzjiQsFjmb3KwECVXPvMwvAxxZGCP9XmWSopmjW3bCV3wD7TgxrUhiGSueDS1MU5X1Vb1YjYcp8jitXc5fXfdC1z68hDDEyKRNr/0/*)";
Expand Down Expand Up @@ -112,8 +112,9 @@ impl<'a> LightClientBuilder<'a> {
self
}

/// Use all the scripts up to the wallet's lookahead parameter. Only to be used during wallet recovery,
/// when we do not have any knowledge of the scripts used in the wallet yet. For more information on the wallet lookahead,
/// Use all the scripts up to the wallet's lookahead parameter. Only to be used during wallet
/// recovery, when we do not have any knowledge of the scripts used in the wallet yet. For
/// more information on the wallet lookahead,
/// see [`KeychainTxOutIndex`](bdk_wallet::chain::indexer::keychain_txout::KeychainTxOutIndex).
pub fn use_lookahead_scripts(mut self) -> Self {
self.lookahead = true;
Expand Down Expand Up @@ -173,8 +174,9 @@ impl<'a> LightClientBuilder<'a> {
}
match self.birthday_height {
Some(birthday) => {
// If there is a birthday at a height less than our local chain, we may assume we've already synced
// the wallet past the birthday height and no longer need it.
// If there is a birthday at a height less than our local chain, we may assume we've
// already synced the wallet past the birthday height and no longer
// need it.
if birthday < self.wallet.local_chain().tip().height() {
let block_id = self.wallet.local_chain().tip();
let header_cp = HeaderCheckpoint::new(block_id.height(), block_id.hash());
Expand All @@ -185,8 +187,9 @@ impl<'a> LightClientBuilder<'a> {
}
}
None => {
// If there is no birthday provided and the local chain starts at the genesis block, we assume this
// is a new wallet and use the most recent checkpoint. Otherwise we sync from the last known tip in the
// If there is no birthday provided and the local chain starts at the genesis block,
// we assume this is a new wallet and use the most recent
// checkpoint. Otherwise we sync from the last known tip in the
// LocalChain.
let block_id = self.wallet.local_chain().tip();
if block_id.height() > 0 {
Expand Down
72 changes: 43 additions & 29 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
//! BDK-Kyoto is an extension of [Kyoto](https://github.com/rustaceanrob/kyoto), a client-side implementation of BIP157/BIP158.
//! These proposals define a way for users to fetch transactions privately, using _compact block filters_.
//! You may want to read the specification [here](https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki).
//! These proposals define a way for users to fetch transactions privately, using _compact block
//! filters_. You may want to read the specification [here](https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki).
//!
//! Kyoto runs as a psuedo-node, sending messages over the Bitcoin peer-to-peer layer, finding new peers to connect to, and managing a
//! light-weight database of Bitcoin block headers. As such, developing a wallet application using this crate is distinct from a typical
//! client/server relationship. Esplora and Electrum offer _proactive_ APIs, in that the servers will respond to events as they are requested.
//! In the case of running a node as a background process, the developer experience is far more _reactive_, in that the node may emit any number of events,
//! and the application may respond to them.
//! Kyoto runs as a psuedo-node, sending messages over the Bitcoin peer-to-peer layer, finding new
//! peers to connect to, and managing a light-weight database of Bitcoin block headers. As such,
//! developing a wallet application using this crate is distinct from a typical client/server
//! relationship. Esplora and Electrum offer _proactive_ APIs, in that the servers will respond to
//! events as they are requested. In the case of running a node as a background process, the
//! developer experience is far more _reactive_, in that the node may emit any number of events, and
//! the application may respond to them.
//!
//! BDK-Kyoto curates these events into structures that are easily handled by BDK APIs, making integration of compact block filters easily understood.
//! Developers are free to use [`bdk_wallet`], or only primatives found in [`bdk_core`](https://docs.rs/bdk_core/latest/bdk_core/) and [`bdk_chain`].
//! BDK-Kyoto curates these events into structures that are easily handled by BDK APIs, making
//! integration of compact block filters easily understood. Developers are free to use [`bdk_wallet`], or only primatives found in [`bdk_core`](https://docs.rs/bdk_core/latest/bdk_core/) and [`bdk_chain`].
//!
//! ## Examples
//!
//! If you have an existing project that leverages `bdk_wallet`, building the compact block filter _node_ and _client_ is simple.
//! You may construct and configure a node to integrate with your wallet by using a [`LightClientBuilder`](crate).
//! If you have an existing project that leverages `bdk_wallet`, building the compact block filter
//! _node_ and _client_ is simple. You may construct and configure a node to integrate with your
//! wallet by using a [`LightClientBuilder`](crate).
//!
//! ```no_run
//! # const RECEIVE: &str = "tr([7d94197e/86'/1'/0']tpubDCyQVJj8KzjiQsFjmb3KwECVXPvMwvAxxZGCP9XmWSopmjW3bCV3wD7TgxrUhiGSueDS1MU5X1Vb1YjYcp8jitXc5fXfdC1z68hDDEyKRNr/0/*)";
Expand Down Expand Up @@ -44,7 +47,8 @@
//! }
//! ```
//!
//! Custom wallet implementations may still take advantage of BDK-Kyoto, however building the [`Client`] will involve configuring Kyoto directly.
//! Custom wallet implementations may still take advantage of BDK-Kyoto, however building the
//! [`Client`] will involve configuring Kyoto directly.
//!
//! ```no_run
//! # const RECEIVE: &str = "tr([7d94197e/86'/1'/0']tpubDCyQVJj8KzjiQsFjmb3KwECVXPvMwvAxxZGCP9XmWSopmjW3bCV3wD7TgxrUhiGSueDS1MU5X1Vb1YjYcp8jitXc5fXfdC1z68hDDEyKRNr/0/*)";
Expand Down Expand Up @@ -119,7 +123,7 @@
//! }
//! client.shutdown().await?;
//! Ok(())
//!}
//! }
//! ```

#![warn(missing_docs)]
Expand Down Expand Up @@ -153,7 +157,7 @@ pub use kyoto::{
#[derive(Debug)]
pub struct Client<K> {
// channel sender
sender: kyoto::ClientSender,
client: kyoto::Client,
// channel receiver
receiver: kyoto::Receiver<NodeMessage>,
// changes to local chain
Expand All @@ -172,9 +176,9 @@ where
index: &KeychainTxOutIndex<K>,
client: kyoto::Client,
) -> Result<Self, MissingGenesisError> {
let (sender, receiver) = client.split();
let receiver = client.receiver();
Ok(Self {
sender,
client,
receiver,
chain: LocalChain::from_tip(cp)?,
graph: IndexedTxGraph::new(index.clone()),
Expand All @@ -185,9 +189,9 @@ where
/// This may take a significant portion of time during wallet recoveries or dormant wallets.
/// Note that you may call this method in a loop as long as the [`Node`] is running.
///
/// A reference to a [`NodeMessageHandler`] is required, which handles events emitted from a running
/// [`Node`]. Production applications should define how the application handles these events and displays
/// them to end users.
/// A reference to a [`NodeMessageHandler`] is required, which handles events emitted from a
/// running [`Node`]. Production applications should define how the application handles
/// these events and displays them to end users.
pub async fn update(&mut self, logger: &dyn NodeMessageHandler) -> Option<FullScanResult<K>> {
let mut chain_changeset = BTreeMap::new();
while let Ok(message) = self.receiver.recv().await {
Expand Down Expand Up @@ -272,33 +276,43 @@ where
tx: Transaction,
policy: TxBroadcastPolicy,
) -> Result<(), ClientError> {
self.sender
self.client
.broadcast_tx(TxBroadcast {
tx,
broadcast_policy: policy,
})
.await
}

/// Add more scripts to the node. For example, a user may reveal a Bitcoin address to receive a payment,
/// so this script should be added to the [`Node`].
/// Add more scripts to the node. For example, a user may reveal a Bitcoin address to receive a
/// payment, so this script should be added to the [`Node`].
pub async fn add_script(&self, script: impl Into<ScriptBuf>) -> Result<(), ClientError> {
self.sender.add_script(script).await
self.client.add_script(script).await
}

/// Shutdown the node.
pub async fn shutdown(&self) -> Result<(), ClientError> {
self.sender.shutdown().await
self.client.shutdown().await
}

/// Get a structure to broadcast transactions. Useful for broadcasting transactions and updating concurrently.
/// Get a structure to broadcast transactions. Useful for broadcasting transactions and updating
/// concurrently.
pub fn transaction_broadcaster(&self) -> TransactionBroadcaster {
TransactionBroadcaster::new(self.sender.clone())
TransactionBroadcaster::new(self.client.sender())
}

/// Get a mutable reference to the underlying channel [`Receiver`].
pub fn channel_receiver(&mut self) -> &mut Receiver<NodeMessage> {
&mut self.receiver
/// Generate a new channel [`Receiver`] to get [`NodeMessage`] directly. Note that
/// [`Client::update`] will handle messages and build updates.
///
/// ## Performance
///
/// When generating a new channel [`Receiver`], a message must be consumed by _all_ [`Receiver`]
/// before it is removed from memory. For channels that process data slowly, this can cause
/// messages to build up in the channel, and may even cause errors if too many messages
/// are held in the channel at one time. For the best results, applications may not want to call
/// this method at all, or only a few times.
pub fn channel_receiver(&self) -> Receiver<NodeMessage> {
self.client.receiver()
}
}

Expand Down
16 changes: 9 additions & 7 deletions src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
//!
//! # Examples
//!
//! For quick iteration and debugging, the [`PrintLogger`] responds to node events by simply printing the display to the console.
//! For quick iteration and debugging, the [`PrintLogger`] responds to node events by simply
//! printing the display to the console.
//!
//! ```rust
//! use bdk_kyoto::logger::{PrintLogger, NodeMessageHandler};
//! use bdk_kyoto::logger::{NodeMessageHandler, PrintLogger};
//! use bdk_kyoto::Warning;
//!
//!
//! let logger = PrintLogger::new();
//! logger.dialog("The node is running".into());
//! logger.warning(Warning::PeerTimedOut);
Expand All @@ -16,16 +17,17 @@
//! For a more descriptive console log, the `tracing` feature may be used.
//!
//! ```rust
//! use bdk_kyoto::logger::{TraceLogger, NodeMessageHandler};
//! use bdk_kyoto::logger::{NodeMessageHandler, TraceLogger};
//! use bdk_kyoto::Warning;
//!
//!
//! let logger = TraceLogger::new();
//! logger.dialog("The node is running".into());
//! logger.warning(Warning::PeerTimedOut);
//! ```
//!
//! For production applications, a custom implementation of [`NodeMessageHandler`] should be implemented.
//! An example of a good applciation logger should implement user interface behavior and potentially save information to a file.
//! For production applications, a custom implementation of [`NodeMessageHandler`] should be
//! implemented. An example of a good applciation logger should implement user interface behavior
//! and potentially save information to a file.

use std::fmt::Debug;

Expand Down
Loading