Skip to content
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
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
type to mark for a missing client.
- Upgrade `tokio` to `1.0`.

#### Transaction Creation Overhaul

The `TxBuilder` is now created from the `build_tx` or `build_fee_bump` functions on wallet and the
final transaction is created by calling `finish` on the builder.

- Removed `TxBuilder::utxos` in favor of `TxBuilder::add_utxos`
- Added `Wallet::build_tx` to replace `Wallet::create_tx`
- Added `Wallet::build_fee_bump` to replace `Wallet::bump_fee`
- Added `Wallet::get_utxo`
- Added `Wallet::get_descriptor_for_keychain`

### CLI
#### Changed
- Remove `cli.rs` module, `cli-utils` feature and `repl.rs` example; moved to new [`bdk-cli`](https://github.com/bitcoindevkit/bdk-cli) repository
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ test-electrum = ["electrum"]
test-md-docs = ["electrum"]

[dev-dependencies]
bdk-testutils = "0.2"
bdk-testutils-macros = "0.2"
bdk-testutils = { path = "./testutils" }
bdk-testutils-macros = { path = "./testutils-macros" }
serial_test = "0.4"
lazy_static = "1.4"
env_logger = "0.7"
Expand Down
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ fn main() -> Result<(), bdk::Error> {
### Create a transaction

```rust,no_run
use bdk::{FeeRate, TxBuilder, Wallet};
use bdk::{FeeRate, Wallet};
use bdk::database::MemoryDatabase;
use bdk::blockchain::{noop_progress, ElectrumBlockchain};

Expand All @@ -108,12 +108,15 @@ fn main() -> Result<(), bdk::Error> {
wallet.sync(noop_progress(), None)?;

let send_to = wallet.get_new_address()?;
let (psbt, details) = wallet.create_tx(
TxBuilder::with_recipients(vec![(send_to.script_pubkey(), 50_000)])
let (psbt, details) = {
let mut builder = wallet.build_tx();
builder
.add_recipient(send_to.script_pubkey(), 50_000)
.enable_rbf()
.do_not_spend_change()
.fee_rate(FeeRate::from_sat_per_vb(5.0))
)?;
.fee_rate(FeeRate::from_sat_per_vb(5.0));
builder.finish()?
};

println!("Transaction details: {:#?}", details);
println!("Unsigned PSBT: {}", base64::encode(&serialize(&psbt)));
Expand Down
1 change: 1 addition & 0 deletions examples/address_validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use bitcoin::hashes::hex::FromHex;
use bitcoin::util::bip32::Fingerprint;
use bitcoin::{Network, Script};

#[derive(Debug)]
struct DummyValidator;
impl AddressValidator for DummyValidator {
fn validate(
Expand Down
57 changes: 44 additions & 13 deletions src/database/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,16 +458,17 @@ impl ConfigurableDatabase for MemoryDatabase {
}
}

#[cfg(test)]
impl MemoryDatabase {
// Artificially insert a tx in the database, as if we had found it with a `sync`
pub fn received_tx(
&mut self,
tx_meta: testutils::TestIncomingTx,
current_height: Option<u32>,
) -> bitcoin::Txid {
use std::str::FromStr;

#[macro_export]
#[doc(hidden)]
/// Artificially insert a tx in the database, as if we had found it with a `sync`. This is a hidden
/// macro and not a `[cfg(test)]` function so it can be called within the context of doctests which
/// don't have `test` set.
macro_rules! populate_test_db {
($db:expr, $tx_meta:expr, $current_height:expr$(,)?) => {{
use $crate::database::BatchOperations;
let mut db = $db;
let tx_meta = $tx_meta;
let current_height: Option<u32> = $current_height;
let tx = Transaction {
version: 1,
lock_time: 0,
Expand Down Expand Up @@ -499,9 +500,9 @@ impl MemoryDatabase {
fees: 0,
};

self.set_tx(&tx_details).unwrap();
db.set_tx(&tx_details).unwrap();
Comment thread
LLFourn marked this conversation as resolved.
for (vout, out) in tx.output.iter().enumerate() {
self.set_utxo(&UTXO {
db.set_utxo(&UTXO {
txout: out.clone(),
outpoint: OutPoint {
txid,
Expand All @@ -513,7 +514,37 @@ impl MemoryDatabase {
}

txid
}
}};
}

#[macro_export]
#[doc(hidden)]
/// Macro for getting a wallet for use in a doctest
macro_rules! doctest_wallet {
() => {{
use $crate::bitcoin::Network;
use $crate::database::MemoryDatabase;
use testutils::testutils;
let descriptor = "wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)";
let descriptors = testutils!(@descriptors (descriptor) (descriptor));

let mut db = MemoryDatabase::new();
let txid = populate_test_db!(
&mut db,
testutils! {
@tx ( (@external descriptors, 0) => 500_000 ) (@confirmations 1)
},
Some(100),
);

$crate::Wallet::new_offline(
&descriptors.0,
descriptors.1.as_ref(),
Network::Regtest,
db
)
.unwrap()
}}
}

#[cfg(test)]
Expand Down
14 changes: 7 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@
//! ### Example
//! ```ignore
//! use base64::decode;
//! use bdk::{FeeRate, TxBuilder, Wallet};
//! use bdk::{FeeRate, Wallet};
//! use bdk::database::MemoryDatabase;
//! use bdk::blockchain::{noop_progress, ElectrumBlockchain};
//!
Expand All @@ -136,12 +136,12 @@
//! wallet.sync(noop_progress(), None)?;
//!
//! let send_to = wallet.get_new_address()?;
//! let (psbt, details) = wallet.create_tx(
//! TxBuilder::with_recipients(vec![(send_to.script_pubkey(), 50_000)])
//! .enable_rbf()
//! .do_not_spend_change()
//! .fee_rate(FeeRate::from_sat_per_vb(5.0))
//! )?;
//! let (psbt, details) = wallet.build_tx()
//! .add_recipient(send_to.script_pubkey(), 50_000)
//! .enable_rbf()
//! .do_not_spend_change()
//! .fee_rate(FeeRate::from_sat_per_vb(5.0))
//! .finish()?;
//!
//! println!("Transaction details: {:#?}", details);
//! println!("Unsigned PSBT: {}", base64::encode(&serialize(&psbt)));
Expand Down
14 changes: 6 additions & 8 deletions src/wallet/address_validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
//! # use bdk::address_validator::*;
//! # use bdk::database::*;
//! # use bdk::*;
//! #[derive(Debug)]
//! struct PrintAddressAndContinue;
//!
//! impl AddressValidator for PrintAddressAndContinue {
Expand Down Expand Up @@ -111,7 +112,7 @@ impl std::error::Error for AddressValidatorError {}
/// validator will be propagated up to the original caller that triggered the address generation.
///
/// For a usage example see [this module](crate::address_validator)'s documentation.
pub trait AddressValidator: Send + Sync {
pub trait AddressValidator: Send + Sync + fmt::Debug {
/// Validate or inspect an address
fn validate(
&self,
Expand All @@ -127,8 +128,8 @@ mod test {

use super::*;
use crate::wallet::test::{get_funded_wallet, get_test_wpkh};
use crate::wallet::TxBuilder;

#[derive(Debug)]
struct TestValidator;
impl AddressValidator for TestValidator {
fn validate(
Expand Down Expand Up @@ -157,11 +158,8 @@ mod test {
wallet.add_address_validator(Arc::new(TestValidator));

let addr = testutils!(@external descriptors, 10);
wallet
.create_tx(TxBuilder::with_recipients(vec![(
addr.script_pubkey(),
25_000,
)]))
.unwrap();
let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 25_000);
builder.finish().unwrap();
}
}
25 changes: 12 additions & 13 deletions src/wallet/coin_selection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,16 @@
//! This module provides the trait [`CoinSelectionAlgorithm`] that can be implemented to
//! define custom coin selection algorithms.
//!
//! The coin selection algorithm is not globally part of a [`Wallet`](super::Wallet), instead it
//! is selected whenever a [`Wallet::create_tx`](super::Wallet::create_tx) call is made, through
//! the use of the [`TxBuilder`] structure, specifically with
//! [`TxBuilder::coin_selection`](super::tx_builder::TxBuilder::coin_selection) method.
//!
//! The [`DefaultCoinSelectionAlgorithm`] selects the default coin selection algorithm that
//! [`TxBuilder`] uses, if it's not explicitly overridden.
//! You can specify a custom coin selection algorithm through the [`coin_selection`] method on
//! [`TxBuilder`]. [`DefaultCoinSelectionAlgorithm`] aliases the coin selection algorithm that will
//! be used if it is not explicitly set.
//!
//! [`TxBuilder`]: super::tx_builder::TxBuilder
//! [`coin_selection`]: super::tx_builder::TxBuilder::coin_selection
//!
//! ## Example
//!
//! ```no_run
//! ```
//! # use std::str::FromStr;
//! # use bitcoin::*;
//! # use bdk::wallet::coin_selection::*;
Expand Down Expand Up @@ -84,14 +81,16 @@
//! }
//! }
//!
//! # let wallet = Wallet::new_offline("", None, Network::Testnet, bdk::database::MemoryDatabase::default())?;
//! # let wallet = doctest_wallet!();
//! // create wallet, sync, ...
//!
//! let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
//! let (psbt, details) = wallet.create_tx(
//! TxBuilder::with_recipients(vec![(to_address.script_pubkey(), 50_000)])
//! .coin_selection(AlwaysSpendEverything),
//! )?;
//! let (psbt, details) = {
//! let mut builder = wallet.build_tx().coin_selection(AlwaysSpendEverything);
//! builder
//! .add_recipient(to_address.script_pubkey(), 50_000);
//! builder.finish()?
//! };
//!
//! // inspect, sign, broadcast, ...
//!
Expand Down
Loading