Skip to content

Commit

Permalink
chore: add tests using legacy PKH wallet
Browse files Browse the repository at this point in the history
  • Loading branch information
realeinherjar committed Sep 19, 2023
1 parent e6185d6 commit b902be2
Show file tree
Hide file tree
Showing 2 changed files with 202 additions and 0 deletions.
4 changes: 4 additions & 0 deletions crates/bdk/tests/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ pub fn get_funded_wallet(descriptor: &str) -> (Wallet, bitcoin::Txid) {
get_funded_wallet_with_change(descriptor, None)
}

pub fn get_test_pkh() -> &'static str {
"pkh(0275d93539d503d824ad0c69a4c23ae480700489de09378ba32c1776cf86d6bb93)"
}

pub fn get_test_wpkh() -> &'static str {
"wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)"
}
Expand Down
198 changes: 198 additions & 0 deletions crates/bdk/tests/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1031,6 +1031,78 @@ fn test_create_tx_global_xpubs_with_origin() {
assert_eq!(psbt.xpub.get(&key), Some(&(fingerprint, path)));
}

#[test]
fn test_legacy_add_foreign_utxo() {
let (mut wallet1, _) = get_funded_wallet(get_test_pkh()); // legacy wallet using PKH
let (wallet2, _) =
get_funded_wallet("wpkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)");

let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
.unwrap()
.assume_checked();
let utxo = wallet2.list_unspent().next().expect("must take!");
let foreign_utxo_satisfaction = wallet2
.get_descriptor_for_keychain(KeychainKind::External)
.max_weight_to_satisfy()
.unwrap();

let psbt_input = psbt::Input {
witness_utxo: Some(utxo.txout.clone()),
..Default::default()
};

let mut builder = wallet1.build_tx();
builder
.add_recipient(addr.script_pubkey(), 60_000)
.only_witness_utxo()
.add_foreign_utxo(utxo.outpoint, psbt_input, foreign_utxo_satisfaction)
.unwrap();
let mut psbt = builder.finish().unwrap();
wallet1.insert_txout(utxo.outpoint, utxo.txout);
let fee = check_fee!(wallet1, psbt);
let sent_received = wallet1.sent_and_received(&psbt.clone().extract_tx());

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

assert!(
psbt.unsigned_tx
.input
.iter()
.any(|input| input.previous_output == utxo.outpoint),
"foreign_utxo should be in there"
);

let finished = wallet1
.sign(
&mut psbt,
SignOptions {
trust_witness_utxo: true,
..Default::default()
},
)
.unwrap();

assert!(
!finished,
"only one of the inputs should have been signed so far"
);

let finished = wallet2
.sign(
&mut psbt,
SignOptions {
trust_witness_utxo: true,
..Default::default()
},
)
.unwrap();
assert!(finished, "all the inputs should have been signed now");
}

#[test]
fn test_add_foreign_utxo() {
let (mut wallet1, _) = get_funded_wallet(get_test_wpkh());
Expand Down Expand Up @@ -1713,6 +1785,73 @@ fn test_bump_fee_remove_output_manually_selected_only() {
builder.finish().unwrap();
}

#[test]
fn test_legacy_bump_fee_add_input() {
let (mut wallet, _) = get_funded_wallet(get_test_pkh()); // legacy wallet PKH
let init_tx = Transaction {
version: 1,
lock_time: absolute::LockTime::ZERO,
input: vec![],
output: vec![TxOut {
script_pubkey: wallet.get_address(New).script_pubkey(),
value: 25_000,
}],
};
let pos = wallet
.transactions()
.last()
.unwrap()
.chain_position
.cloned()
.into();
wallet.insert_tx(init_tx, pos).unwrap();

let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
.unwrap()
.assume_checked();
let mut builder = wallet.build_tx().coin_selection(LargestFirstCoinSelection);
builder
.add_recipient(addr.script_pubkey(), 45_000)
.enable_rbf();
let psbt = builder.finish().unwrap();
let tx = psbt.extract_tx();
let original_details = wallet.sent_and_received(&tx);
let txid = tx.txid();
wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
.unwrap();

let mut builder = wallet.build_fee_bump(txid).unwrap();
builder.fee_rate(FeeRate::from_sat_per_vb(50.0));
let psbt = builder.finish().unwrap();
let sent_received = wallet.sent_and_received(&psbt.clone().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);

let tx = &psbt.unsigned_tx;
assert_eq!(tx.input.len(), 2);
assert_eq!(tx.output.len(), 2);
assert_eq!(
tx.output
.iter()
.find(|txout| txout.script_pubkey == addr.script_pubkey())
.unwrap()
.value,
45_000
);
assert_eq!(
tx.output
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
.value,
sent_received.1
);

assert_fee_rate!(psbt, fee.unwrap_or(0), FeeRate::from_sat_per_vb(50.0), @add_signature);
}

#[test]
fn test_bump_fee_add_input() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
Expand Down Expand Up @@ -1963,6 +2102,65 @@ fn test_bump_fee_add_input_change_dust() {
assert_fee_rate!(psbt, fee.unwrap_or(0), FeeRate::from_sat_per_vb(140.0), @dust_change, @add_signature);
}

#[test]
fn test_legacy_bump_fee_force_add_input() {
let (mut wallet, _) = get_funded_wallet(get_test_pkh()); // legacy wallet using PKH
let incoming_op = receive_output_in_latest_block(&mut wallet, 25_000);

let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
.unwrap()
.assume_checked();
let mut builder = wallet.build_tx().coin_selection(LargestFirstCoinSelection);
builder
.add_recipient(addr.script_pubkey(), 45_000)
.enable_rbf();
let psbt = builder.finish().unwrap();
let mut tx = psbt.extract_tx();
let original_sent_received = wallet.sent_and_received(&tx);
let txid = tx.txid();
for txin in &mut tx.input {
txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // fake signature
}
wallet
.insert_tx(tx.clone(), ConfirmationTime::Unconfirmed { last_seen: 0 })
.unwrap();
// the new fee_rate is low enough that just reducing the change would be fine, but we force
// the addition of an extra input with `add_utxo()`
let mut builder = wallet.build_fee_bump(txid).unwrap();
builder
.add_utxo(incoming_op)
.unwrap()
.fee_rate(FeeRate::from_sat_per_vb(5.0));
let psbt = builder.finish().unwrap();
let sent_received = wallet.sent_and_received(&psbt.clone().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);

let tx = &psbt.unsigned_tx;
assert_eq!(tx.input.len(), 2);
assert_eq!(tx.output.len(), 2);
assert_eq!(
tx.output
.iter()
.find(|txout| txout.script_pubkey == addr.script_pubkey())
.unwrap()
.value,
45_000
);
assert_eq!(
tx.output
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
.value,
sent_received.1
);

assert_fee_rate!(psbt, fee.unwrap_or(0), FeeRate::from_sat_per_vb(5.0), @add_signature);
}

#[test]
fn test_bump_fee_force_add_input() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
Expand Down

0 comments on commit b902be2

Please sign in to comment.