Skip to content

Commit

Permalink
Merge ValuedMammal/bdk-kyoto#52: Allow getting multiple Receiver
Browse files Browse the repository at this point in the history
f97514e fix(client): allow getting multiple `Receiver` (Rob N)

Pull request description:

  i realized that only allowing `&mut Receiver<NodeMessage>` may be a bit too limiting in the LN context. there is no API limitation preventing multiple `Receiver<NodeMessage>` out at one time, so i go ahead with that here

  cc @ValuedMammal

ACKs for top commit:
  ValuedMammal:
    ACK f97514e

Tree-SHA512: 03610a9b2ed0a7bf880c8f074e8b898ed9b82ce86a6cabde3832d49352dcfc2e8099b8d474049cd0be6af13e1f7e300918559446e763f6b0075712ca8ac5488d
  • Loading branch information
ValuedMammal committed Sep 23, 2024
2 parents 21fde8a + f97514e commit 1e1d37a
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 44 deletions.
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

0 comments on commit 1e1d37a

Please sign in to comment.