Skip to content

Commit

Permalink
feat: use Amount on spk_txout_index and related
Browse files Browse the repository at this point in the history
- update `wallet.rs` fns: `sent_and_received` fn
- update `keychain` `txout_index`fn: `sent_and_received and `net_value`
  • Loading branch information
oleonardolima committed May 5, 2024
1 parent b3e3714 commit 20f4c1f
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 69 deletions.
4 changes: 2 additions & 2 deletions crates/bdk/src/wallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -953,7 +953,7 @@ impl Wallet {
.map(|fee| bitcoin::Amount::from_sat(fee) / tx.weight())
}

/// Compute the `tx`'s sent and received amounts (in satoshis).
/// Compute the `tx`'s sent and received amounts (in [`bitcoin::Amount`]).
///
/// This method returns a tuple `(sent, received)`. Sent is the sum of the txin amounts
/// that spend from previous txouts tracked by this wallet. Received is the summation
Expand All @@ -978,7 +978,7 @@ impl Wallet {
/// let tx = &psbt.clone().extract_tx().expect("tx");
/// let (sent, received) = wallet.sent_and_received(tx);
/// ```
pub fn sent_and_received(&self, tx: &Transaction) -> (u64, u64) {
pub fn sent_and_received(&self, tx: &Transaction) -> (Amount, Amount) {
self.indexed_graph.index.sent_and_received(tx, ..)
}

Expand Down
118 changes: 73 additions & 45 deletions crates/bdk/tests/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ fn test_get_funded_wallet_balance() {
fn test_get_funded_wallet_sent_and_received() {
let (wallet, txid) = get_funded_wallet(get_test_wpkh());

let mut tx_amounts: Vec<(Txid, (u64, u64))> = wallet
let mut tx_amounts: Vec<(Txid, (Amount, Amount))> = wallet
.transactions()
.map(|ct| (ct.tx_node.txid, wallet.sent_and_received(&ct.tx_node)))
.collect();
Expand All @@ -219,8 +219,8 @@ fn test_get_funded_wallet_sent_and_received() {
// The funded wallet contains a tx with a 76_000 sats input and two outputs, one spending 25_000
// to a foreign address and one returning 50_000 back to the wallet as change. The remaining 1000
// sats are the transaction fee.
assert_eq!(sent, 76_000);
assert_eq!(received, 50_000);
assert_eq!(sent.to_sat(), 76_000);
assert_eq!(received.to_sat(), 50_000);
}

#[test]
Expand Down Expand Up @@ -1034,7 +1034,8 @@ fn test_create_tx_add_utxo() {
"should add an additional input since 25_000 < 30_000"
);
assert_eq!(
sent_received.0, 75_000,
sent_received.0,
Amount::from_sat(75_000),
"total should be sum of both inputs"
);
}
Expand Down Expand Up @@ -1225,7 +1226,7 @@ fn test_add_foreign_utxo() {
wallet1.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));

assert_eq!(
sent_received.0 - sent_received.1,
(sent_received.0 - sent_received.1).to_sat(),
10_000 + fee.unwrap_or(0),
"we should have only net spent ~10_000"
);
Expand Down Expand Up @@ -1622,8 +1623,8 @@ fn test_bump_fee_reduce_change() {

assert_eq!(sent_received.0, original_sent_received.0);
assert_eq!(
sent_received.1 + fee.unwrap_or(0),
original_sent_received.1 + original_fee.unwrap_or(0)
sent_received.1 + Amount::from_sat(fee.unwrap_or(0)),
original_sent_received.1 + Amount::from_sat(original_fee.unwrap_or(0))
);
assert!(fee.unwrap_or(0) > original_fee.unwrap_or(0));

Expand All @@ -1642,8 +1643,7 @@ fn test_bump_fee_reduce_change() {
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
.value
.to_sat(),
.value,
sent_received.1
);

Expand All @@ -1659,8 +1659,8 @@ fn test_bump_fee_reduce_change() {

assert_eq!(sent_received.0, original_sent_received.0);
assert_eq!(
sent_received.1 + fee.unwrap_or(0),
original_sent_received.1 + original_fee.unwrap_or(0)
sent_received.1 + Amount::from_sat(fee.unwrap_or(0)),
original_sent_received.1 + Amount::from_sat(original_fee.unwrap_or(0))
);
assert!(
fee.unwrap_or(0) > original_fee.unwrap_or(0),
Expand All @@ -1684,8 +1684,7 @@ fn test_bump_fee_reduce_change() {
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
.value
.to_sat(),
.value,
sent_received.1
);

Expand Down Expand Up @@ -1729,7 +1728,7 @@ fn test_bump_fee_reduce_single_recipient() {
let tx = &psbt.unsigned_tx;
assert_eq!(tx.output.len(), 1);
assert_eq!(
tx.output[0].value.to_sat() + fee.unwrap_or(0),
tx.output[0].value + Amount::from_sat(fee.unwrap_or(0)),
sent_received.0
);

Expand Down Expand Up @@ -1771,7 +1770,7 @@ fn test_bump_fee_absolute_reduce_single_recipient() {

assert_eq!(tx.output.len(), 1);
assert_eq!(
tx.output[0].value.to_sat() + fee.unwrap_or(0),
tx.output[0].value + Amount::from_sat(fee.unwrap_or(0)),
sent_received.0
);

Expand Down Expand Up @@ -1825,7 +1824,7 @@ fn test_bump_fee_drain_wallet() {
wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
.unwrap();
assert_eq!(original_sent_received.0, 25_000);
assert_eq!(original_sent_received.0, Amount::from_sat(25_000));

// for the new feerate, it should be enough to reduce the output, but since we specify
// `drain_wallet` we expect to spend everything
Expand All @@ -1838,7 +1837,7 @@ fn test_bump_fee_drain_wallet() {
let psbt = builder.finish().unwrap();
let sent_received = wallet.sent_and_received(&psbt.extract_tx().expect("failed to extract tx"));

assert_eq!(sent_received.0, 75_000);
assert_eq!(sent_received.0, Amount::from_sat(75_000));
}

#[test]
Expand Down Expand Up @@ -1895,7 +1894,7 @@ fn test_bump_fee_remove_output_manually_selected_only() {
wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
.unwrap();
assert_eq!(original_sent_received.0, 25_000);
assert_eq!(original_sent_received.0, Amount::from_sat(25_000));

let mut builder = wallet.build_fee_bump(txid).unwrap();
builder
Expand Down Expand Up @@ -1949,8 +1948,14 @@ fn test_bump_fee_add_input() {
let sent_received =
wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt);
assert_eq!(sent_received.0, original_details.0 + 25_000);
assert_eq!(fee.unwrap_or(0) + sent_received.1, 30_000);
assert_eq!(
sent_received.0,
original_details.0 + Amount::from_sat(25_000)
);
assert_eq!(
Amount::from_sat(fee.unwrap_or(0)) + sent_received.1,
Amount::from_sat(30_000)
);

let tx = &psbt.unsigned_tx;
assert_eq!(tx.input.len(), 2);
Expand All @@ -1968,8 +1973,7 @@ fn test_bump_fee_add_input() {
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
.value
.to_sat(),
.value,
sent_received.1
);

Expand Down Expand Up @@ -2002,8 +2006,14 @@ fn test_bump_fee_absolute_add_input() {
wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt);

assert_eq!(sent_received.0, original_sent_received.0 + 25_000);
assert_eq!(fee.unwrap_or(0) + sent_received.1, 30_000);
assert_eq!(
sent_received.0,
original_sent_received.0 + Amount::from_sat(25_000)
);
assert_eq!(
Amount::from_sat(fee.unwrap_or(0)) + sent_received.1,
Amount::from_sat(30_000)
);

let tx = &psbt.unsigned_tx;
assert_eq!(tx.input.len(), 2);
Expand All @@ -2021,8 +2031,7 @@ fn test_bump_fee_absolute_add_input() {
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
.value
.to_sat(),
.value,
sent_received.1
);

Expand Down Expand Up @@ -2065,11 +2074,15 @@ fn test_bump_fee_no_change_add_input_and_change() {
wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt);

let original_send_all_amount = original_sent_received.0 - original_fee.unwrap_or(0);
assert_eq!(sent_received.0, original_sent_received.0 + 50_000);
let original_send_all_amount =
original_sent_received.0 - Amount::from_sat(original_fee.unwrap_or(0));
assert_eq!(
sent_received.0,
original_sent_received.0 + Amount::from_sat(50_000)
);
assert_eq!(
sent_received.1,
75_000 - original_send_all_amount - fee.unwrap_or(0)
Amount::from_sat(75_000) - original_send_all_amount - Amount::from_sat(fee.unwrap_or(0))
);

let tx = &psbt.unsigned_tx;
Expand All @@ -2081,16 +2094,15 @@ fn test_bump_fee_no_change_add_input_and_change() {
.find(|txout| txout.script_pubkey == addr.script_pubkey())
.unwrap()
.value,
Amount::from_sat(original_send_all_amount)
original_send_all_amount
);
assert_eq!(
tx.output
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
.value
.to_sat(),
75_000 - original_send_all_amount - fee.unwrap_or(0)
.value,
Amount::from_sat(75_000) - original_send_all_amount - Amount::from_sat(fee.unwrap_or(0))
);

assert_fee_rate!(psbt, fee.unwrap_or(0), FeeRate::from_sat_per_vb_unchecked(50), @add_signature);
Expand Down Expand Up @@ -2145,11 +2157,17 @@ fn test_bump_fee_add_input_change_dust() {
wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt);

assert_eq!(original_sent_received.1, 5_000 - original_fee.unwrap_or(0));
assert_eq!(
original_sent_received.1,
Amount::from_sat(5_000 - original_fee.unwrap_or(0))
);

assert_eq!(sent_received.0, original_sent_received.0 + 25_000);
assert_eq!(
sent_received.0,
original_sent_received.0 + Amount::from_sat(25_000)
);
assert_eq!(fee.unwrap_or(0), 30_000);
assert_eq!(sent_received.1, 0);
assert_eq!(sent_received.1, Amount::ZERO);

let tx = &psbt.unsigned_tx;
assert_eq!(tx.input.len(), 2);
Expand Down Expand Up @@ -2200,8 +2218,14 @@ fn test_bump_fee_force_add_input() {
wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt);

assert_eq!(sent_received.0, original_sent_received.0 + 25_000);
assert_eq!(fee.unwrap_or(0) + sent_received.1, 30_000);
assert_eq!(
sent_received.0,
original_sent_received.0 + Amount::from_sat(25_000)
);
assert_eq!(
Amount::from_sat(fee.unwrap_or(0)) + sent_received.1,
Amount::from_sat(30_000)
);

let tx = &psbt.unsigned_tx;
assert_eq!(tx.input.len(), 2);
Expand All @@ -2219,8 +2243,7 @@ fn test_bump_fee_force_add_input() {
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
.value
.to_sat(),
.value,
sent_received.1
);

Expand Down Expand Up @@ -2260,8 +2283,14 @@ fn test_bump_fee_absolute_force_add_input() {
wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt);

assert_eq!(sent_received.0, original_sent_received.0 + 25_000);
assert_eq!(fee.unwrap_or(0) + sent_received.1, 30_000);
assert_eq!(
sent_received.0,
original_sent_received.0 + Amount::from_sat(25_000)
);
assert_eq!(
Amount::from_sat(fee.unwrap_or(0)) + sent_received.1,
Amount::from_sat(30_000)
);

let tx = &psbt.unsigned_tx;
assert_eq!(tx.input.len(), 2);
Expand All @@ -2279,8 +2308,7 @@ fn test_bump_fee_absolute_force_add_input() {
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
.value
.to_sat(),
.value,
sent_received.1
);

Expand Down Expand Up @@ -3228,7 +3256,7 @@ fn test_taproot_foreign_utxo() {

assert_eq!(
sent_received.0 - sent_received.1,
10_000 + fee.unwrap_or(0),
Amount::from_sat(10_000 + fee.unwrap_or(0)),
"we should have only net spent ~10_000"
);

Expand Down
10 changes: 7 additions & 3 deletions crates/chain/src/keychain/txout_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
spk_iter::BIP32_MAX_INDEX,
SpkIterator, SpkTxOutIndex,
};
use bitcoin::{OutPoint, Script, Transaction, TxOut, Txid};
use bitcoin::{Amount, OutPoint, Script, SignedAmount, Transaction, TxOut, Txid};
use core::{
fmt::Debug,
ops::{Bound, RangeBounds},
Expand Down Expand Up @@ -273,7 +273,11 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
/// *received* when it is on an output. For `sent` to be computed correctly, the output being
/// spent must have already been scanned by the index. Calculating received just uses the
/// [`Transaction`] outputs directly, so it will be correct even if it has not been scanned.
pub fn sent_and_received(&self, tx: &Transaction, range: impl RangeBounds<K>) -> (u64, u64) {
pub fn sent_and_received(
&self,
tx: &Transaction,
range: impl RangeBounds<K>,
) -> (Amount, Amount) {
self.inner
.sent_and_received(tx, Self::map_to_inner_bounds(range))
}
Expand All @@ -285,7 +289,7 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
/// This calls [`SpkTxOutIndex::net_value`] internally.
///
/// [`sent_and_received`]: Self::sent_and_received
pub fn net_value(&self, tx: &Transaction, range: impl RangeBounds<K>) -> i64 {
pub fn net_value(&self, tx: &Transaction, range: impl RangeBounds<K>) -> SignedAmount {
self.inner.net_value(tx, Self::map_to_inner_bounds(range))
}
}
Expand Down
Loading

0 comments on commit 20f4c1f

Please sign in to comment.