Skip to content

Commit

Permalink
feat(wallet): add back TxBuilder finish() and sort_tx() with thread_r…
Browse files Browse the repository at this point in the history
…ng()
  • Loading branch information
notmandatory authored and rustaceanrob committed Jun 19, 2024
1 parent 45c0cae commit 4bddb0d
Show file tree
Hide file tree
Showing 19 changed files with 245 additions and 242 deletions.
1 change: 0 additions & 1 deletion crates/esplora/src/blocking_ext.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::collections::BTreeSet;
use std::thread::JoinHandle;
use std::usize;

use bdk_chain::collections::BTreeMap;
use bdk_chain::spk_client::{FullScanRequest, FullScanResult, SyncRequest, SyncResult};
Expand Down
2 changes: 1 addition & 1 deletion crates/wallet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ bip39 = { version = "2.0", optional = true }

[features]
default = ["std"]
std = ["bitcoin/std", "miniscript/std", "bdk_chain/std"]
std = ["bitcoin/std", "bitcoin/rand-std", "miniscript/std", "bdk_chain/std"]
compiler = ["miniscript/compiler"]
all-keys = ["keys-bip39"]
keys-bip39 = ["bip39"]
Expand Down
47 changes: 22 additions & 25 deletions crates/wallet/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,30 +70,28 @@ To persist `Wallet` state data use a data store crate that reads and writes [`bd
```rust,no_run
use bdk_wallet::{bitcoin::Network, KeychainKind, wallet::{ChangeSet, Wallet}};
fn main() {
// Open or create a new file store for wallet data.
let mut db =
bdk_file_store::Store::<ChangeSet>::open_or_create_new(b"magic_bytes", "/tmp/my_wallet.db")
.expect("create store");
// Create a wallet with initial wallet data read from the file store.
let descriptor = "wpkh(tprv8ZgxMBicQKsPdcAqYBpzAFwU5yxBUo88ggoBqu1qPcHUfSbKK1sKMLmC7EAk438btHQrSdu3jGGQa6PA71nvH5nkDexhLteJqkM4dQmWF9g/84'/1'/0'/0/*)";
let change_descriptor = "wpkh(tprv8ZgxMBicQKsPdcAqYBpzAFwU5yxBUo88ggoBqu1qPcHUfSbKK1sKMLmC7EAk438btHQrSdu3jGGQa6PA71nvH5nkDexhLteJqkM4dQmWF9g/84'/1'/0'/1/*)";
let changeset = db.aggregate_changesets().expect("changeset loaded");
let mut wallet =
Wallet::new_or_load(descriptor, change_descriptor, changeset, Network::Testnet)
.expect("create or load wallet");
// Get a new address to receive bitcoin.
let receive_address = wallet.reveal_next_address(KeychainKind::External);
// Persist staged wallet data changes to the file store.
let staged_changeset = wallet.take_staged();
if let Some(changeset) = staged_changeset {
db.append_changeset(&changeset)
.expect("must commit changes to database");
}
println!("Your new receive address is: {}", receive_address.address);
// Open or create a new file store for wallet data.
let mut db =
bdk_file_store::Store::<ChangeSet>::open_or_create_new(b"magic_bytes", "/tmp/my_wallet.db")
.expect("create store");
// Create a wallet with initial wallet data read from the file store.
let descriptor = "wpkh(tprv8ZgxMBicQKsPdcAqYBpzAFwU5yxBUo88ggoBqu1qPcHUfSbKK1sKMLmC7EAk438btHQrSdu3jGGQa6PA71nvH5nkDexhLteJqkM4dQmWF9g/84'/1'/0'/0/*)";
let change_descriptor = "wpkh(tprv8ZgxMBicQKsPdcAqYBpzAFwU5yxBUo88ggoBqu1qPcHUfSbKK1sKMLmC7EAk438btHQrSdu3jGGQa6PA71nvH5nkDexhLteJqkM4dQmWF9g/84'/1'/0'/1/*)";
let changeset = db.aggregate_changesets().expect("changeset loaded");
let mut wallet =
Wallet::new_or_load(descriptor, change_descriptor, changeset, Network::Testnet)
.expect("create or load wallet");
// Get a new address to receive bitcoin.
let receive_address = wallet.reveal_next_address(KeychainKind::External);
// Persist staged wallet data changes to the file store.
let staged_changeset = wallet.take_staged();
if let Some(changeset) = staged_changeset {
db.append_changeset(&changeset)
.expect("must commit changes to database");
}
println!("Your new receive address is: {}", receive_address.address);
```

<!-- ### Sync the balance of a descriptor -->
Expand Down Expand Up @@ -154,7 +152,6 @@ fn main() {
<!-- use bitcoin::base64; -->
<!-- use bdk_wallet::bitcoin::consensus::serialize; -->
<!-- use bdk_wallet::bitcoin::Network; -->
<!-- use rand::thread_rng(); -->

<!-- fn main() -> Result<(), bdk_wallet::Error> { -->
<!-- let blockchain = ElectrumBlockchain::from(Client::new("ssl://electrum.blockstream.info:60002")?); -->
Expand All @@ -174,7 +171,7 @@ fn main() {
<!-- .enable_rbf() -->
<!-- .do_not_spend_change() -->
<!-- .fee_rate(FeeRate::from_sat_per_vb(5.0)); -->
<!-- builder.finish_with_aux_rand(&mut thread_rng())? -->
<!-- builder.finish()? -->
<!-- }; -->

<!-- println!("Transaction details: {:#?}", details); -->
Expand Down
4 changes: 1 addition & 3 deletions crates/wallet/examples/mnemonic_to_descriptors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ use bdk_wallet::descriptor::IntoWalletDescriptor;
use bdk_wallet::keys::bip39::{Language, Mnemonic, WordCount};
use bdk_wallet::keys::{GeneratableKey, GeneratedKey};
use bdk_wallet::miniscript::Tap;
use rand::thread_rng;
use std::str::FromStr;

/// This example demonstrates how to generate a mnemonic phrase
Expand All @@ -26,9 +25,8 @@ fn main() -> Result<(), anyhow::Error> {
// In this example we are generating a 12 words mnemonic phrase
// but it is also possible generate 15, 18, 21 and 24 words
// using their respective `WordCount` variant.
let mut rng = thread_rng();
let mnemonic: GeneratedKey<_, Tap> =
Mnemonic::generate((WordCount::Words12, Language::English), &mut rng)
Mnemonic::generate((WordCount::Words12, Language::English))
.map_err(|_| anyhow!("Mnemonic generation error"))?;

println!("Mnemonic phrase: {}", *mnemonic);
Expand Down
8 changes: 3 additions & 5 deletions crates/wallet/src/keys/bip39.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,6 @@ mod test {

use bip39::{Language, Mnemonic};

use rand::thread_rng;

use crate::keys::{any_network, GeneratableKey, GeneratedKey};

use super::WordCount;
Expand Down Expand Up @@ -218,12 +216,12 @@ mod test {

#[test]
fn test_keys_generate_bip39_random() {
let mut rng = thread_rng();
let generated_mnemonic: GeneratedKey<_, miniscript::Segwitv0> =
Mnemonic::generate((WordCount::Words12, Language::English), &mut rng).unwrap();
Mnemonic::generate((WordCount::Words12, Language::English)).unwrap();
assert_eq!(generated_mnemonic.valid_networks, any_network());

let generated_mnemonic: GeneratedKey<_, miniscript::Segwitv0> =
Mnemonic::generate((WordCount::Words24, Language::English), &mut rng).unwrap();
Mnemonic::generate((WordCount::Words24, Language::English)).unwrap();
assert_eq!(generated_mnemonic.valid_networks, any_network());
}
}
28 changes: 24 additions & 4 deletions crates/wallet/src/keys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -633,8 +633,18 @@ pub trait GeneratableKey<Ctx: ScriptContext>: Sized {
entropy: Self::Entropy,
) -> Result<GeneratedKey<Self, Ctx>, Self::Error>;

/// Generate a key given the options with a random entropy
fn generate(
/// Generate a key given the options with random entropy.
///
/// Uses the thread-local random number generator.
#[cfg(feature = "std")]
fn generate(options: Self::Options) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
Self::generate_with_aux_rand(options, &mut bitcoin::key::rand::thread_rng())
}

/// Generate a key given the options with random entropy.
///
/// Uses a provided random number generator (rng).
fn generate_with_aux_rand(
options: Self::Options,
rng: &mut (impl CryptoRng + RngCore),
) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
Expand All @@ -660,10 +670,20 @@ where
}

/// Generate a key with the default options and a random entropy
fn generate_default(
///
/// Uses the thread-local random number generator.
#[cfg(feature = "std")]
fn generate_default() -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
Self::generate_with_aux_rand(Default::default(), &mut bitcoin::key::rand::thread_rng())
}

/// Generate a key with the default options and a random entropy
///
/// Uses a provided random number generator (rng).
fn generate_default_with_aux_rand(
rng: &mut (impl CryptoRng + RngCore),
) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
Self::generate(Default::default(), rng)
Self::generate_with_aux_rand(Default::default(), rng)
}
}

Expand Down
4 changes: 1 addition & 3 deletions crates/wallet/src/wallet/coin_selection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@
//! # use bdk_wallet::*;
//! # use bdk_wallet::wallet::coin_selection::decide_change;
//! # use anyhow::Error;
//! # use rand::{thread_rng, RngCore};
//!
//! #[derive(Debug)]
//! struct AlwaysSpendEverything;
//!
Expand Down Expand Up @@ -94,7 +92,7 @@
//! let psbt = {
//! let mut builder = wallet.build_tx().coin_selection(AlwaysSpendEverything);
//! builder.add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000));
//! builder.finish_with_aux_rand(&mut thread_rng())?
//! builder.finish()?
//! };
//!
//! // inspect, sign, broadcast, ...
Expand Down
4 changes: 2 additions & 2 deletions crates/wallet/src/wallet/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ impl fmt::Display for MiniscriptPsbtError {
impl std::error::Error for MiniscriptPsbtError {}

#[derive(Debug)]
/// Error returned from [`TxBuilder::finish_with_aux_rand`]
/// Error returned from [`TxBuilder::finish`]
///
/// [`TxBuilder::finish_with_aux_rand`]: crate::wallet::tx_builder::TxBuilder::finish_with_aux_rand
/// [`TxBuilder::finish`]: crate::wallet::tx_builder::TxBuilder::finish
pub enum CreateTxError {
/// There was a problem with the descriptors passed in
Descriptor(DescriptorError),
Expand Down
12 changes: 5 additions & 7 deletions crates/wallet/src/wallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1212,15 +1212,14 @@ impl Wallet {
/// # use bdk_wallet::wallet::ChangeSet;
/// # use bdk_wallet::wallet::error::CreateTxError;
/// # use anyhow::Error;
/// # use rand::thread_rng;
/// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
/// # let mut wallet = doctest_wallet!();
/// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
/// let psbt = {
/// let mut builder = wallet.build_tx();
/// builder
/// .add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000));
/// builder.finish_with_aux_rand(&mut thread_rng())?
/// builder.finish()?
/// };
///
/// // sign and broadcast ...
Expand Down Expand Up @@ -1577,7 +1576,6 @@ impl Wallet {
/// # use bdk_wallet::wallet::ChangeSet;
/// # use bdk_wallet::wallet::error::CreateTxError;
/// # use anyhow::Error;
/// # use rand::thread_rng;
/// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
/// # let mut wallet = doctest_wallet!();
/// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
Expand All @@ -1586,7 +1584,7 @@ impl Wallet {
/// builder
/// .add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000))
/// .enable_rbf();
/// builder.finish_with_aux_rand(&mut thread_rng())?
/// builder.finish()?
/// };
/// let _ = wallet.sign(&mut psbt, SignOptions::default())?;
/// let tx = psbt.clone().extract_tx().expect("tx");
Expand All @@ -1595,7 +1593,7 @@ impl Wallet {
/// let mut builder = wallet.build_fee_bump(tx.compute_txid())?;
/// builder
/// .fee_rate(FeeRate::from_sat_per_vb(5).expect("valid feerate"));
/// builder.finish_with_aux_rand(&mut thread_rng())?
/// builder.finish()?
/// };
///
/// let _ = wallet.sign(&mut psbt, SignOptions::default())?;
Expand Down Expand Up @@ -1755,14 +1753,13 @@ impl Wallet {
/// # use bdk_wallet::*;
/// # use bdk_wallet::wallet::ChangeSet;
/// # use bdk_wallet::wallet::error::CreateTxError;
/// # use rand::thread_rng;
/// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
/// # let mut wallet = doctest_wallet!();
/// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
/// let mut psbt = {
/// let mut builder = wallet.build_tx();
/// builder.add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000));
/// builder.finish_with_aux_rand(&mut thread_rng())?
/// builder.finish()?
/// };
/// let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
/// assert!(finalized, "we should have signed all the inputs");
Expand Down Expand Up @@ -1807,6 +1804,7 @@ impl Wallet {
{
signer.sign_transaction(psbt, &sign_options, &self.secp)?;
}

// attempt to finalize
if sign_options.try_finalize {
self.finalize_psbt(psbt, sign_options)
Expand Down
Loading

0 comments on commit 4bddb0d

Please sign in to comment.