diff --git a/src/descriptor/checksum.rs b/src/descriptor/checksum.rs index 15f80055..04b22601 100644 --- a/src/descriptor/checksum.rs +++ b/src/descriptor/checksum.rs @@ -92,3 +92,35 @@ pub fn get_checksum(desc: &str) -> Result { Ok(String::from_iter(chars)) } + +#[cfg(test)] +mod test { + use super::*; + use crate::descriptor::get_checksum; + + // test get_checksum() function; it should return the same value as Bitcoin Core + #[test] + fn test_get_checksum() { + let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)"; + assert_eq!(get_checksum(desc).unwrap(), "tqz0nc62"); + + let desc = "pkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/44'/1'/0'/0/*)"; + assert_eq!(get_checksum(desc).unwrap(), "lasegmfs"); + } + + #[test] + fn test_get_checksum_invalid_character() { + let sparkle_heart = vec![240, 159, 146, 150]; + let sparkle_heart = std::str::from_utf8(&sparkle_heart) + .unwrap() + .chars() + .next() + .unwrap(); + let invalid_desc = format!("wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcL{}fjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)", sparkle_heart); + + assert!(matches!( + get_checksum(&invalid_desc).err(), + Some(Error::InvalidDescriptorCharacter(invalid_char)) if invalid_char == sparkle_heart + )); + } +} diff --git a/src/descriptor/dsl.rs b/src/descriptor/dsl.rs index d53b2a4d..6b99d448 100644 --- a/src/descriptor/dsl.rs +++ b/src/descriptor/dsl.rs @@ -402,3 +402,10 @@ macro_rules! fragment { }); } + +// test the descriptor!() macro +// - at least one of each "type" of operator; ie. one modifier, one leaf_opcode, one leaf_opcode_value, etc. +// - mixing up key types that implement ToDescriptorKey in multi() or thresh() +// - verify the valid_networks returned is correctly computed based on the keys present in the descriptor +// - verify the key_maps are correctly merged together +// - verify the ScriptContext is correctly validated (i.e. passing a type that only impl ToDescriptorKey to a pkh() descriptor should throw a compilation error diff --git a/src/descriptor/policy.rs b/src/descriptor/policy.rs index a71c9a98..55b9b9a0 100644 --- a/src/descriptor/policy.rs +++ b/src/descriptor/policy.rs @@ -814,13 +814,10 @@ mod test { tprv: &str, ) -> (DescriptorKey, DescriptorKey, Fingerprint) { let secp: Secp256k1 = Secp256k1::new(); - let path = bip32::DerivationPath::from_str(PATH).unwrap(); - let tprv = bip32::ExtendedPrivKey::from_str(tprv).unwrap(); let tpub = bip32::ExtendedPubKey::from_private(&secp, &tprv); let fingerprint = tprv.fingerprint(&secp); - let prvkey = (tprv, path.clone()).to_descriptor_key().unwrap(); let pubkey = (tpub, path).to_descriptor_key().unwrap(); @@ -832,20 +829,14 @@ mod test { #[test] fn test_extract_policy_for_wpkh() { let (prvkey, pubkey, fingerprint) = setup_keys(TPRV0_STR); - let desc = descriptor!(wpkh(pubkey)).unwrap(); - - println!("desc = {:?}", desc); // TODO remove - let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap(); - let signers_container = Arc::new(SignersContainer::from(keymap)); let policy = wallet_desc .extract_policy(signers_container) .unwrap() .unwrap(); - println!("desc policy = {:?}", policy); // TODO remove assert!( matches!(&policy.item, Signature(pk_or_f) if &pk_or_f.fingerprint.unwrap() == &fingerprint) ); @@ -853,14 +844,12 @@ mod test { let desc = descriptor!(wpkh(prvkey)).unwrap(); let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap(); - let signers_container = Arc::new(SignersContainer::from(keymap)); let policy = wallet_desc .extract_policy(signers_container) .unwrap() .unwrap(); - println!("desc policy = {:?}", policy); // TODO remove assert!( matches!(&policy.item, Signature(pk_or_f) if &pk_or_f.fingerprint.unwrap() == &fingerprint) ); @@ -874,17 +863,14 @@ mod test { fn test_extract_policy_for_sh_multi_partial_0of2() { let (_prvkey0, pubkey0, fingerprint0) = setup_keys(TPRV0_STR); let (_prvkey1, pubkey1, fingerprint1) = setup_keys(TPRV1_STR); - let desc = descriptor!(sh(multi 2, pubkey0, pubkey1)).unwrap(); let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap(); - let signers_container = Arc::new(SignersContainer::from(keymap)); let policy = wallet_desc .extract_policy(signers_container) .unwrap() .unwrap(); - println!("desc policy = {:?}", policy); // TODO remove assert!( matches!(&policy.item, Multisig { keys, threshold } if threshold == &2 && &keys[0].fingerprint.unwrap() == &fingerprint0 @@ -907,17 +893,14 @@ mod test { fn test_extract_policy_for_sh_multi_partial_1of2() { let (prvkey0, _pubkey0, fingerprint0) = setup_keys(TPRV0_STR); let (_prvkey1, pubkey1, fingerprint1) = setup_keys(TPRV1_STR); - let desc = descriptor!(sh(multi 2, prvkey0, pubkey1)).unwrap(); let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap(); - let signers_container = Arc::new(SignersContainer::from(keymap)); let policy = wallet_desc .extract_policy(signers_container) .unwrap() .unwrap(); - println!("desc policy = {:?}", policy); // TODO remove assert!( matches!(&policy.item, Multisig { keys, threshold } if threshold == &2 && &keys[0].fingerprint.unwrap() == &fingerprint0 @@ -939,17 +922,14 @@ mod test { fn test_extract_policy_for_sh_multi_complete_1of2() { let (_prvkey0, pubkey0, fingerprint0) = setup_keys(TPRV0_STR); let (prvkey1, _pubkey1, fingerprint1) = setup_keys(TPRV1_STR); - let desc = descriptor!(sh(multi 1, pubkey0, prvkey1)).unwrap(); let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap(); - let signers_container = Arc::new(SignersContainer::from(keymap)); let policy = wallet_desc .extract_policy(signers_container) .unwrap() .unwrap(); - println!("desc policy = {:?}", policy); // TODO remove assert!( matches!(&policy.item, Multisig { keys, threshold } if threshold == &1 && &keys[0].fingerprint.unwrap() == &fingerprint0 @@ -970,18 +950,14 @@ mod test { fn test_extract_policy_for_sh_multi_complete_2of2() { let (prvkey0, _pubkey0, fingerprint0) = setup_keys(TPRV0_STR); let (prvkey1, _pubkey1, fingerprint1) = setup_keys(TPRV1_STR); - let desc = descriptor!(sh(multi 2, prvkey0, prvkey1)).unwrap(); let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap(); - let signers_container = Arc::new(SignersContainer::from(keymap)); - let policy = wallet_desc .extract_policy(signers_container) .unwrap() .unwrap(); - println!("desc policy = {:?}", policy); // TODO remove assert!( matches!(&policy.item, Multisig { keys, threshold } if threshold == &2 && &keys[0].fingerprint.unwrap() == &fingerprint0 @@ -1002,22 +978,15 @@ mod test { #[test] fn test_extract_policy_for_single_wpkh() { let (prvkey, pubkey, fingerprint) = setup_keys(TPRV0_STR); - let desc = descriptor!(wpkh(pubkey)).unwrap(); - println!("desc = {:?}", desc); // TODO remove - let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap(); - let single_key = wallet_desc.derive(&[ChildNumber::from_normal_idx(0).unwrap()]); - println!("single_key = {:?}", single_key); // TODO remove - let signers_container = Arc::new(SignersContainer::from(keymap)); let policy = single_key .extract_policy(signers_container) .unwrap() .unwrap(); - println!("desc policy = {:?}", policy); // TODO remove assert!( matches!(&policy.item, Signature(pk_or_f) if &pk_or_f.fingerprint.unwrap() == &fingerprint) ); @@ -1025,18 +994,13 @@ mod test { let desc = descriptor!(wpkh(prvkey)).unwrap(); let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap(); - let single_key = wallet_desc.derive(&[ChildNumber::from_normal_idx(0).unwrap()]); - - println!("single_key = {:?}", single_key); // TODO remove - let signers_container = Arc::new(SignersContainer::from(keymap)); let policy = single_key .extract_policy(signers_container) .unwrap() .unwrap(); - println!("desc policy = {:?}", policy); // TODO remove assert!( matches!(&policy.item, Signature(pk_or_f) if &pk_or_f.fingerprint.unwrap() == &fingerprint) ); @@ -1050,20 +1014,15 @@ mod test { fn test_extract_policy_for_single_wsh_multi_complete_1of2() { let (_prvkey0, pubkey0, fingerprint0) = setup_keys(TPRV0_STR); let (prvkey1, _pubkey1, fingerprint1) = setup_keys(TPRV1_STR); - let desc = descriptor!(sh(multi 1, pubkey0, prvkey1)).unwrap(); let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap(); - let single_key = wallet_desc.derive(&[ChildNumber::from_normal_idx(0).unwrap()]); - println!("single_key = {:?}", single_key); // TODO remove - let signers_container = Arc::new(SignersContainer::from(keymap)); let policy = single_key .extract_policy(signers_container) .unwrap() .unwrap(); - println!("desc policy = {:?}", policy); // TODO remove assert!( matches!(&policy.item, Multisig { keys, threshold } if threshold == &1 && &keys[0].fingerprint.unwrap() == &fingerprint0 @@ -1086,23 +1045,18 @@ mod test { let (prvkey0, _pubkey0, _fingerprint0) = setup_keys(TPRV0_STR); let (_prvkey1, pubkey1, _fingerprint1) = setup_keys(TPRV1_STR); let sequence = 50; - let desc = descriptor!(wsh ( thresh 2, (pk prvkey0), (+s pk pubkey1), (+s+d+v older sequence) )) .unwrap(); - println!("desc = {:?}", desc); // TODO remove - let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap(); - let signers_container = Arc::new(SignersContainer::from(keymap)); let policy = wallet_desc .extract_policy(signers_container) .unwrap() .unwrap(); - println!("desc policy = {:?}", policy); // TODO remove assert!( matches!(&policy.item, Thresh { items, threshold } if items.len() == 3 && threshold == &2) ); @@ -1123,17 +1077,11 @@ mod test { #[test] fn test_extract_policy_for_wsh_mixed_timelocks() { let (prvkey0, _pubkey0, _fingerprint0) = setup_keys(TPRV0_STR); - let locktime_threshold = 500000000; // if less than this means block number, else block time in seconds let locktime_blocks = 100; let locktime_seconds = locktime_blocks + locktime_threshold; - let desc = descriptor!(sh (and_v (+v pk prvkey0), (and_v (+v after locktime_seconds), (after locktime_blocks)))).unwrap(); - - println!("desc = {:?}", desc); // TODO remove - let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap(); - let signers_container = Arc::new(SignersContainer::from(keymap)); let policy = wallet_desc .extract_policy(signers_container) @@ -1150,16 +1098,10 @@ mod test { #[test] fn test_extract_policy_for_multiple_same_timelocks() { let (prvkey0, _pubkey0, _fingerprint0) = setup_keys(TPRV0_STR); - let locktime_blocks0 = 100; let locktime_blocks1 = 200; - let desc = descriptor!(sh (and_v (+v pk prvkey0), (and_v (+v after locktime_blocks0), (after locktime_blocks1)))).unwrap(); - - println!("desc = {:?}", desc); // TODO remove - let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap(); - let signers_container = Arc::new(SignersContainer::from(keymap)); let policy = wallet_desc .extract_policy(signers_container) @@ -1168,17 +1110,13 @@ mod test { println!("desc policy = {:?}", policy); // TODO remove - let (prvkey1, _pubkey1, _fingerprint1) = setup_keys(TPRV0_STR); + // TODO how should this merge timelocks? + let (prvkey1, _pubkey1, _fingerprint1) = setup_keys(TPRV0_STR); let locktime_seconds0 = 500000100; let locktime_seconds1 = 500000200; - let desc = descriptor!(sh (and_v (+v pk prvkey1), (and_v (+v after locktime_seconds0), (after locktime_seconds1)))).unwrap(); - - println!("desc = {:?}", desc); // TODO remove - let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap(); - let signers_container = Arc::new(SignersContainer::from(keymap)); let policy = wallet_desc .extract_policy(signers_container) diff --git a/src/descriptor/template.rs b/src/descriptor/template.rs index b167ca45..6cc6b17f 100644 --- a/src/descriptor/template.rs +++ b/src/descriptor/template.rs @@ -422,3 +422,5 @@ macro_rules! expand_make_bipxx { expand_make_bipxx!(legacy, Legacy); expand_make_bipxx!(segwit_v0, Segwitv0); + +// test existing descriptor templates, make sure they are expanded to the right descriptors