From 748d3bd8b241b45d350768dd6887652e71c44813 Mon Sep 17 00:00:00 2001 From: Musab1258 Date: Tue, 29 Apr 2025 08:59:07 +0100 Subject: [PATCH 1/6] add an example using the BIP329 crate with bdk_wallet --- wallet/Cargo.toml | 6 + wallet/examples/bip329_example.rs | 249 ++++++++++++++++++++++++++++++ 2 files changed, 255 insertions(+) create mode 100644 wallet/examples/bip329_example.rs diff --git a/wallet/Cargo.toml b/wallet/Cargo.toml index 4d917c82..19286bbc 100644 --- a/wallet/Cargo.toml +++ b/wallet/Cargo.toml @@ -46,6 +46,7 @@ bdk_wallet = { path = ".", features = ["rusqlite", "file_store", "test-utils"] } bdk_file_store = { version = "0.18.1" } anyhow = "1" rand = "^0.8" +bip329 = "0.4.0" [package.metadata.docs.rs] all-features = true @@ -60,3 +61,8 @@ required-features = ["all-keys"] name = "miniscriptc" path = "examples/compiler.rs" required-features = ["compiler"] + +[[example]] +name = "bip329_example" +path = "examples/bip329_example.rs" +required-features = ["keys-bip39"] \ No newline at end of file diff --git a/wallet/examples/bip329_example.rs b/wallet/examples/bip329_example.rs new file mode 100644 index 00000000..87a5eb84 --- /dev/null +++ b/wallet/examples/bip329_example.rs @@ -0,0 +1,249 @@ +//! Example demonstrating how to use bdk_wallet with an external BIP-329 library +//! for managing wallet labels persisted in a separate file. + +extern crate anyhow; +extern crate bdk_wallet; +extern crate bip329; +extern crate bitcoin; +extern crate tempfile; + +use anyhow::{anyhow, Context, Result}; +use bdk_wallet::{ + descriptor, + keys::bip39::{Language, Mnemonic, WordCount}, + keys::GeneratableKey, + keys::{DerivableKey, DescriptorSecretKey, ExtendedKey, GeneratedKey}, + miniscript::{self, Descriptor, DescriptorPublicKey}, + KeychainKind, Wallet, +}; +use bip329::{AddressRecord, Label, LabelRef, Labels, TransactionRecord}; +use bitcoin::{address::NetworkUnchecked, bip32::DerivationPath, Address, Network, OutPoint, Txid}; +use std::{ + collections::{BTreeMap, HashMap, HashSet}, + io::ErrorKind, + ops::DerefMut, + path::PathBuf, + str::FromStr, +}; +use tempfile::tempdir; + +// --- Helper Functions --- +fn format_ref_str(item_ref: &LabelRef) -> String { + match item_ref { + LabelRef::Txid(txid) => format!("txid:{}", txid), + LabelRef::Address(_) => format!("addr:{}", item_ref), + LabelRef::Output(op) => format!("output:{}", op), + LabelRef::Input(op) => format!("input:{}", op), + LabelRef::PublicKey(pk_str) => format!("pubkey:{}", pk_str), + LabelRef::Xpub(xpub_str) => format!("xpub:{}", xpub_str), + } +} +fn format_bdk_addr_ref(addr: &Address) -> String { + format!("addr:{}", addr) +} +fn format_bdk_txid_ref(txid: Txid) -> String { + format!("txid:{}", txid) +} +fn format_bdk_outpoint_ref(op: OutPoint) -> String { + format!("output:{}", op) +} + +// --- Main Example Logic --- +fn main() -> Result<()> { + println!("--- BDK Wallet + BIP-329 Label Example ---"); + + let temp_dir = tempdir().context("Failed to create temporary directory")?; + let label_file_path: PathBuf = temp_dir.path().join("bdk_bip329_example_labels.jsonl"); + println!("Using temporary label file: {}", label_file_path.display()); + + let network = Network::Regtest; + + // 1. Generate Keys and Descriptors Programmatically + println!("Generating keys and descriptors..."); + let mnemonic: GeneratedKey<_, miniscript::Segwitv0> = + Mnemonic::generate((WordCount::Words12, Language::English)) + .map_err(|_| anyhow!("Mnemonic generation failed"))?; + let mnemonic_words = mnemonic.to_string(); + println!("Generated Mnemonic: {}", mnemonic_words); + let mnemonic = Mnemonic::parse_in(Language::English, mnemonic_words)?; + let xkey: ExtendedKey = mnemonic.into_extended_key()?; + let master_xprv = xkey + .into_xprv(network) + .ok_or_else(|| anyhow!("Could not derive xprv for network {}", network))?; + let external_path = DerivationPath::from_str("m/84h/1h/0h/0")?; + let internal_path = DerivationPath::from_str("m/84h/1h/0h/1")?; + + // CORRECTED Type Annotations: + let (external_descriptor, _ext_keymap, _ext_networks): ( + Descriptor, + BTreeMap, + HashSet, + ) = descriptor!(wpkh((master_xprv.clone(), external_path)))?; + + let (internal_descriptor, _int_keymap, _int_networks): ( + Descriptor, + BTreeMap, + HashSet, + ) = descriptor!(wpkh((master_xprv, internal_path)))?; + + let external_descriptor_str = external_descriptor.to_string(); + let internal_descriptor_str = internal_descriptor.to_string(); + + println!("External Descriptor: {}", external_descriptor_str); + println!("Internal Descriptor: {}", internal_descriptor_str); + + // 2. Create the BDK Wallet + let mut wallet = Wallet::create(external_descriptor_str, internal_descriptor_str) + .network(network) + .create_wallet_no_persist() + .context("Failed to create wallet using generated descriptors")?; + println!("Wallet created successfully."); + + // Get example items + let address1 = wallet.next_unused_address(KeychainKind::External); + let address2 = wallet.next_unused_address(KeychainKind::External); + let dummy_txid = + Txid::from_str("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16")?; + let dummy_outpoint = OutPoint::new(dummy_txid, 0); + println!( + "Wallet Addresses: Index {} -> {}", + address1.index, address1.address + ); + println!("Index {} -> {}", address2.index, address2.address); + println!("Dummy TXID: {}", dummy_txid); + println!("Dummy OutPoint: {}", dummy_outpoint); + + // 3. Load Labels from temporary file (or create empty) + println!("\n--- Loading Labels ---"); + // Use the PathBuf variable directly (borrowed) + let mut labels = match Labels::try_from_file(&label_file_path) { + Ok(loaded_labels) => { + println!( + "Loaded {} labels from temporary file '{}'.", // Updated message + loaded_labels.len(), + label_file_path.display() + ); + loaded_labels + } + Err(bip329::error::ParseError::FileReadError(io_err)) + if io_err.kind() == ErrorKind::NotFound => + { + println!( + "Temporary label file '{}' not found, starting empty.", // Updated message + label_file_path.display() + ); + Labels::default() + } + Err(e) => { + return Err(anyhow!( + "Failed to load labels from {}: {}", + label_file_path.display(), + e + )) + } + }; + + // Build lookup map + let mut label_lookup: HashMap = HashMap::new(); + for label_entry in labels.iter() { + if let Some(label_text) = label_entry.label() { + let ref_str = format_ref_str(&label_entry.ref_()); + label_lookup.insert(ref_str, label_text.to_string()); + } + } + + // 4. Correlate Wallet Data with Labels + println!("\n--- Current Labels for Wallet Items ---"); + let items_to_lookup: Vec<(&str, String)> = vec![ + ("Address 1", format_bdk_addr_ref(&address1.address)), + ("Address 2", format_bdk_addr_ref(&address2.address)), + ("Dummy Tx", format_bdk_txid_ref(dummy_txid)), + ("Dummy UTXO", format_bdk_outpoint_ref(dummy_outpoint)), + ]; + + for (item_desc, item_ref_str) in &items_to_lookup { + match label_lookup.get(item_ref_str) { + Some(label_text) => println!("{} ({}): {}", item_desc, item_ref_str, label_text), + None => println!("{} ({}): [No Label]", item_desc, item_ref_str), + } + } + + // 5. Add/Update Labels in Memory + println!("\n--- Adding/Updating Labels ---"); + let addr1_ref_str = format_bdk_addr_ref(&address1.address); + let new_addr1_label = "Primary Receiving Address"; + let labels_vec = labels.deref_mut(); + match labels_vec + .iter_mut() + .find(|l| format_ref_str(&l.ref_()) == addr1_ref_str) + { + Some(label_entry) => { + println!("Updating label for {}", addr1_ref_str); + match label_entry { + Label::Address(record) => record.label = Some(new_addr1_label.to_string()), + _ => println!( + "Warning: Found ref string {} but not Address label?", + addr1_ref_str + ), + } + } + None => { + println!("Adding new label for {}", addr1_ref_str); + let addr_unchecked: Address = + Address::from_str(&address1.address.to_string())? + .require_network(network)? + .into_unchecked(); + labels_vec.push(Label::Address(AddressRecord { + ref_: addr_unchecked, + label: Some(new_addr1_label.to_string()), + })); + } + } + let tx_ref_str = format_bdk_txid_ref(dummy_txid); + if !labels_vec + .iter() + .any(|l| format_ref_str(&l.ref_()) == tx_ref_str) + { + println!("Adding new label for {}", tx_ref_str); + labels_vec.push(Label::Transaction(TransactionRecord { + ref_: dummy_txid, + label: Some("Simulated Incoming TX".to_string()), + origin: None, + })); + } + + // 6. Export and Save Labels to temporary file + println!("\n--- Exporting and Saving Labels ---"); + // Use the PathBuf variable directly (borrowed) + match labels.export_to_file(&label_file_path) { + Ok(_) => println!( + "Labels successfully saved to temporary file '{}'", // Updated message + label_file_path.display() + ), + Err(e) => eprintln!("Error saving labels: {}", e), + } + + // 7. Demonstrate reading the temporary file back + println!("\n--- Reading Labels Back from Temporary File ---"); // Updated message + // Use the PathBuf variable directly (borrowed) + match Labels::try_from_file(&label_file_path) { + Ok(reloaded_labels) => { + println!("Successfully reloaded {} labels:", reloaded_labels.len()); + for label_entry in reloaded_labels.iter() { + if let Some(label_text) = label_entry.label() { + println!( + " {} -> {}", + format_ref_str(&label_entry.ref_()), + label_text + ); + } + } + } + Err(e) => eprintln!("Error reloading labels: {}", e), + } + + println!("\n--- Example Finished ---"); + // The `temp_dir` variable goes out of scope here, automatically deleting the directory + // and the label file inside it. + Ok(()) +} From cc13d6078884f4b0ca1d1454f981ea501a132c91 Mon Sep 17 00:00:00 2001 From: Musab1258 Date: Tue, 29 Apr 2025 13:49:27 +0100 Subject: [PATCH 2/6] fix clippy errors --- wallet/Cargo.toml | 2 + wallet/examples/bip329_example.rs | 132 ++++++++++++++++-------------- 2 files changed, 73 insertions(+), 61 deletions(-) diff --git a/wallet/Cargo.toml b/wallet/Cargo.toml index 19286bbc..f657fe6f 100644 --- a/wallet/Cargo.toml +++ b/wallet/Cargo.toml @@ -47,6 +47,8 @@ bdk_file_store = { version = "0.18.1" } anyhow = "1" rand = "^0.8" bip329 = "0.4.0" +log = "0.4" +env_logger = "0.11" [package.metadata.docs.rs] all-features = true diff --git a/wallet/examples/bip329_example.rs b/wallet/examples/bip329_example.rs index 87a5eb84..e6cca580 100644 --- a/wallet/examples/bip329_example.rs +++ b/wallet/examples/bip329_example.rs @@ -5,6 +5,8 @@ extern crate anyhow; extern crate bdk_wallet; extern crate bip329; extern crate bitcoin; +extern crate env_logger; +extern crate log; extern crate tempfile; use anyhow::{anyhow, Context, Result}; @@ -14,24 +16,28 @@ use bdk_wallet::{ keys::GeneratableKey, keys::{DerivableKey, DescriptorSecretKey, ExtendedKey, GeneratedKey}, miniscript::{self, Descriptor, DescriptorPublicKey}, - KeychainKind, Wallet, + AddressInfo, + KeychainKind, + Wallet, // Added AddressInfo }; use bip329::{AddressRecord, Label, LabelRef, Labels, TransactionRecord}; use bitcoin::{address::NetworkUnchecked, bip32::DerivationPath, Address, Network, OutPoint, Txid}; +use log::{error, info, warn}; use std::{ collections::{BTreeMap, HashMap, HashSet}, io::ErrorKind, ops::DerefMut, - path::PathBuf, + // Removed path::PathBuf - no longer needed explicitly str::FromStr, }; use tempfile::tempdir; // --- Helper Functions --- fn format_ref_str(item_ref: &LabelRef) -> String { + // Use the existing Display impl from bip329::LabelRef which handles assume_checked() match item_ref { LabelRef::Txid(txid) => format!("txid:{}", txid), - LabelRef::Address(_) => format!("addr:{}", item_ref), + LabelRef::Address(_) => format!("addr:{}", item_ref), // Rely on LabelRef's Display LabelRef::Output(op) => format!("output:{}", op), LabelRef::Input(op) => format!("input:{}", op), LabelRef::PublicKey(pk_str) => format!("pubkey:{}", pk_str), @@ -50,21 +56,24 @@ fn format_bdk_outpoint_ref(op: OutPoint) -> String { // --- Main Example Logic --- fn main() -> Result<()> { - println!("--- BDK Wallet + BIP-329 Label Example ---"); + // Initialize logger - Output controlled by RUST_LOG env var + env_logger::init(); + + info!("--- BDK Wallet + BIP-329 Label Example ---"); let temp_dir = tempdir().context("Failed to create temporary directory")?; - let label_file_path: PathBuf = temp_dir.path().join("bdk_bip329_example_labels.jsonl"); - println!("Using temporary label file: {}", label_file_path.display()); + let label_file_path = temp_dir.path().join("bdk_bip329_example_labels.jsonl"); // PathBuf inferred + info!("Using temporary label file: {}", label_file_path.display()); let network = Network::Regtest; // 1. Generate Keys and Descriptors Programmatically - println!("Generating keys and descriptors..."); + info!("Generating keys and descriptors..."); let mnemonic: GeneratedKey<_, miniscript::Segwitv0> = Mnemonic::generate((WordCount::Words12, Language::English)) .map_err(|_| anyhow!("Mnemonic generation failed"))?; let mnemonic_words = mnemonic.to_string(); - println!("Generated Mnemonic: {}", mnemonic_words); + info!("Generated Mnemonic: {}", mnemonic_words); let mnemonic = Mnemonic::parse_in(Language::English, mnemonic_words)?; let xkey: ExtendedKey = mnemonic.into_extended_key()?; let master_xprv = xkey @@ -73,7 +82,6 @@ fn main() -> Result<()> { let external_path = DerivationPath::from_str("m/84h/1h/0h/0")?; let internal_path = DerivationPath::from_str("m/84h/1h/0h/1")?; - // CORRECTED Type Annotations: let (external_descriptor, _ext_keymap, _ext_networks): ( Descriptor, BTreeMap, @@ -89,37 +97,41 @@ fn main() -> Result<()> { let external_descriptor_str = external_descriptor.to_string(); let internal_descriptor_str = internal_descriptor.to_string(); - println!("External Descriptor: {}", external_descriptor_str); - println!("Internal Descriptor: {}", internal_descriptor_str); + info!("External Descriptor: {}", external_descriptor_str); + info!("Internal Descriptor: {}", internal_descriptor_str); - // 2. Create the BDK Wallet - let mut wallet = Wallet::create(external_descriptor_str, internal_descriptor_str) + // 2. Create the BDK Wallet (Corrected: Pass owned Strings, removed mut) + let wallet = Wallet::create(external_descriptor_str, internal_descriptor_str) // Pass String, not &String, removed mut .network(network) .create_wallet_no_persist() .context("Failed to create wallet using generated descriptors")?; - println!("Wallet created successfully."); + info!("Wallet created successfully."); + + // Get example items using peek_address + let address0: AddressInfo = wallet.peek_address(KeychainKind::External, 0); + let address1: AddressInfo = wallet.peek_address(KeychainKind::External, 1); - // Get example items - let address1 = wallet.next_unused_address(KeychainKind::External); - let address2 = wallet.next_unused_address(KeychainKind::External); let dummy_txid = Txid::from_str("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16")?; let dummy_outpoint = OutPoint::new(dummy_txid, 0); - println!( + info!( "Wallet Addresses: Index {} -> {}", + address0.index, address0.address + ); + info!( + " Index {} -> {}", address1.index, address1.address ); - println!("Index {} -> {}", address2.index, address2.address); - println!("Dummy TXID: {}", dummy_txid); - println!("Dummy OutPoint: {}", dummy_outpoint); + info!("Dummy TXID: {}", dummy_txid); + info!("Dummy OutPoint: {}", dummy_outpoint); // 3. Load Labels from temporary file (or create empty) - println!("\n--- Loading Labels ---"); - // Use the PathBuf variable directly (borrowed) + info!("\n--- Loading Labels ---"); + // Pass label_file_path by reference let mut labels = match Labels::try_from_file(&label_file_path) { Ok(loaded_labels) => { - println!( - "Loaded {} labels from temporary file '{}'.", // Updated message + info!( + "Loaded {} labels from temporary file '{}'.", loaded_labels.len(), label_file_path.display() ); @@ -128,8 +140,8 @@ fn main() -> Result<()> { Err(bip329::error::ParseError::FileReadError(io_err)) if io_err.kind() == ErrorKind::NotFound => { - println!( - "Temporary label file '{}' not found, starting empty.", // Updated message + info!( + "Temporary label file '{}' not found, starting empty.", label_file_path.display() ); Labels::default() @@ -139,7 +151,7 @@ fn main() -> Result<()> { "Failed to load labels from {}: {}", label_file_path.display(), e - )) + )); } }; @@ -153,49 +165,49 @@ fn main() -> Result<()> { } // 4. Correlate Wallet Data with Labels - println!("\n--- Current Labels for Wallet Items ---"); + info!("\n--- Current Labels for Wallet Items ---"); + // Use address0 and address1 correctly let items_to_lookup: Vec<(&str, String)> = vec![ - ("Address 1", format_bdk_addr_ref(&address1.address)), - ("Address 2", format_bdk_addr_ref(&address2.address)), + ("Address 0", format_bdk_addr_ref(&address0.address)), // Use address0 + ("Address 1", format_bdk_addr_ref(&address1.address)), // Use address1 ("Dummy Tx", format_bdk_txid_ref(dummy_txid)), ("Dummy UTXO", format_bdk_outpoint_ref(dummy_outpoint)), ]; - for (item_desc, item_ref_str) in &items_to_lookup { match label_lookup.get(item_ref_str) { - Some(label_text) => println!("{} ({}): {}", item_desc, item_ref_str, label_text), - None => println!("{} ({}): [No Label]", item_desc, item_ref_str), + Some(label_text) => info!("{} ({}): {}", item_desc, item_ref_str, label_text), + None => info!("{} ({}): [No Label]", item_desc, item_ref_str), } } // 5. Add/Update Labels in Memory - println!("\n--- Adding/Updating Labels ---"); - let addr1_ref_str = format_bdk_addr_ref(&address1.address); - let new_addr1_label = "Primary Receiving Address"; + info!("\n--- Adding/Updating Labels ---"); + // Use address0 for the label update logic + let addr0_ref_str = format_bdk_addr_ref(&address0.address); + let new_addr0_label = "Primary Receiving Address (Index 0)"; let labels_vec = labels.deref_mut(); match labels_vec .iter_mut() - .find(|l| format_ref_str(&l.ref_()) == addr1_ref_str) + .find(|l| format_ref_str(&l.ref_()) == addr0_ref_str) // Use addr0_ref_str { Some(label_entry) => { - println!("Updating label for {}", addr1_ref_str); + info!("Updating label for {}", addr0_ref_str); match label_entry { - Label::Address(record) => record.label = Some(new_addr1_label.to_string()), - _ => println!( + Label::Address(record) => record.label = Some(new_addr0_label.to_string()), // Use new_addr0_label + _ => warn!( "Warning: Found ref string {} but not Address label?", - addr1_ref_str + addr0_ref_str ), } } None => { - println!("Adding new label for {}", addr1_ref_str); + info!("Adding new label for {}", addr0_ref_str); + // Use address0 for conversion let addr_unchecked: Address = - Address::from_str(&address1.address.to_string())? - .require_network(network)? - .into_unchecked(); + Address::from_str(&address0.address.to_string())?.into_unchecked(); labels_vec.push(Label::Address(AddressRecord { ref_: addr_unchecked, - label: Some(new_addr1_label.to_string()), + label: Some(new_addr0_label.to_string()), // Use new_addr0_label })); } } @@ -204,7 +216,7 @@ fn main() -> Result<()> { .iter() .any(|l| format_ref_str(&l.ref_()) == tx_ref_str) { - println!("Adding new label for {}", tx_ref_str); + info!("Adding new label for {}", tx_ref_str); labels_vec.push(Label::Transaction(TransactionRecord { ref_: dummy_txid, label: Some("Simulated Incoming TX".to_string()), @@ -213,25 +225,25 @@ fn main() -> Result<()> { } // 6. Export and Save Labels to temporary file - println!("\n--- Exporting and Saving Labels ---"); - // Use the PathBuf variable directly (borrowed) + info!("\n--- Exporting and Saving Labels ---"); match labels.export_to_file(&label_file_path) { - Ok(_) => println!( - "Labels successfully saved to temporary file '{}'", // Updated message + // Pass &PathBuf ref + Ok(_) => info!( + "Labels successfully saved to temporary file '{}'", label_file_path.display() ), - Err(e) => eprintln!("Error saving labels: {}", e), + Err(e) => error!("Error saving labels: {}", e), } // 7. Demonstrate reading the temporary file back - println!("\n--- Reading Labels Back from Temporary File ---"); // Updated message - // Use the PathBuf variable directly (borrowed) + info!("\n--- Reading Labels Back from Temporary File ---"); match Labels::try_from_file(&label_file_path) { + // Pass &PathBuf ref Ok(reloaded_labels) => { - println!("Successfully reloaded {} labels:", reloaded_labels.len()); + info!("Successfully reloaded {} labels:", reloaded_labels.len()); for label_entry in reloaded_labels.iter() { if let Some(label_text) = label_entry.label() { - println!( + info!( " {} -> {}", format_ref_str(&label_entry.ref_()), label_text @@ -239,11 +251,9 @@ fn main() -> Result<()> { } } } - Err(e) => eprintln!("Error reloading labels: {}", e), + Err(e) => error!("Error reloading labels: {}", e), } - println!("\n--- Example Finished ---"); - // The `temp_dir` variable goes out of scope here, automatically deleting the directory - // and the label file inside it. + info!("\n--- Example Finished ---"); Ok(()) } From 06bb539108af61d3ee125fcd8adbed970916beb4 Mon Sep 17 00:00:00 2001 From: Musab1258 Date: Tue, 29 Apr 2025 16:43:15 +0100 Subject: [PATCH 3/6] fix clippy and build errors --- wallet/Cargo.toml | 2 +- wallet/examples/bip329_example.rs | 43 ++++++++++--------------------- 2 files changed, 14 insertions(+), 31 deletions(-) diff --git a/wallet/Cargo.toml b/wallet/Cargo.toml index f657fe6f..9780867e 100644 --- a/wallet/Cargo.toml +++ b/wallet/Cargo.toml @@ -48,7 +48,7 @@ anyhow = "1" rand = "^0.8" bip329 = "0.4.0" log = "0.4" -env_logger = "0.11" +env_logger = "0.11.0" [package.metadata.docs.rs] all-features = true diff --git a/wallet/examples/bip329_example.rs b/wallet/examples/bip329_example.rs index e6cca580..f064046c 100644 --- a/wallet/examples/bip329_example.rs +++ b/wallet/examples/bip329_example.rs @@ -16,9 +16,7 @@ use bdk_wallet::{ keys::GeneratableKey, keys::{DerivableKey, DescriptorSecretKey, ExtendedKey, GeneratedKey}, miniscript::{self, Descriptor, DescriptorPublicKey}, - AddressInfo, - KeychainKind, - Wallet, // Added AddressInfo + AddressInfo, KeychainKind, Wallet, }; use bip329::{AddressRecord, Label, LabelRef, Labels, TransactionRecord}; use bitcoin::{address::NetworkUnchecked, bip32::DerivationPath, Address, Network, OutPoint, Txid}; @@ -27,17 +25,15 @@ use std::{ collections::{BTreeMap, HashMap, HashSet}, io::ErrorKind, ops::DerefMut, - // Removed path::PathBuf - no longer needed explicitly str::FromStr, }; use tempfile::tempdir; // --- Helper Functions --- fn format_ref_str(item_ref: &LabelRef) -> String { - // Use the existing Display impl from bip329::LabelRef which handles assume_checked() match item_ref { LabelRef::Txid(txid) => format!("txid:{}", txid), - LabelRef::Address(_) => format!("addr:{}", item_ref), // Rely on LabelRef's Display + LabelRef::Address(_) => format!("addr:{}", item_ref), LabelRef::Output(op) => format!("output:{}", op), LabelRef::Input(op) => format!("input:{}", op), LabelRef::PublicKey(pk_str) => format!("pubkey:{}", pk_str), @@ -62,7 +58,7 @@ fn main() -> Result<()> { info!("--- BDK Wallet + BIP-329 Label Example ---"); let temp_dir = tempdir().context("Failed to create temporary directory")?; - let label_file_path = temp_dir.path().join("bdk_bip329_example_labels.jsonl"); // PathBuf inferred + let label_file_path = temp_dir.path().join("bdk_bip329_example_labels.jsonl"); info!("Using temporary label file: {}", label_file_path.display()); let network = Network::Regtest; @@ -86,7 +82,7 @@ fn main() -> Result<()> { Descriptor, BTreeMap, HashSet, - ) = descriptor!(wpkh((master_xprv.clone(), external_path)))?; + ) = descriptor!(wpkh((master_xprv, external_path)))?; let (internal_descriptor, _int_keymap, _int_networks): ( Descriptor, @@ -100,8 +96,8 @@ fn main() -> Result<()> { info!("External Descriptor: {}", external_descriptor_str); info!("Internal Descriptor: {}", internal_descriptor_str); - // 2. Create the BDK Wallet (Corrected: Pass owned Strings, removed mut) - let wallet = Wallet::create(external_descriptor_str, internal_descriptor_str) // Pass String, not &String, removed mut + // 2. Create the BDK Wallet + let wallet = Wallet::create(external_descriptor_str, internal_descriptor_str) .network(network) .create_wallet_no_persist() .context("Failed to create wallet using generated descriptors")?; @@ -118,16 +114,12 @@ fn main() -> Result<()> { "Wallet Addresses: Index {} -> {}", address0.index, address0.address ); - info!( - " Index {} -> {}", - address1.index, address1.address - ); + info!("Index {} -> {}", address1.index, address1.address); info!("Dummy TXID: {}", dummy_txid); info!("Dummy OutPoint: {}", dummy_outpoint); // 3. Load Labels from temporary file (or create empty) info!("\n--- Loading Labels ---"); - // Pass label_file_path by reference let mut labels = match Labels::try_from_file(&label_file_path) { Ok(loaded_labels) => { info!( @@ -166,10 +158,9 @@ fn main() -> Result<()> { // 4. Correlate Wallet Data with Labels info!("\n--- Current Labels for Wallet Items ---"); - // Use address0 and address1 correctly let items_to_lookup: Vec<(&str, String)> = vec![ - ("Address 0", format_bdk_addr_ref(&address0.address)), // Use address0 - ("Address 1", format_bdk_addr_ref(&address1.address)), // Use address1 + ("Address 0", format_bdk_addr_ref(&address0.address)), + ("Address 1", format_bdk_addr_ref(&address1.address)), ("Dummy Tx", format_bdk_txid_ref(dummy_txid)), ("Dummy UTXO", format_bdk_outpoint_ref(dummy_outpoint)), ]; @@ -182,18 +173,17 @@ fn main() -> Result<()> { // 5. Add/Update Labels in Memory info!("\n--- Adding/Updating Labels ---"); - // Use address0 for the label update logic let addr0_ref_str = format_bdk_addr_ref(&address0.address); let new_addr0_label = "Primary Receiving Address (Index 0)"; let labels_vec = labels.deref_mut(); match labels_vec .iter_mut() - .find(|l| format_ref_str(&l.ref_()) == addr0_ref_str) // Use addr0_ref_str + .find(|l| format_ref_str(&l.ref_()) == addr0_ref_str) { Some(label_entry) => { info!("Updating label for {}", addr0_ref_str); match label_entry { - Label::Address(record) => record.label = Some(new_addr0_label.to_string()), // Use new_addr0_label + Label::Address(record) => record.label = Some(new_addr0_label.to_string()), _ => warn!( "Warning: Found ref string {} but not Address label?", addr0_ref_str @@ -202,12 +192,11 @@ fn main() -> Result<()> { } None => { info!("Adding new label for {}", addr0_ref_str); - // Use address0 for conversion let addr_unchecked: Address = Address::from_str(&address0.address.to_string())?.into_unchecked(); labels_vec.push(Label::Address(AddressRecord { ref_: addr_unchecked, - label: Some(new_addr0_label.to_string()), // Use new_addr0_label + label: Some(new_addr0_label.to_string()), })); } } @@ -227,7 +216,6 @@ fn main() -> Result<()> { // 6. Export and Save Labels to temporary file info!("\n--- Exporting and Saving Labels ---"); match labels.export_to_file(&label_file_path) { - // Pass &PathBuf ref Ok(_) => info!( "Labels successfully saved to temporary file '{}'", label_file_path.display() @@ -238,16 +226,11 @@ fn main() -> Result<()> { // 7. Demonstrate reading the temporary file back info!("\n--- Reading Labels Back from Temporary File ---"); match Labels::try_from_file(&label_file_path) { - // Pass &PathBuf ref Ok(reloaded_labels) => { info!("Successfully reloaded {} labels:", reloaded_labels.len()); for label_entry in reloaded_labels.iter() { if let Some(label_text) = label_entry.label() { - info!( - " {} -> {}", - format_ref_str(&label_entry.ref_()), - label_text - ); + info!("{} -> {}", format_ref_str(&label_entry.ref_()), label_text); } } } From 93b4a9f00f47f6ad235feea5eb856b0dee1410f3 Mon Sep 17 00:00:00 2001 From: Musab1258 Date: Tue, 29 Apr 2025 17:50:47 +0100 Subject: [PATCH 4/6] fix build errors --- wallet/Cargo.toml | 1 - wallet/examples/bip329_example.rs | 4 ---- 2 files changed, 5 deletions(-) diff --git a/wallet/Cargo.toml b/wallet/Cargo.toml index 9780867e..14685bdc 100644 --- a/wallet/Cargo.toml +++ b/wallet/Cargo.toml @@ -48,7 +48,6 @@ anyhow = "1" rand = "^0.8" bip329 = "0.4.0" log = "0.4" -env_logger = "0.11.0" [package.metadata.docs.rs] all-features = true diff --git a/wallet/examples/bip329_example.rs b/wallet/examples/bip329_example.rs index f064046c..5e849040 100644 --- a/wallet/examples/bip329_example.rs +++ b/wallet/examples/bip329_example.rs @@ -5,7 +5,6 @@ extern crate anyhow; extern crate bdk_wallet; extern crate bip329; extern crate bitcoin; -extern crate env_logger; extern crate log; extern crate tempfile; @@ -52,9 +51,6 @@ fn format_bdk_outpoint_ref(op: OutPoint) -> String { // --- Main Example Logic --- fn main() -> Result<()> { - // Initialize logger - Output controlled by RUST_LOG env var - env_logger::init(); - info!("--- BDK Wallet + BIP-329 Label Example ---"); let temp_dir = tempdir().context("Failed to create temporary directory")?; From 96af86c7779eec183b7847d82d68f9a120928d66 Mon Sep 17 00:00:00 2001 From: Musab1258 Date: Thu, 1 May 2025 09:40:26 +0100 Subject: [PATCH 5/6] update code to use println! instead of log --- wallet/Cargo.toml | 1 - wallet/examples/bip329_example.rs | 63 +++++++++++++++---------------- 2 files changed, 31 insertions(+), 33 deletions(-) diff --git a/wallet/Cargo.toml b/wallet/Cargo.toml index 14685bdc..19286bbc 100644 --- a/wallet/Cargo.toml +++ b/wallet/Cargo.toml @@ -47,7 +47,6 @@ bdk_file_store = { version = "0.18.1" } anyhow = "1" rand = "^0.8" bip329 = "0.4.0" -log = "0.4" [package.metadata.docs.rs] all-features = true diff --git a/wallet/examples/bip329_example.rs b/wallet/examples/bip329_example.rs index 5e849040..bb434443 100644 --- a/wallet/examples/bip329_example.rs +++ b/wallet/examples/bip329_example.rs @@ -5,7 +5,6 @@ extern crate anyhow; extern crate bdk_wallet; extern crate bip329; extern crate bitcoin; -extern crate log; extern crate tempfile; use anyhow::{anyhow, Context, Result}; @@ -19,7 +18,6 @@ use bdk_wallet::{ }; use bip329::{AddressRecord, Label, LabelRef, Labels, TransactionRecord}; use bitcoin::{address::NetworkUnchecked, bip32::DerivationPath, Address, Network, OutPoint, Txid}; -use log::{error, info, warn}; use std::{ collections::{BTreeMap, HashMap, HashSet}, io::ErrorKind, @@ -50,22 +48,23 @@ fn format_bdk_outpoint_ref(op: OutPoint) -> String { } // --- Main Example Logic --- +#[allow(clippy::print_stdout)] fn main() -> Result<()> { - info!("--- BDK Wallet + BIP-329 Label Example ---"); + println!("--- BDK Wallet + BIP-329 Label Example ---"); let temp_dir = tempdir().context("Failed to create temporary directory")?; let label_file_path = temp_dir.path().join("bdk_bip329_example_labels.jsonl"); - info!("Using temporary label file: {}", label_file_path.display()); + println!("Using temporary label file: {}", label_file_path.display()); let network = Network::Regtest; // 1. Generate Keys and Descriptors Programmatically - info!("Generating keys and descriptors..."); + println!("Generating keys and descriptors..."); let mnemonic: GeneratedKey<_, miniscript::Segwitv0> = Mnemonic::generate((WordCount::Words12, Language::English)) .map_err(|_| anyhow!("Mnemonic generation failed"))?; let mnemonic_words = mnemonic.to_string(); - info!("Generated Mnemonic: {}", mnemonic_words); + println!("Generated Mnemonic: {}", mnemonic_words); let mnemonic = Mnemonic::parse_in(Language::English, mnemonic_words)?; let xkey: ExtendedKey = mnemonic.into_extended_key()?; let master_xprv = xkey @@ -89,15 +88,15 @@ fn main() -> Result<()> { let external_descriptor_str = external_descriptor.to_string(); let internal_descriptor_str = internal_descriptor.to_string(); - info!("External Descriptor: {}", external_descriptor_str); - info!("Internal Descriptor: {}", internal_descriptor_str); + println!("External Descriptor: {}", external_descriptor_str); + println!("Internal Descriptor: {}", internal_descriptor_str); // 2. Create the BDK Wallet let wallet = Wallet::create(external_descriptor_str, internal_descriptor_str) .network(network) .create_wallet_no_persist() .context("Failed to create wallet using generated descriptors")?; - info!("Wallet created successfully."); + println!("Wallet created successfully."); // Get example items using peek_address let address0: AddressInfo = wallet.peek_address(KeychainKind::External, 0); @@ -106,19 +105,19 @@ fn main() -> Result<()> { let dummy_txid = Txid::from_str("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16")?; let dummy_outpoint = OutPoint::new(dummy_txid, 0); - info!( + println!( "Wallet Addresses: Index {} -> {}", address0.index, address0.address ); - info!("Index {} -> {}", address1.index, address1.address); - info!("Dummy TXID: {}", dummy_txid); - info!("Dummy OutPoint: {}", dummy_outpoint); + println!("Index {} -> {}", address1.index, address1.address); + println!("Dummy TXID: {}", dummy_txid); + println!("Dummy OutPoint: {}", dummy_outpoint); // 3. Load Labels from temporary file (or create empty) - info!("\n--- Loading Labels ---"); + println!("\n--- Loading Labels ---"); let mut labels = match Labels::try_from_file(&label_file_path) { Ok(loaded_labels) => { - info!( + println!( "Loaded {} labels from temporary file '{}'.", loaded_labels.len(), label_file_path.display() @@ -128,7 +127,7 @@ fn main() -> Result<()> { Err(bip329::error::ParseError::FileReadError(io_err)) if io_err.kind() == ErrorKind::NotFound => { - info!( + println!( "Temporary label file '{}' not found, starting empty.", label_file_path.display() ); @@ -153,7 +152,7 @@ fn main() -> Result<()> { } // 4. Correlate Wallet Data with Labels - info!("\n--- Current Labels for Wallet Items ---"); + println!("\n--- Current Labels for Wallet Items ---"); let items_to_lookup: Vec<(&str, String)> = vec![ ("Address 0", format_bdk_addr_ref(&address0.address)), ("Address 1", format_bdk_addr_ref(&address1.address)), @@ -162,13 +161,13 @@ fn main() -> Result<()> { ]; for (item_desc, item_ref_str) in &items_to_lookup { match label_lookup.get(item_ref_str) { - Some(label_text) => info!("{} ({}): {}", item_desc, item_ref_str, label_text), - None => info!("{} ({}): [No Label]", item_desc, item_ref_str), + Some(label_text) => println!("{} ({}): {}", item_desc, item_ref_str, label_text), + None => println!("{} ({}): [No Label]", item_desc, item_ref_str), } } // 5. Add/Update Labels in Memory - info!("\n--- Adding/Updating Labels ---"); + println!("\n--- Adding/Updating Labels ---"); let addr0_ref_str = format_bdk_addr_ref(&address0.address); let new_addr0_label = "Primary Receiving Address (Index 0)"; let labels_vec = labels.deref_mut(); @@ -177,17 +176,17 @@ fn main() -> Result<()> { .find(|l| format_ref_str(&l.ref_()) == addr0_ref_str) { Some(label_entry) => { - info!("Updating label for {}", addr0_ref_str); + println!("Updating label for {}", addr0_ref_str); match label_entry { Label::Address(record) => record.label = Some(new_addr0_label.to_string()), - _ => warn!( + _ => eprintln!( "Warning: Found ref string {} but not Address label?", addr0_ref_str ), } } None => { - info!("Adding new label for {}", addr0_ref_str); + println!("Adding new label for {}", addr0_ref_str); let addr_unchecked: Address = Address::from_str(&address0.address.to_string())?.into_unchecked(); labels_vec.push(Label::Address(AddressRecord { @@ -201,7 +200,7 @@ fn main() -> Result<()> { .iter() .any(|l| format_ref_str(&l.ref_()) == tx_ref_str) { - info!("Adding new label for {}", tx_ref_str); + println!("Adding new label for {}", tx_ref_str); labels_vec.push(Label::Transaction(TransactionRecord { ref_: dummy_txid, label: Some("Simulated Incoming TX".to_string()), @@ -210,29 +209,29 @@ fn main() -> Result<()> { } // 6. Export and Save Labels to temporary file - info!("\n--- Exporting and Saving Labels ---"); + println!("\n--- Exporting and Saving Labels ---"); match labels.export_to_file(&label_file_path) { - Ok(_) => info!( + Ok(_) => println!( "Labels successfully saved to temporary file '{}'", label_file_path.display() ), - Err(e) => error!("Error saving labels: {}", e), + Err(e) => eprintln!("Error saving labels: {}", e), } // 7. Demonstrate reading the temporary file back - info!("\n--- Reading Labels Back from Temporary File ---"); + println!("\n--- Reading Labels Back from Temporary File ---"); match Labels::try_from_file(&label_file_path) { Ok(reloaded_labels) => { - info!("Successfully reloaded {} labels:", reloaded_labels.len()); + println!("Successfully reloaded {} labels:", reloaded_labels.len()); for label_entry in reloaded_labels.iter() { if let Some(label_text) = label_entry.label() { - info!("{} -> {}", format_ref_str(&label_entry.ref_()), label_text); + println!("{} -> {}", format_ref_str(&label_entry.ref_()), label_text); } } } - Err(e) => error!("Error reloading labels: {}", e), + Err(e) => eprintln!("Error reloading labels: {}", e), } - info!("\n--- Example Finished ---"); + println!("\n--- Example Finished ---"); Ok(()) } From 7be28d4b239ae637c0f3405c4f1b540a12dba0bf Mon Sep 17 00:00:00 2001 From: Musab1258 Date: Thu, 1 May 2025 10:10:25 +0100 Subject: [PATCH 6/6] fix clippy errors --- wallet/examples/bip329_example.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wallet/examples/bip329_example.rs b/wallet/examples/bip329_example.rs index bb434443..a907a015 100644 --- a/wallet/examples/bip329_example.rs +++ b/wallet/examples/bip329_example.rs @@ -48,7 +48,7 @@ fn format_bdk_outpoint_ref(op: OutPoint) -> String { } // --- Main Example Logic --- -#[allow(clippy::print_stdout)] +#[allow(clippy::print_stdout, clippy::print_stderr)] fn main() -> Result<()> { println!("--- BDK Wallet + BIP-329 Label Example ---");