Skip to content

Commit 08fa87a

Browse files
apoelstraaider-chat-bot
authored andcommitted
test: extend unit tests to cover KeyMapWrapper error conditions
Claude 4 wrote the original tests; I then replaced its fix (which incorrectly also propagated errors in GetKey for KeyMap), updated the tests, and removed some extra tests which seemed uninformative and just noisy. To backport this to 12.x, just do s/KeyMap/KeyMapWrapper/ on the new tests. Oh, and add some `let keymap = KeyMapWrapper::from(keymap)` lines. Co-authored-by: aider (anthropic/claude-sonnet-4-20250514) <[email protected]>
1 parent 5f089aa commit 08fa87a

File tree

1 file changed

+80
-0
lines changed

1 file changed

+80
-0
lines changed

src/descriptor/key_map.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,4 +278,84 @@ mod tests {
278278

279279
assert_eq!(pk, expected_pk);
280280
}
281+
282+
#[test]
283+
fn get_key_keymap_no_match() {
284+
let secp = Secp256k1::new();
285+
286+
// Create a keymap with one key
287+
let descriptor_s = "wpkh(cMk8gWmj1KpjdYnAWwsEDekodMYhbyYBhG8gMtCCxucJ98JzcNij)";
288+
let (_, keymap) = Descriptor::parse_descriptor(&secp, descriptor_s).unwrap();
289+
let keymap_wrapper = KeyMapWrapper::from(keymap);
290+
291+
// Request a different public key that doesn't exist in the keymap
292+
let different_sk =
293+
PrivateKey::from_str("cNJFgo1driFnPcBdBX8BrJrpxchBWXwXCvNH5SoSkdcF6JXXwHMm").unwrap();
294+
let different_pk = different_sk.public_key(&secp);
295+
let request = KeyRequest::Pubkey(different_pk);
296+
297+
let result = keymap_wrapper.get_key(request, &secp).unwrap();
298+
assert!(result.is_none(), "Should return None when no matching key is found");
299+
}
300+
301+
#[test]
302+
fn get_key_descriptor_secret_key_xonly_not_supported() {
303+
let secp = Secp256k1::new();
304+
305+
let descriptor_sk = DescriptorSecretKey::from_str("xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi").unwrap();
306+
307+
// Create an x-only public key request
308+
let sk =
309+
PrivateKey::from_str("cMk8gWmj1KpjdYnAWwsEDekodMYhbyYBhG8gMtCCxucJ98JzcNij").unwrap();
310+
let xonly_pk = sk.public_key(&secp).inner.x_only_public_key().0;
311+
let request = KeyRequest::XOnlyPubkey(xonly_pk);
312+
313+
let result = descriptor_sk.get_key(request.clone(), &secp);
314+
assert!(matches!(result, Err(GetKeyError::NotSupported)));
315+
316+
// Also test with KeyMap
317+
let descriptor_s = "wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi)";
318+
let (_, keymap) = Descriptor::parse_descriptor(&secp, descriptor_s).unwrap();
319+
let keymap_wrapper = KeyMapWrapper::from(keymap);
320+
321+
// While requesting an x-only key from an individual xpriv, that's an error.
322+
// But from a keymap, which might have both x-only keys and regular xprivs,
323+
// we treat errors as "key not found".
324+
let result = keymap_wrapper.get_key(request, &secp);
325+
assert!(matches!(result, Ok(None)));
326+
}
327+
328+
#[test]
329+
fn get_key_descriptor_secret_key_xonly_multipath() {
330+
let secp = Secp256k1::new();
331+
332+
let descriptor_sk = DescriptorSecretKey::from_str("[d34db33f/84h/0h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/<0;1>").unwrap();
333+
334+
// Request with a different fingerprint
335+
let different_fingerprint = bitcoin::bip32::Fingerprint::from([0x12, 0x34, 0x56, 0x78]);
336+
let path = DerivationPath::from_str("84'/1'/0'/0").unwrap();
337+
let request = KeyRequest::Bip32((different_fingerprint, path));
338+
339+
let result = descriptor_sk.get_key(request.clone(), &secp).unwrap();
340+
assert!(result.is_none(), "Should return None when fingerprint doesn't match");
341+
342+
// Create an x-only public key request -- now we get "not supported".
343+
let sk =
344+
PrivateKey::from_str("cMk8gWmj1KpjdYnAWwsEDekodMYhbyYBhG8gMtCCxucJ98JzcNij").unwrap();
345+
let xonly_pk = sk.public_key(&secp).inner.x_only_public_key().0;
346+
let request_x = KeyRequest::XOnlyPubkey(xonly_pk);
347+
348+
let result = descriptor_sk.get_key(request_x.clone(), &secp);
349+
assert!(matches!(result, Err(GetKeyError::NotSupported)));
350+
351+
// Also test with KeyMap; as in the previous test, the error turns to None.
352+
let descriptor_s = "wpkh([d34db33f/84h/1h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)";
353+
let (_, keymap) = Descriptor::parse_descriptor(&secp, descriptor_s).unwrap();
354+
let keymap_wrapper = KeyMapWrapper::from(keymap);
355+
356+
let result = keymap_wrapper.get_key(request, &secp).unwrap();
357+
assert!(result.is_none(), "Should return None when fingerprint doesn't match");
358+
let result = keymap_wrapper.get_key(request_x, &secp).unwrap();
359+
assert!(result.is_none(), "Should return None even on error");
360+
}
281361
}

0 commit comments

Comments
 (0)