Skip to content

Commit 5ce40ec

Browse files
thunderbiscuit110CodingP
authored andcommitted
tests: add tests for KeyRing and Wallet
1 parent aa8592e commit 5ce40ec

5 files changed

Lines changed: 1114 additions & 779 deletions

File tree

src/keyring/mod.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,3 +247,55 @@ where
247247
}))
248248
}
249249
}
250+
251+
#[cfg(test)]
252+
mod test {
253+
#[cfg(feature = "rusqlite")]
254+
#[test]
255+
fn test_persist() {
256+
use crate::keyring::{ChangeSet, KeyRing};
257+
use bdk_chain::rusqlite;
258+
use bdk_wallet::KeychainKind;
259+
use bitcoin::Network;
260+
use tempfile::tempdir;
261+
262+
let dir = tempdir().unwrap();
263+
let file_path = dir.path().join(".bdk_example_keyring.sqlite");
264+
265+
// create a keyring and persist it
266+
let desc1 = "tr(tprv8ZgxMBicQKsPdWAHbugK2tjtVtRjKGixYVZUdL7xLHMgXZS6BFbFi1UDb1CHT25Z5PU1F9j7wGxwUiRhqz9E3nZRztikGUV6HoRDYcqPhM4/86'/1'/0'/0/*)";
267+
let keychain1 = KeychainKind::External;
268+
let mut keyring = KeyRing::new(Network::Regtest, keychain1, desc1).unwrap();
269+
let changeset = keyring.initial_changeset();
270+
271+
let mut conn = rusqlite::Connection::open(file_path).unwrap();
272+
let db_tx = conn.transaction().unwrap();
273+
274+
ChangeSet::<KeychainKind>::init_sqlite_tables(&db_tx).unwrap();
275+
changeset.persist_to_sqlite(&db_tx).unwrap();
276+
db_tx.commit().unwrap();
277+
278+
// add a descriptor to the keyring and persist again
279+
let desc2 = "tr(tprv8ZgxMBicQKsPdWAHbugK2tjtVtRjKGixYVZUdL7xLHMgXZS6BFbFi1UDb1CHT25Z5PU1F9j7wGxwUiRhqz9E3nZRztikGUV6HoRDYcqPhM4/86'/1'/0'/1/*)";
280+
let keychain2 = KeychainKind::Internal;
281+
let changeset2 = keyring.add_descriptor(keychain2, desc2, true).unwrap();
282+
283+
let db_tx = conn.transaction().unwrap();
284+
changeset2.persist_to_sqlite(&db_tx).unwrap();
285+
db_tx.commit().unwrap();
286+
287+
let db_tx = conn.transaction().unwrap();
288+
let keyring_read = KeyRing::from_changeset(
289+
ChangeSet::<KeychainKind>::from_sqlite(&db_tx).unwrap(),
290+
None,
291+
[].into(),
292+
None,
293+
)
294+
.unwrap()
295+
.unwrap();
296+
297+
assert_eq!(keyring.list_keychains(), keyring_read.list_keychains());
298+
assert_eq!(keyring.network(), keyring_read.network());
299+
assert_eq!(keyring.default_keychain(), keyring_read.default_keychain());
300+
}
301+
}

src/test_utils.rs

Lines changed: 130 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -5,132 +5,143 @@ use alloc::sync::Arc;
55
use core::fmt;
66
use core::str::FromStr;
77

8+
use crate::keyring::KeyRing;
9+
use crate::{KeychainKind, Update, Wallet};
810
use bdk_chain::{BlockId, CheckPoint, ConfirmationBlockTime, TxUpdate};
911
use bitcoin::{
1012
absolute, hashes::Hash, transaction, Address, Amount, BlockHash, FeeRate, Network, OutPoint,
1113
Transaction, TxIn, TxOut, Txid,
1214
};
1315

14-
use crate::{KeychainKind, Update, Wallet};
16+
/// Return a fake wallet that appears to be funded for testing.
17+
///
18+
/// The funded wallet contains a tx with a 76_000 sats input and two outputs, one spending 25_000
19+
/// to a foreign address and one returning 50_000 back to the wallet. The remaining 1000
20+
/// sats are the transaction fee.
21+
pub fn get_funded_wallet(
22+
descriptor: &str,
23+
change_descriptor: &str,
24+
) -> (Wallet<KeychainKind>, Txid) {
25+
new_funded_wallet(descriptor, Some(change_descriptor))
26+
}
27+
28+
fn new_funded_wallet(
29+
descriptor: &str,
30+
change_descriptor: Option<&str>,
31+
) -> (Wallet<KeychainKind>, Txid) {
32+
let (mut wallet, txid, update) = new_wallet_and_funding_update(descriptor, change_descriptor);
33+
wallet.apply_update(update).unwrap();
34+
(wallet, txid)
35+
}
36+
37+
/// Return a fake wallet that appears to be funded for testing.
38+
///
39+
/// The funded wallet contains a tx with a 76_000 sats input and two outputs, one spending 25_000
40+
/// to a foreign address and one returning 50_000 back to the wallet. The remaining 1000
41+
/// sats are the transaction fee.
42+
pub fn get_funded_wallet_single(descriptor: &str) -> (Wallet<KeychainKind>, Txid) {
43+
new_funded_wallet(descriptor, None)
44+
}
45+
46+
/// Get funded segwit wallet
47+
pub fn get_funded_wallet_wpkh() -> (Wallet<KeychainKind>, Txid) {
48+
let (desc, change_desc) = get_test_wpkh_and_change_desc();
49+
get_funded_wallet(desc, change_desc)
50+
}
51+
52+
// TODO: Perhaps this can be made generic!
53+
/// Get unfunded wallet and wallet update that funds it
54+
///
55+
/// The funding update contains a tx with a 76_000 sats input and two outputs, one spending
56+
/// 25_000 to a foreign address and one returning 50_000 back to the wallet as
57+
/// change. The remaining 1000 sats are the transaction fee.
58+
pub fn new_wallet_and_funding_update(
59+
descriptor: &str,
60+
change_descriptor: Option<&str>,
61+
) -> (Wallet<KeychainKind>, Txid, Update<KeychainKind>) {
62+
let mut keyring = KeyRing::new(Network::Regtest, KeychainKind::External, descriptor)
63+
.expect("descriptor must be valid");
64+
if let Some(change_desc) = change_descriptor {
65+
keyring
66+
.add_descriptor(KeychainKind::Internal, change_desc, false)
67+
.expect("descriptor must be valid");
68+
};
69+
70+
let wallet = Wallet::create(keyring)
71+
.create_wallet_no_persist()
72+
.expect("descriptors must be valid");
73+
74+
let receive_address = wallet
75+
.peek_address(KeychainKind::External, 0)
76+
.unwrap()
77+
.address;
78+
let sendto_address = Address::from_str("bcrt1q3qtze4ys45tgdvguj66zrk4fu6hq3a3v9pfly5")
79+
.expect("address")
80+
.require_network(Network::Regtest)
81+
.unwrap();
1582

16-
// /// Return a fake wallet that appears to be funded for testing.
17-
// ///
18-
// /// The funded wallet contains a tx with a 76_000 sats input and two outputs, one spending 25_000
19-
// /// to a foreign address and one returning 50_000 back to the wallet. The remaining 1000
20-
// /// sats are the transaction fee.
21-
// pub fn get_funded_wallet(descriptor: &str, change_descriptor: &str) -> (Wallet, Txid) {
22-
// new_funded_wallet(descriptor, Some(change_descriptor))
23-
// }
24-
25-
// fn new_funded_wallet(descriptor: &str, change_descriptor: Option<&str>) -> (Wallet, Txid) {
26-
// let (mut wallet, txid, update) = new_wallet_and_funding_update(descriptor,
27-
// change_descriptor); wallet.apply_update(update).unwrap();
28-
// (wallet, txid)
29-
// }
30-
//
31-
// /// Return a fake wallet that appears to be funded for testing.
32-
// ///
33-
// /// The funded wallet contains a tx with a 76_000 sats input and two outputs, one spending 25_000
34-
// /// to a foreign address and one returning 50_000 back to the wallet. The remaining 1000
35-
// /// sats are the transaction fee.
36-
// pub fn get_funded_wallet_single(descriptor: &str) -> (Wallet, Txid) {
37-
// new_funded_wallet(descriptor, None)
38-
// }
39-
//
40-
// /// Get funded segwit wallet
41-
// pub fn get_funded_wallet_wpkh() -> (Wallet, Txid) {
42-
// let (desc, change_desc) = get_test_wpkh_and_change_desc();
43-
// get_funded_wallet(desc, change_desc)
44-
// }
45-
//
46-
// /// Get unfunded wallet and wallet update that funds it
47-
// ///
48-
// /// The funding update contains a tx with a 76_000 sats input and two outputs, one spending
49-
// /// 25_000 to a foreign address and one returning 50_000 back to the wallet as
50-
// /// change. The remaining 1000 sats are the transaction fee.
51-
// pub fn new_wallet_and_funding_update(
52-
// descriptor: &str,
53-
// change_descriptor: Option<&str>,
54-
// ) -> (Wallet, Txid, Update) {
55-
// let params = if let Some(change_desc) = change_descriptor {
56-
// Wallet::create(descriptor.to_string(), change_desc.to_string())
57-
// } else {
58-
// Wallet::create_single(descriptor.to_string())
59-
// };
60-
//
61-
// let wallet = params
62-
// .network(Network::Regtest)
63-
// .create_wallet_no_persist()
64-
// .expect("descriptors must be valid");
65-
//
66-
// let receive_address = wallet.peek_address(KeychainKind::External, 0).address;
67-
// let sendto_address = Address::from_str("bcrt1q3qtze4ys45tgdvguj66zrk4fu6hq3a3v9pfly5")
68-
// .expect("address")
69-
// .require_network(Network::Regtest)
70-
// .unwrap();
71-
//
72-
// let mut update = Update::default();
73-
//
74-
// let tx0 = Transaction {
75-
// output: vec![TxOut {
76-
// value: Amount::from_sat(76_000),
77-
// script_pubkey: receive_address.script_pubkey(),
78-
// }],
79-
// ..new_tx(0)
80-
// };
81-
//
82-
// let tx1 = Transaction {
83-
// input: vec![TxIn {
84-
// previous_output: OutPoint {
85-
// txid: tx0.compute_txid(),
86-
// vout: 0,
87-
// },
88-
// ..Default::default()
89-
// }],
90-
// output: vec![
91-
// TxOut {
92-
// value: Amount::from_sat(50_000),
93-
// script_pubkey: receive_address.script_pubkey(),
94-
// },
95-
// TxOut {
96-
// value: Amount::from_sat(25_000),
97-
// script_pubkey: sendto_address.script_pubkey(),
98-
// },
99-
// ],
100-
// ..new_tx(0)
101-
// };
102-
// let txid1 = tx1.compute_txid();
103-
//
104-
// let b0 = BlockId {
105-
// height: 0,
106-
// hash: BlockHash::from_slice(wallet.network().chain_hash().as_bytes()).unwrap(),
107-
// };
108-
// let b1 = BlockId {
109-
// height: 42,
110-
// hash: BlockHash::all_zeros(),
111-
// };
112-
// let b2 = BlockId {
113-
// height: 1000,
114-
// hash: BlockHash::all_zeros(),
115-
// };
116-
// let a2 = ConfirmationBlockTime {
117-
// block_id: b2,
118-
// confirmation_time: 100,
119-
// };
120-
// let b3 = BlockId {
121-
// height: 2000,
122-
// hash: BlockHash::all_zeros(),
123-
// };
124-
// let a3 = ConfirmationBlockTime {
125-
// block_id: b3,
126-
// confirmation_time: 200,
127-
// };
128-
// update.chain = CheckPoint::from_block_ids([b0, b1, b2, b3]).ok();
129-
// update.tx_update.anchors = [(a2, tx0.compute_txid()), (a3, tx1.compute_txid())].into();
130-
// update.tx_update.txs = [Arc::new(tx0), Arc::new(tx1)].into();
131-
//
132-
// (wallet, txid1, update)
133-
// }
83+
let mut update = Update::default();
84+
85+
let tx0 = Transaction {
86+
output: vec![TxOut {
87+
value: Amount::from_sat(76_000),
88+
script_pubkey: receive_address.script_pubkey(),
89+
}],
90+
..new_tx(0)
91+
};
92+
93+
let tx1 = Transaction {
94+
input: vec![TxIn {
95+
previous_output: OutPoint {
96+
txid: tx0.compute_txid(),
97+
vout: 0,
98+
},
99+
..Default::default()
100+
}],
101+
output: vec![
102+
TxOut {
103+
value: Amount::from_sat(50_000),
104+
script_pubkey: receive_address.script_pubkey(),
105+
},
106+
TxOut {
107+
value: Amount::from_sat(25_000),
108+
script_pubkey: sendto_address.script_pubkey(),
109+
},
110+
],
111+
..new_tx(0)
112+
};
113+
let txid1 = tx1.compute_txid();
114+
115+
let b0 = BlockId {
116+
height: 0,
117+
hash: BlockHash::from_slice(wallet.network().chain_hash().as_bytes()).unwrap(),
118+
};
119+
let b1 = BlockId {
120+
height: 42,
121+
hash: BlockHash::all_zeros(),
122+
};
123+
let b2 = BlockId {
124+
height: 1000,
125+
hash: BlockHash::all_zeros(),
126+
};
127+
let a2 = ConfirmationBlockTime {
128+
block_id: b2,
129+
confirmation_time: 100,
130+
};
131+
let b3 = BlockId {
132+
height: 2000,
133+
hash: BlockHash::all_zeros(),
134+
};
135+
let a3 = ConfirmationBlockTime {
136+
block_id: b3,
137+
confirmation_time: 200,
138+
};
139+
update.chain = CheckPoint::from_block_ids([b0, b1, b2, b3]).ok();
140+
update.tx_update.anchors = [(a2, tx0.compute_txid()), (a3, tx1.compute_txid())].into();
141+
update.tx_update.txs = [Arc::new(tx0), Arc::new(tx1)].into();
142+
143+
(wallet, txid1, update)
144+
}
134145

135146
/// `pkh` single key descriptor
136147
pub fn get_test_pkh() -> &'static str {

0 commit comments

Comments
 (0)