Skip to content

Commit

Permalink
test(wallet): test redefined relevant txs WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
LagginTimes committed Dec 9, 2024
1 parent a0fdfbb commit 3545b48
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 0 deletions.
4 changes: 4 additions & 0 deletions crates/wallet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ bdk_file_store = { path = "../file_store" }
anyhow = "1"
rand = "^0.8"

# temporary dev-dependencies for testing purposes
bdk_bitcoind_rpc = { path = "../bitcoind_rpc" }
bdk_testenv = { path = "../testenv" }

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
Expand Down
117 changes: 117 additions & 0 deletions crates/wallet/tests/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4196,8 +4196,125 @@ fn test_transactions_sort_by() {
assert_eq!([None, Some(2000), Some(1000)], conf_heights.as_slice());
}

use std::collections::HashMap;

use bdk_bitcoind_rpc::Emitter;
use bdk_testenv::bitcoincore_rpc::json::CreateRawTransactionInput;
use bdk_testenv::bitcoincore_rpc::{RawTx, RpcApi};
use bdk_testenv::TestEnv;
use bdk_wallet::CreateParams;

#[test]
fn test_tx_builder_is_send_safe() {
let (mut wallet, _txid) = get_funded_wallet_wpkh();
let _box: Box<dyn Send + Sync> = Box::new(wallet.build_tx());
}

// ErikDeSmedt's double spend test scenario
#[test]
fn detect_double_spend() -> anyhow::Result<()> {
// Create a test environment and mine initial funds
let env = TestEnv::new().expect("Failed to launch bitcoind");
let client = env
.bitcoind
.create_wallet("")
.expect("Failed to create wallet");
let address = client
.get_new_address(None, None)
.expect("Failed to create address");
client
.generate_to_address(106, address.assume_checked_ref())
.expect("Failed to mine block");

// Create the wallet under test
let mut alice = {
const DESC: &str ="tr(tprv8ZgxMBicQKsPdnxnfzsvrUZ58eNTq85PA6nhJALQiGy9GVhcvXmHX2r9znpyApMVNLdkPBp3WArLgU3UnA6npK9TtGoZDKdAjjkoYm3rY7F/84'/0'/0'/0/*)";
Wallet::create_with_params(
CreateParams::new_single(DESC).network(Network::Regtest)
)
}
.expect("Wallet can be created");

// Sync it with the chain
let mut emitter = Emitter::new(&env.bitcoind.client, alice.latest_checkpoint(), 0);
while let Some(ev) = emitter.next_block().unwrap() {
alice
.apply_block_connected_to(&ev.block, ev.block_height(), ev.connected_to())
.unwrap();
}

// Creates some transactions
let unspent = client
.list_unspent(None, None, None, Some(false), None)
.unwrap();

let input_amount = unspent[0].amount;
let destination_amount = Amount::from_sat(100_000);
let fee_amount = Amount::from_sat(2_000);
let change_amount = input_amount - destination_amount - fee_amount;

// Create a transaction that pays Alice
let address = alice.reveal_next_address(KeychainKind::External).address;
let change_address = client.get_new_address(None, None).unwrap().assume_checked();
let inputs = [CreateRawTransactionInput {
txid: unspent[0].txid,
vout: unspent[0].vout,
sequence: Some(0xFFFFFFFE),
}];
let mut outputs = HashMap::new();
outputs.insert(address.to_string(), destination_amount);
outputs.insert(change_address.to_string(), change_amount);
let tx1a = client
.create_raw_transaction(&inputs, &outputs, None, None)
.unwrap();
let tx1a = client
.sign_raw_transaction_with_wallet(tx1a.raw_hex(), None, None)
.unwrap()
.transaction()
.unwrap();

// Create a double-spent of tx1a
let address = client.get_new_address(None, None).unwrap().assume_checked();
let mut outputs = HashMap::new();
outputs.insert(address.to_string(), destination_amount);
outputs.insert(change_address.to_string(), change_amount);
let tx1b = client
.create_raw_transaction(&inputs, &outputs, None, None)
.unwrap();
let tx1b: Transaction = client
.sign_raw_transaction_with_wallet(tx1b.raw_hex(), None, None)
.unwrap()
.transaction()
.unwrap();

// Alice observes tx1a in the mempool
alice.apply_unconfirmed_txs(vec![(tx1a.clone(), 100)]);

// A block is create
// In this block tx1a is doublespent by tx1b
client.send_raw_transaction(tx1b.raw_hex()).unwrap();
let address = client
.get_new_address(None, None)
.expect("Failed to create address");
client
.generate_to_address(6, address.assume_checked_ref())
.expect("Failed to mine block");

// Apply the block to the w1
let mut emitter = Emitter::new(&env.bitcoind.client, alice.latest_checkpoint(), 0);
while let Some(ev) = emitter.next_block().unwrap() {
alice
.apply_block_connected_to(&ev.block, ev.block_height(), ev.connected_to())
.unwrap();
}

// We also add txb do the wallet
alice.apply_unconfirmed_txs([(tx1b.clone(), 101)]);

// I expect list_unspent to be empty.
// (tx1a) was double-spent
assert_eq!(alice.list_unspent().collect::<Vec<_>>(), vec![]);
//assert_eq!(alice.transactions().collect::<Vec<_>>(), vec![]);

Ok(())
}

0 comments on commit 3545b48

Please sign in to comment.