Skip to content

Commit d4a203b

Browse files
tests: add tests for KeyRing and Wallet
1 parent 7cd8600 commit d4a203b

4 files changed

Lines changed: 1098 additions & 552 deletions

File tree

src/keyring/mod.rs

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

tests/keyring.rs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
use std::collections::BTreeMap;
2+
3+
use bdk_wallet::descriptor::DescriptorError;
4+
use bdk_wallet::keyring::KeyRing;
5+
use bdk_wallet::KeychainKind;
6+
use bdk_wallet::{chain::DescriptorExt, keyring::KeyRingError};
7+
use bitcoin::secp256k1::Secp256k1;
8+
use bitcoin::Network;
9+
use miniscript::{Descriptor, DescriptorPublicKey};
10+
11+
// From the mnemonic "awesome awesome awesome awesome awesome awesome awesome awesome awesome
12+
// awesome awesome awesome"
13+
const DESC_1: &str = "tr(tprv8ZgxMBicQKsPdWAHbugK2tjtVtRjKGixYVZUdL7xLHMgXZS6BFbFi1UDb1CHT25Z5PU1F9j7wGxwUiRhqz9E3nZRztikGUV6HoRDYcqPhM4/86'/1'/0'/0/*)";
14+
15+
pub fn get_descriptor(desc_str: &str) -> Descriptor<DescriptorPublicKey> {
16+
Descriptor::parse_descriptor(&Secp256k1::new(), desc_str)
17+
.unwrap()
18+
.0
19+
}
20+
21+
#[test]
22+
fn test_simple_keyring() {
23+
let network = Network::Regtest;
24+
let keychain_id = KeychainKind::External;
25+
26+
let keyring = KeyRing::new(network, keychain_id, DESC_1).unwrap();
27+
28+
assert_eq!(keyring.default_keychain(), keychain_id);
29+
assert_eq!(keyring.list_keychains().len(), 1);
30+
}
31+
32+
#[test]
33+
fn test_8_keychains_keyring() {
34+
const DESC_1: &str = "tr(tprv8ZgxMBicQKsPdWAHbugK2tjtVtRjKGixYVZUdL7xLHMgXZS6BFbFi1UDb1CHT25Z5PU1F9j7wGxwUiRhqz9E3nZRztikGUV6HoRDYcqPhM4/86'/1'/0'/0/*)";
35+
const DESC_2: &str = "tr(tprv8ZgxMBicQKsPdWAHbugK2tjtVtRjKGixYVZUdL7xLHMgXZS6BFbFi1UDb1CHT25Z5PU1F9j7wGxwUiRhqz9E3nZRztikGUV6HoRDYcqPhM4/86'/1'/0'/1/*)";
36+
const DESC_3: &str = "tr(tprv8ZgxMBicQKsPdWAHbugK2tjtVtRjKGixYVZUdL7xLHMgXZS6BFbFi1UDb1CHT25Z5PU1F9j7wGxwUiRhqz9E3nZRztikGUV6HoRDYcqPhM4/86'/1'/0'/2/*)";
37+
const DESC_4: &str = "tr(tprv8ZgxMBicQKsPdWAHbugK2tjtVtRjKGixYVZUdL7xLHMgXZS6BFbFi1UDb1CHT25Z5PU1F9j7wGxwUiRhqz9E3nZRztikGUV6HoRDYcqPhM4/86'/1'/0'/3/*)";
38+
const DESC_5: &str = "tr(tprv8ZgxMBicQKsPdWAHbugK2tjtVtRjKGixYVZUdL7xLHMgXZS6BFbFi1UDb1CHT25Z5PU1F9j7wGxwUiRhqz9E3nZRztikGUV6HoRDYcqPhM4/86'/1'/0'/4/*)";
39+
const DESC_6: &str = "tr(tprv8ZgxMBicQKsPdWAHbugK2tjtVtRjKGixYVZUdL7xLHMgXZS6BFbFi1UDb1CHT25Z5PU1F9j7wGxwUiRhqz9E3nZRztikGUV6HoRDYcqPhM4/86'/1'/0'/5/*)";
40+
const DESC_7: &str = "tr(tprv8ZgxMBicQKsPdWAHbugK2tjtVtRjKGixYVZUdL7xLHMgXZS6BFbFi1UDb1CHT25Z5PU1F9j7wGxwUiRhqz9E3nZRztikGUV6HoRDYcqPhM4/86'/1'/0'/6/*)";
41+
const DESC_8: &str = "tr(tprv8ZgxMBicQKsPdWAHbugK2tjtVtRjKGixYVZUdL7xLHMgXZS6BFbFi1UDb1CHT25Z5PU1F9j7wGxwUiRhqz9E3nZRztikGUV6HoRDYcqPhM4/86'/1'/0'/7/*)";
42+
43+
let descriptors: BTreeMap<u8, &str> = [
44+
(1, DESC_1),
45+
(2, DESC_2),
46+
(3, DESC_3),
47+
(4, DESC_4),
48+
(5, DESC_5),
49+
(6, DESC_6),
50+
(7, DESC_7),
51+
(8, DESC_8),
52+
]
53+
.into();
54+
55+
let keyring = KeyRing::new_with_descriptors(Network::Regtest, descriptors, Some(1)).unwrap();
56+
57+
assert_eq!(keyring.default_keychain(), 1);
58+
assert_eq!(keyring.list_keychains().len(), 8);
59+
}
60+
61+
#[test]
62+
fn err_on_hardened_derivation_path() {
63+
let err = KeyRing::new(Network::Regtest, KeychainKind::External, "tr(tpubD6NzVbkrYhZ4WyC5VZLuSJQ14uwfUbus7oAFurAFkZA5N3groeQqtW65m8pG1TT1arPpfWu9RbBsc5rSBncrX2d84BAwJJHQfaRjnMCQwuT/86h/1h/0h/0/*)").err();
64+
assert_eq!(
65+
err,
66+
Some(KeyRingError::Descriptor(
67+
DescriptorError::HardenedDerivationXpub
68+
))
69+
);
70+
let mut keyring = KeyRing::new(Network::Regtest, KeychainKind::External, DESC_1).unwrap();
71+
let res = keyring.add_descriptor(KeychainKind::Internal,"tr([738b4dbd/86h/1h/0h]tpubDDQsJyQKuP6jCCSZ75Y8zpBAnXsvAN6BWpp6ZoczfxKBDBWnY8XGbC7AMMSyXAcQPNgppkCBmv3hkCLZSaQ4VvSTGsstuTrXuDadMaB7E45/0'/*)", false).err();
72+
assert_eq!(
73+
res,
74+
Some(KeyRingError::Descriptor(
75+
DescriptorError::HardenedDerivationXpub
76+
))
77+
);
78+
}
79+
80+
#[test]
81+
fn err_on_multipath() {
82+
let err = KeyRing::new(Network::Regtest, KeychainKind::External, "pkh(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/<0;1>)").err();
83+
assert_eq!(
84+
err,
85+
Some(KeyRingError::Descriptor(DescriptorError::Miniscript(
86+
miniscript::Error::BadDescriptor(
87+
"`check_wallet_descriptor` must not contain multipath keys".to_string(),
88+
)
89+
)))
90+
);
91+
let mut keyring = KeyRing::new(Network::Regtest, KeychainKind::External, DESC_1).unwrap();
92+
let res = keyring.add_descriptor(KeychainKind::Internal, "tr(tpubD6NzVbkrYhZ4WyC5VZLuSJQ14uwfUbus7oAFurAFkZA5N3groeQqtW65m8pG1TT1arPpfWu9RbBsc5rSBncrX2d84BAwJJHQfaRjnMCQwuT/86/1/0/<0;1>/*)" , false).err();
93+
assert_eq!(
94+
res,
95+
Some(KeyRingError::Descriptor(DescriptorError::Miniscript(
96+
miniscript::Error::BadDescriptor(
97+
"`check_wallet_descriptor` must not contain multipath keys".to_string(),
98+
)
99+
)))
100+
);
101+
}
102+
103+
#[test]
104+
fn duplicate_desc_keychain() {
105+
let desc1 = get_descriptor(DESC_1);
106+
let did1 = desc1.descriptor_id();
107+
let mut keyring = KeyRing::new(Network::Regtest, did1, desc1.clone()).unwrap();
108+
let desc2 = get_descriptor("tr(tprv8ZgxMBicQKsPdWAHbugK2tjtVtRjKGixYVZUdL7xLHMgXZS6BFbFi1UDb1CHT25Z5PU1F9j7wGxwUiRhqz9E3nZRztikGUV6HoRDYcqPhM4/86'/1'/0'/1/*)");
109+
let res1 = keyring
110+
.add_descriptor(desc2.descriptor_id(), desc1.clone(), false)
111+
.err();
112+
assert_eq!(
113+
res1,
114+
Some(KeyRingError::DescAlreadyExists(Box::new(desc1.clone())))
115+
);
116+
117+
let res2 = keyring.add_descriptor(did1, desc2, false).err();
118+
assert_eq!(res2, Some(KeyRingError::KeychainAlreadyExists(did1)));
119+
}

0 commit comments

Comments
 (0)