From f2ea34384674c3816a827aed12915fb8970a2bae Mon Sep 17 00:00:00 2001 From: Vladimir Fomene Date: Tue, 18 Jul 2023 17:53:59 +0300 Subject: [PATCH 1/5] Implement a CBF client using Nakamoto This implements a structure that help us start a Nakamoto client and watch for events like BlockMatched, BlockDisconnected and Sync for the scripts that we are interested in. We also implement a ChainOracle for the CBF client. --- Cargo.toml | 1 + crates/bdk_cbf/Cargo.toml | 10 +++ crates/bdk_cbf/src/lib.rs | 125 ++++++++++++++++++++++++++ example-crates/example_cbf/Cargo.toml | 11 +++ 4 files changed, 147 insertions(+) create mode 100644 crates/bdk_cbf/Cargo.toml create mode 100644 crates/bdk_cbf/src/lib.rs create mode 100644 example-crates/example_cbf/Cargo.toml diff --git a/Cargo.toml b/Cargo.toml index c5f2692da..f76134b38 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "crates/file_store", "crates/electrum", "crates/esplora", + "crates/bdk_cbf", "example-crates/example_cli", "example-crates/example_electrum", "example-crates/wallet_electrum", diff --git a/crates/bdk_cbf/Cargo.toml b/crates/bdk_cbf/Cargo.toml new file mode 100644 index 000000000..8c92edc33 --- /dev/null +++ b/crates/bdk_cbf/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "bdk_cbf" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +nakamoto = "0.4.0" +bdk_chain = { path = "../chain", version = "0.4.0"} diff --git a/crates/bdk_cbf/src/lib.rs b/crates/bdk_cbf/src/lib.rs new file mode 100644 index 000000000..616b61ed0 --- /dev/null +++ b/crates/bdk_cbf/src/lib.rs @@ -0,0 +1,125 @@ +use std::{net, thread}; + +use nakamoto::client::network::Services; +use nakamoto::client::traits::Handle as HandleTrait; +use nakamoto::client::Handle; +use nakamoto::client::{Client, Config, Error, chan, Event}; +use nakamoto::common::block::Height; +use nakamoto::net::poll; + +use bdk_chain::{bitcoin::{ Script, Transaction }, BlockId, ChainOracle}; + +/// The network reactor we're going to use. +type Reactor = poll::Reactor; + +impl ChainOracle for CBFClient { + type Error = nakamoto::client::Error; + + fn is_block_in_chain( + &self, + block: BlockId, + chain_tip: BlockId, + ) -> Result, Self::Error> { + if block.height > chain_tip.height { + return Ok(None); + } + + Ok( + match ( + self.handle.get_block_by_height(block.height as _)?, + self.handle.get_block_by_height(chain_tip.height as _)?, + ) { + (Some(b), Some(c)) => { + Some(b.block_hash() == block.hash && c.block_hash() == chain_tip.hash) + } + _ => None, + }, + ) + } + + fn get_chain_tip(&self) -> Result, Self::Error> { + let (height, header) = self.handle.get_tip()?; + Ok(Some(BlockId { + height: height as u32, + hash: header.block_hash(), + })) + } +} + +pub struct CBFClient { + handle: Handle, +} + +pub enum CBFUpdate { + Synced { height: Height, tip: Height }, + BlockMatched { + transactions: Vec, + block: BlockId + }, + BlockDisconnected { block: BlockId }, +} + +impl CBFClient { + pub fn start_client(cfg: Config, peer_count: usize) -> Result { + let client = Client::::new()?; + let handle = client.handle(); + + // Run the client on a different thread, to not block the main thread. + thread::spawn(|| client.run(cfg).unwrap()); + + // Wait for the client to be connected to a peer. + handle.wait_for_peers(peer_count, Services::default())?; + + Ok(Self { handle }) + } + + //create a function to watch + pub fn start_scanning( + &self, + start_height: Height, + watch: impl Iterator, + ) -> Result<(), Error> { + self.handle.rescan(start_height.., watch)?; + Ok(()) + } + + pub fn watch_events(&self) -> Result { + let events_chan = self.handle.events(); + loop { + chan::select! { + recv(events_chan) -> event => { + let event = event?; + match event { + Event::Ready { .. } => { + todo!("Handle ready event"); + } + Event::FilterProcessed { .. } => { + todo!("Handle filter processed event"); + } + Event::BlockDisconnected { hash, height, .. } => { + return Ok(CBFUpdate::BlockDisconnected { block: BlockId { height: height as u32, hash } }); + } + Event::BlockMatched { + hash, + height, + transactions, + .. + } => { + return Ok(CBFUpdate::BlockMatched { + transactions, + block: BlockId { height: height as u32, hash } + }); + } + Event::Synced { height, tip } => { + return Ok(CBFUpdate::Synced { height, tip }); + } + _ => {} + } + } + } + } + } + + // Create a method that takes in a CBFUpdate and turns it into a + // Indexed Graph update. +} diff --git a/example-crates/example_cbf/Cargo.toml b/example-crates/example_cbf/Cargo.toml new file mode 100644 index 000000000..1ed622fdb --- /dev/null +++ b/example-crates/example_cbf/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "example_cbf" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +bdk_cbf = { path = "../../crates/bdk_cbf"} +bdk_chain = { path = "../../crates/chain"} +bdk_cli = { path = "../example_cli" } From a5e682f91047b278a4d98389acfb711787469f5e Mon Sep 17 00:00:00 2001 From: Vladimir Fomene Date: Tue, 1 Aug 2023 09:32:20 +0300 Subject: [PATCH 2/5] Create CBFUpdate iterator and convert CBFUpdate into TxGraph update CBFUpdateIterator will return CBFUpdate data until the Nakamoto client has reached the tip of the chain. At that point, the iterator will return None. The new method, `into_tx_graph_update`, will convert the CBFUpdate into a TxGraph update. This method is a helper that will be necessary for updating the TxGraph once we have a CBFUpdate. --- crates/bdk_cbf/src/lib.rs | 75 ++++++++++++++++++++++++++++++++------- 1 file changed, 62 insertions(+), 13 deletions(-) diff --git a/crates/bdk_cbf/src/lib.rs b/crates/bdk_cbf/src/lib.rs index 616b61ed0..6e35dfd76 100644 --- a/crates/bdk_cbf/src/lib.rs +++ b/crates/bdk_cbf/src/lib.rs @@ -3,11 +3,14 @@ use std::{net, thread}; use nakamoto::client::network::Services; use nakamoto::client::traits::Handle as HandleTrait; use nakamoto::client::Handle; -use nakamoto::client::{Client, Config, Error, chan, Event}; +use nakamoto::client::{chan, Client, Config, Error, Event}; use nakamoto::common::block::Height; use nakamoto::net::poll; -use bdk_chain::{bitcoin::{ Script, Transaction }, BlockId, ChainOracle}; +use bdk_chain::{ + bitcoin::{Script, Transaction}, + BlockId, ChainOracle, TxGraph, +}; /// The network reactor we're going to use. type Reactor = poll::Reactor; @@ -46,17 +49,45 @@ impl ChainOracle for CBFClient { } } +#[derive(Clone)] pub struct CBFClient { handle: Handle, } +#[derive(Debug, Clone)] pub enum CBFUpdate { - Synced { height: Height, tip: Height }, + Synced { + height: Height, + tip: Height, + }, BlockMatched { transactions: Vec, - block: BlockId + block: BlockId, + }, + BlockDisconnected { + block: BlockId, }, - BlockDisconnected { block: BlockId }, +} + +pub struct CBFUpdateIterator { + client: CBFClient, +} + +impl Iterator for CBFUpdateIterator { + type Item = Result; + + fn next(&mut self) -> Option { + match self.client.watch_events() { + Ok(update) => { + if let CBFUpdate::Synced { .. } = update { + None + } else { + Some(Ok(update)) + } + } + Err(e) => Some(Err(e)), + } + } } impl CBFClient { @@ -83,6 +114,7 @@ impl CBFClient { Ok(()) } + // Watch for Block events that match the scripts we're interested in pub fn watch_events(&self) -> Result { let events_chan = self.handle.events(); loop { @@ -90,12 +122,6 @@ impl CBFClient { recv(events_chan) -> event => { let event = event?; match event { - Event::Ready { .. } => { - todo!("Handle ready event"); - } - Event::FilterProcessed { .. } => { - todo!("Handle filter processed event"); - } Event::BlockDisconnected { hash, height, .. } => { return Ok(CBFUpdate::BlockDisconnected { block: BlockId { height: height as u32, hash } }); } @@ -120,6 +146,29 @@ impl CBFClient { } } - // Create a method that takes in a CBFUpdate and turns it into a - // Indexed Graph update. + // Turns a CBFUpdate into a TxGraph update + pub fn into_tx_graph_update( + &self, + txs: Vec, + block: BlockId, + is_relevant: F, + ) -> TxGraph + where + F: Fn(&Transaction) -> bool, + { + let mut tx_graph = TxGraph::default(); + let filtered_txs = txs.into_iter().filter(|tx| is_relevant(tx)); + for tx in filtered_txs { + let txid = tx.txid(); + let _ = tx_graph.insert_anchor(txid, block); + let _ = tx_graph.insert_tx(tx); + } + tx_graph + } + + pub fn iter(&self) -> CBFUpdateIterator { + CBFUpdateIterator { + client: self.clone(), + } + } } From 5dd5d3d4db0745ac1d0168c90451a3a6646c28a2 Mon Sep 17 00:00:00 2001 From: Vladimir Fomene Date: Thu, 3 Aug 2023 12:07:09 +0300 Subject: [PATCH 3/5] feat: Update into_tx_graph_update and add syncing Update into_tx_graph_update to take a Vec of tuples of blocks and transactions as input to create a TxGraph. Add scanning with Nakamoto client. We start by creating a list of scripts to scan and we continue to scan the chain until we have satisfied stop_gap condition. On each scan we get a fresh list of script to watch. We then update the IndexedGraph and return the IndexedAdditions. --- crates/bdk_cbf/src/lib.rs | 176 +++++++++++++++++++++++++++++++++----- 1 file changed, 156 insertions(+), 20 deletions(-) diff --git a/crates/bdk_cbf/src/lib.rs b/crates/bdk_cbf/src/lib.rs index 6e35dfd76..476178acc 100644 --- a/crates/bdk_cbf/src/lib.rs +++ b/crates/bdk_cbf/src/lib.rs @@ -1,18 +1,25 @@ use std::{net, thread}; +use bdk_chain::keychain::DerivationAdditions; use nakamoto::client::network::Services; -use nakamoto::client::traits::Handle as HandleTrait; use nakamoto::client::Handle; +use nakamoto::client::traits::Handle as HandleTrait; use nakamoto::client::{chan, Client, Config, Error, Event}; use nakamoto::common::block::Height; use nakamoto::net::poll; +pub use nakamoto::client::network::Network; + use bdk_chain::{ bitcoin::{Script, Transaction}, - BlockId, ChainOracle, TxGraph, + collections::BTreeMap, + indexed_tx_graph::{IndexedAdditions, IndexedTxGraph, Indexer}, + keychain::KeychainTxOutIndex, + BlockId, ChainOracle, ConfirmationHeightAnchor, TxGraph, }; -/// The network reactor we're going to use. +use core::fmt::Debug; + type Reactor = poll::Reactor; impl ChainOracle for CBFClient { @@ -79,10 +86,9 @@ impl Iterator for CBFUpdateIterator { fn next(&mut self) -> Option { match self.client.watch_events() { Ok(update) => { - if let CBFUpdate::Synced { .. } = update { - None - } else { - Some(Ok(update)) + match update { + CBFUpdate::Synced { height, tip } if height == tip => None, + _ => Some(Ok(update)) } } Err(e) => Some(Err(e)), @@ -101,6 +107,8 @@ impl CBFClient { // Wait for the client to be connected to a peer. handle.wait_for_peers(peer_count, Services::default())?; + println!("Connected to {} peers", peer_count); + Ok(Self { handle }) } @@ -111,6 +119,7 @@ impl CBFClient { watch: impl Iterator, ) -> Result<(), Error> { self.handle.rescan(start_height.., watch)?; + println!("About to start scanning from height {}", start_height); Ok(()) } @@ -118,6 +127,7 @@ impl CBFClient { pub fn watch_events(&self) -> Result { let events_chan = self.handle.events(); loop { + print!("looping..."); chan::select! { recv(events_chan) -> event => { let event = event?; @@ -131,12 +141,14 @@ impl CBFClient { transactions, .. } => { + println!("Block matched: {} {}", height, hash); return Ok(CBFUpdate::BlockMatched { transactions, block: BlockId { height: height as u32, hash } }); } Event::Synced { height, tip } => { + println!("Synced: {} {}", height, tip); return Ok(CBFUpdate::Synced { height, tip }); } _ => {} @@ -147,21 +159,18 @@ impl CBFClient { } // Turns a CBFUpdate into a TxGraph update - pub fn into_tx_graph_update( + pub fn into_tx_graph_update( &self, - txs: Vec, - block: BlockId, - is_relevant: F, - ) -> TxGraph - where - F: Fn(&Transaction) -> bool, - { + block_txs: Vec<(BlockId, Vec)>, + ) -> TxGraph { let mut tx_graph = TxGraph::default(); - let filtered_txs = txs.into_iter().filter(|tx| is_relevant(tx)); - for tx in filtered_txs { - let txid = tx.txid(); - let _ = tx_graph.insert_anchor(txid, block); - let _ = tx_graph.insert_tx(tx); + + for (blockid, txs) in block_txs.into_iter() { + for tx in txs { + let txid = tx.txid(); + let _ = tx_graph.insert_anchor(txid, to_confirmation_height_anchor(blockid)); + let _ = tx_graph.insert_tx(tx); + } } tx_graph } @@ -171,4 +180,131 @@ impl CBFClient { client: self.clone(), } } + + pub fn scan( + &self, + mut watch_per_keychain: u32, + start_height: Height, + indexed_tx_graph: &mut IndexedTxGraph>, + stop_gap: u32, + ) -> Result>, Error> + where + K: Ord + Clone + Debug, + { + let mut keychain_spks = indexed_tx_graph.index.spks_of_all_keychains(); + let mut empty_scripts_counter = BTreeMap::::new(); + keychain_spks.keys().for_each(|k| { + empty_scripts_counter.insert(k.clone(), 0); + }); + + let mut updates = Vec::new(); + + while let Some(keychains) = Self::check_stop_gap(stop_gap, &empty_scripts_counter) { + keychains.iter().for_each(|k| { + /*let (_, _) =*/ indexed_tx_graph.index.set_lookahead(k, watch_per_keychain); + }); + + let mut spk_watchlist = BTreeMap::>::new(); + for (k, script_iter) in keychain_spks.iter_mut() { + (0..watch_per_keychain).for_each(|_| { + if let Some((_, script)) = script_iter.next() { + let spks = spk_watchlist.entry(k.clone()).or_insert(vec![]); + spks.push(script); + } + }); + } + + let scripts = spk_watchlist.values().flatten().cloned().collect::>(); + self.start_scanning(start_height, scripts.into_iter())?; + + for update in self.iter() { + match update { + Ok(CBFUpdate::BlockMatched { + transactions, + block, + }) => { + let relevant_txs = transactions + .into_iter() + .filter(|tx| indexed_tx_graph.index.is_tx_relevant(tx)) + .collect::>(); + updates.push((block, relevant_txs)); + } + Ok(CBFUpdate::BlockDisconnected { .. }) => { + //TODO: Don't know how to handle re-orgs yet + //I will love to get your comments on this. + } + Ok(_) => {} + Err(e) => { + return Err(e); + } + } + } + + // Determine which scripts are part of the update. + for (k, scripts) in spk_watchlist.iter() { + for script in scripts { + let counter = empty_scripts_counter.get_mut(k).unwrap(); + if Self::is_script_in_udpate(script.clone(), &updates) { + *counter = 0; + } else { + *counter += 1; + } + } + } + + watch_per_keychain += watch_per_keychain; + } + + //apply the updates to IndexedGraph + let graph_update = self.into_tx_graph_update(updates); + let additions = indexed_tx_graph.apply_update(graph_update); + + Ok(additions) + } + + fn is_script_in_udpate(script: Script, updates: &Vec<(BlockId, Vec)>) -> bool { + for update in updates { + for tx in update.1.iter() { + for output in tx.output.iter() { + if output.script_pubkey == script { + return true; + } + } + } + } + false + } + + fn check_stop_gap(stop_gap: u32, empty_scripts_counter: &BTreeMap) -> Option> + where + K: Ord + Clone + Debug, + { + let keychains = empty_scripts_counter + .iter() + .filter(|(_, counter)| **counter < stop_gap) + .map(|(k, _)| k.clone()) + .collect::>(); + if keychains.is_empty() { + None + } else { + Some(keychains) + } + } + + pub fn submit_transaction(&self, tx: Transaction) -> Result<(), Error> { + self.handle.submit_transaction(tx)?; + Ok(()) + } + + pub fn shutdown(self) -> Result<(), Error>{ + self.handle.shutdown()?; + Ok(()) + } +} + +fn to_confirmation_height_anchor(blockid: BlockId) -> ConfirmationHeightAnchor { + ConfirmationHeightAnchor { + anchor_block: blockid, + confirmation_height: blockid.height, + } } From bbbfb1342015d41a9aa7cc60a28afb8e298de3e3 Mon Sep 17 00:00:00 2001 From: Vladimir Fomene Date: Thu, 3 Aug 2023 12:13:47 +0300 Subject: [PATCH 4/5] feat: create CBF example with example_cli --- Cargo.toml | 1 + crates/bdk_cbf/src/lib.rs | 33 +++++---- example-crates/example_cbf/Cargo.toml | 2 +- example-crates/example_cbf/src/main.rs | 99 ++++++++++++++++++++++++++ 4 files changed, 119 insertions(+), 16 deletions(-) create mode 100644 example-crates/example_cbf/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index f76134b38..048cacc6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ members = [ "example-crates/wallet_electrum", "example-crates/wallet_esplora", "example-crates/wallet_esplora_async", + "example-crates/example_cbf", "nursery/tmp_plan", "nursery/coin_select" ] diff --git a/crates/bdk_cbf/src/lib.rs b/crates/bdk_cbf/src/lib.rs index 476178acc..64841bce3 100644 --- a/crates/bdk_cbf/src/lib.rs +++ b/crates/bdk_cbf/src/lib.rs @@ -1,14 +1,15 @@ use std::{net, thread}; +use core::fmt::Debug; use bdk_chain::keychain::DerivationAdditions; use nakamoto::client::network::Services; use nakamoto::client::Handle; use nakamoto::client::traits::Handle as HandleTrait; use nakamoto::client::{chan, Client, Config, Error, Event}; -use nakamoto::common::block::Height; use nakamoto::net::poll; pub use nakamoto::client::network::Network; +pub use nakamoto::common::block::Height; use bdk_chain::{ bitcoin::{Script, Transaction}, @@ -18,10 +19,13 @@ use bdk_chain::{ BlockId, ChainOracle, ConfirmationHeightAnchor, TxGraph, }; -use core::fmt::Debug; - type Reactor = poll::Reactor; +#[derive(Clone)] +pub struct CBFClient { + handle: Handle, +} + impl ChainOracle for CBFClient { type Error = nakamoto::client::Error; @@ -56,11 +60,6 @@ impl ChainOracle for CBFClient { } } -#[derive(Clone)] -pub struct CBFClient { - handle: Handle, -} - #[derive(Debug, Clone)] pub enum CBFUpdate { Synced { @@ -97,7 +96,11 @@ impl Iterator for CBFUpdateIterator { } impl CBFClient { - pub fn start_client(cfg: Config, peer_count: usize) -> Result { + pub fn start_client(network: Network, peer_count: usize) -> Result { + let cfg = Config { + network, + ..Default::default() + }; let client = Client::::new()?; let handle = client.handle(); @@ -112,7 +115,7 @@ impl CBFClient { Ok(Self { handle }) } - //create a function to watch + /// Given a list of scripts, start scanning the chain from the given height. pub fn start_scanning( &self, start_height: Height, @@ -123,7 +126,7 @@ impl CBFClient { Ok(()) } - // Watch for Block events that match the scripts we're interested in + /// Listen for nakamoto events that are relevant to scripts we are watching. pub fn watch_events(&self) -> Result { let events_chan = self.handle.events(); loop { @@ -158,7 +161,7 @@ impl CBFClient { } } - // Turns a CBFUpdate into a TxGraph update + /// Given a list of tuples of block and their transactions, create a TxGraph update. pub fn into_tx_graph_update( &self, block_txs: Vec<(BlockId, Vec)>, @@ -201,7 +204,7 @@ impl CBFClient { while let Some(keychains) = Self::check_stop_gap(stop_gap, &empty_scripts_counter) { keychains.iter().for_each(|k| { - /*let (_, _) =*/ indexed_tx_graph.index.set_lookahead(k, watch_per_keychain); + indexed_tx_graph.index.set_lookahead(k, watch_per_keychain); }); let mut spk_watchlist = BTreeMap::>::new(); @@ -244,7 +247,7 @@ impl CBFClient { for (k, scripts) in spk_watchlist.iter() { for script in scripts { let counter = empty_scripts_counter.get_mut(k).unwrap(); - if Self::is_script_in_udpate(script.clone(), &updates) { + if Self::is_script_in_udpates(script.clone(), &updates) { *counter = 0; } else { *counter += 1; @@ -262,7 +265,7 @@ impl CBFClient { Ok(additions) } - fn is_script_in_udpate(script: Script, updates: &Vec<(BlockId, Vec)>) -> bool { + fn is_script_in_udpates(script: Script, updates: &Vec<(BlockId, Vec)>) -> bool { for update in updates { for tx in update.1.iter() { for output in tx.output.iter() { diff --git a/example-crates/example_cbf/Cargo.toml b/example-crates/example_cbf/Cargo.toml index 1ed622fdb..fda610c6d 100644 --- a/example-crates/example_cbf/Cargo.toml +++ b/example-crates/example_cbf/Cargo.toml @@ -8,4 +8,4 @@ edition = "2021" [dependencies] bdk_cbf = { path = "../../crates/bdk_cbf"} bdk_chain = { path = "../../crates/chain"} -bdk_cli = { path = "../example_cli" } +example_cli = { path = "../example_cli" } diff --git a/example-crates/example_cbf/src/main.rs b/example-crates/example_cbf/src/main.rs new file mode 100644 index 000000000..4d1db9d2c --- /dev/null +++ b/example-crates/example_cbf/src/main.rs @@ -0,0 +1,99 @@ +use std::sync::Mutex; + +use bdk_cbf::{CBFClient, Network}; +use bdk_chain::{keychain::LocalChangeSet, ConfirmationHeightAnchor, IndexedTxGraph}; +use example_cli::{ + anyhow, + clap::{self, Args, Subcommand}, + Keychain, +}; + +const DB_MAGIC: &[u8] = b"bdk_example_cbf"; +const DB_PATH: &str = ".bdk_example_cbf.db"; + +type ChangeSet = LocalChangeSet; + +#[derive(Debug, Clone, Args)] +struct CBFArgs {} + +#[derive(Subcommand, Debug, Clone)] +enum CBFCommands { + Scan { + /// The block height to start scanning from + #[clap(long, default_value = "0")] + start_height: u64, + /// The block height to stop scanning at + #[clap(long, default_value = "5")] + stop_gap: u32, + /// Number of scripts to watch for every sync + #[clap(long, default_value = "1000")] + watchlist_size: u32, + }, +} + +fn main() -> anyhow::Result<()> { + let (args, keymap, index, db, init_changeset) = + example_cli::init::(DB_MAGIC, DB_PATH)?; + + let graph = Mutex::new({ + let mut graph = IndexedTxGraph::new(index); + graph.apply_additions(init_changeset.indexed_additions); + graph + }); + + let client = Mutex::new({ + let client = CBFClient::start_client(Network::Testnet, 1)?; + client + }); + + let cbf_cmd = match args.command { + example_cli::Commands::ChainSpecific(cbf_cmd) => cbf_cmd, + general_cmd => { + let res = example_cli::handle_commands( + &graph, + &db, + &client, + &keymap, + args.network, + |tx| { + client + .lock() + .unwrap() + .submit_transaction(tx.clone()) + .map_err(anyhow::Error::from) + }, + general_cmd, + ); + db.lock().unwrap().commit()?; + return res; + } + }; + + match cbf_cmd { + CBFCommands::Scan { + start_height, + stop_gap, + watchlist_size, + } => { + println!("Scanning from height {} to {}", start_height, stop_gap); + let indexed_additions = { + let mut graph = graph.lock().unwrap(); + client + .lock() + .unwrap() + .scan(watchlist_size, start_height, &mut graph, stop_gap)? + }; + + let curr_changeset = LocalChangeSet::from(indexed_additions); + + // stage changes to the database + let mut db = db.lock().unwrap(); + db.stage(curr_changeset); + db.commit()?; + + println!("commited to database!"); + } + } + + Ok(()) +} From 4afc15885ea36f6ff2facd0fd0a00ca66a99d7d7 Mon Sep 17 00:00:00 2001 From: Vladimir Fomene Date: Mon, 7 Aug 2023 19:48:52 +0300 Subject: [PATCH 5/5] update bdk_chain --- crates/bdk_cbf/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bdk_cbf/Cargo.toml b/crates/bdk_cbf/Cargo.toml index 8c92edc33..66c9e23bd 100644 --- a/crates/bdk_cbf/Cargo.toml +++ b/crates/bdk_cbf/Cargo.toml @@ -7,4 +7,4 @@ edition = "2021" [dependencies] nakamoto = "0.4.0" -bdk_chain = { path = "../chain", version = "0.4.0"} +bdk_chain = { path = "../chain", version = "0.5.0"}