Skip to content

Commit fe3342d

Browse files
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) <aider@aider.chat>
1 parent 78cddab commit fe3342d

File tree

1 file changed

+77
-0
lines changed

1 file changed

+77
-0
lines changed

src/descriptor/key_map.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,4 +336,81 @@ mod tests {
336336

337337
assert_eq!(pk, expected_pk);
338338
}
339+
340+
#[test]
341+
fn get_key_keymap_no_match() {
342+
let secp = Secp256k1::new();
343+
344+
// Create a keymap with one key
345+
let descriptor_s = "wpkh(cMk8gWmj1KpjdYnAWwsEDekodMYhbyYBhG8gMtCCxucJ98JzcNij)";
346+
let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap();
347+
348+
// Request a different public key that doesn't exist in the keymap
349+
let different_sk =
350+
PrivateKey::from_str("cNJFgo1driFnPcBdBX8BrJrpxchBWXwXCvNH5SoSkdcF6JXXwHMm").unwrap();
351+
let different_pk = different_sk.public_key(&secp);
352+
let request = KeyRequest::Pubkey(different_pk);
353+
354+
let result = keymap.get_key(request, &secp).unwrap();
355+
assert!(result.is_none(), "Should return None when no matching key is found");
356+
}
357+
358+
#[test]
359+
fn get_key_descriptor_secret_key_xonly_not_supported() {
360+
let secp = Secp256k1::new();
361+
362+
let descriptor_sk = DescriptorSecretKey::from_str("xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi").unwrap();
363+
364+
// Create an x-only public key request
365+
let sk =
366+
PrivateKey::from_str("cMk8gWmj1KpjdYnAWwsEDekodMYhbyYBhG8gMtCCxucJ98JzcNij").unwrap();
367+
let xonly_pk = sk.public_key(&secp).inner.x_only_public_key().0;
368+
let request = KeyRequest::XOnlyPubkey(xonly_pk);
369+
370+
let result = descriptor_sk.get_key(request.clone(), &secp);
371+
assert!(matches!(result, Err(GetKeyError::NotSupported)));
372+
373+
// Also test with KeyMap
374+
let descriptor_s = "wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi)";
375+
let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap();
376+
377+
// While requesting an x-only key from an individual xpriv, that's an error.
378+
// But from a keymap, which might have both x-only keys and regular xprivs,
379+
// we treat errors as "key not found".
380+
let result = keymap.get_key(request, &secp);
381+
assert!(matches!(result, Ok(None)));
382+
}
383+
384+
#[test]
385+
fn get_key_descriptor_secret_key_xonly_multipath() {
386+
let secp = Secp256k1::new();
387+
388+
let descriptor_sk = DescriptorSecretKey::from_str("[d34db33f/84h/0h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/<0;1>").unwrap();
389+
390+
// Request with a different fingerprint
391+
let different_fingerprint = bitcoin::bip32::Fingerprint::from([0x12, 0x34, 0x56, 0x78]);
392+
let path = DerivationPath::from_str("84'/1'/0'/0").unwrap();
393+
let request = KeyRequest::Bip32((different_fingerprint, path));
394+
395+
let result = descriptor_sk.get_key(request.clone(), &secp).unwrap();
396+
assert!(result.is_none(), "Should return None when fingerprint doesn't match");
397+
398+
// Create an x-only public key request -- now we get "not supported".
399+
let sk =
400+
PrivateKey::from_str("cMk8gWmj1KpjdYnAWwsEDekodMYhbyYBhG8gMtCCxucJ98JzcNij").unwrap();
401+
let xonly_pk = sk.public_key(&secp).inner.x_only_public_key().0;
402+
let request_x = KeyRequest::XOnlyPubkey(xonly_pk);
403+
404+
let result = descriptor_sk.get_key(request_x.clone(), &secp);
405+
assert!(matches!(result, Err(GetKeyError::NotSupported)));
406+
407+
// Also test with KeyMap; as in the previous test, the error turns to None.
408+
let descriptor_s = "wpkh([d34db33f/84h/1h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)";
409+
let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap();
410+
411+
let result = keymap.get_key(request, &secp).unwrap();
412+
assert!(result.is_none(), "Should return None when fingerprint doesn't match");
413+
let result = keymap.get_key(request_x, &secp).unwrap();
414+
assert!(result.is_none(), "Should return None even on error");
415+
}
339416
}

0 commit comments

Comments
 (0)