From e31f5306d27ecf6dffaab3bfb8aade7e19bad075 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Mon, 12 Oct 2020 09:09:25 -0700 Subject: [PATCH] [descriptor] Add descriptor macro tests --- src/descriptor/dsl.rs | 299 ++++++++++++++++++++++++++++++++++++- src/descriptor/template.rs | 270 ++++++++++++++++++++++++++++++++- src/keys/mod.rs | 1 + src/lib.rs | 3 - 4 files changed, 563 insertions(+), 10 deletions(-) diff --git a/src/descriptor/dsl.rs b/src/descriptor/dsl.rs index 6b99d448..da4c5d24 100644 --- a/src/descriptor/dsl.rs +++ b/src/descriptor/dsl.rs @@ -403,9 +403,296 @@ 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 +#[cfg(test)] +mod test { + use bitcoin::hashes::hex::ToHex; + use miniscript::descriptor::{DescriptorPublicKey, KeyMap}; + use miniscript::{Descriptor, Legacy, Segwitv0}; + + use std::str::FromStr; + + use crate::descriptor::DescriptorMeta; + use crate::keys::{DescriptorKey, KeyError, ToDescriptorKey, ValidNetworks}; + use bitcoin::network::constants::Network::{Bitcoin, Regtest, Testnet}; + use bitcoin::util::bip32; + use bitcoin::util::bip32::ChildNumber; + + // test the descriptor!() macro + + // verify descriptor generates expected script(s) (if bare or pk) or address(es) + fn check( + desc: Result<(Descriptor, KeyMap, ValidNetworks), KeyError>, + is_witness: bool, + is_fixed: bool, + expected: &[&str], + ) { + let (desc, _key_map, _networks) = desc.unwrap(); + assert_eq!(desc.is_witness(), is_witness); + assert_eq!(desc.is_fixed(), is_fixed); + for i in 0..expected.len() { + let index = i as u32; + let child_desc = if desc.is_fixed() { + desc.clone() + } else { + desc.derive(&[ChildNumber::from_normal_idx(index).unwrap()]) + }; + let address = child_desc.address(Regtest); + if address.is_some() { + assert_eq!(address.unwrap().to_string(), *expected.get(i).unwrap()); + } else { + let script = child_desc.script_pubkey(); + assert_eq!(script.to_hex().as_str(), *expected.get(i).unwrap()); + } + } + } + + // - 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() + + // expected script for pk and bare manually created + // expected addresses created with `bitcoin-cli getdescriptorinfo` (for hash) and `bitcoin-cli deriveaddresses` + + #[test] + fn test_fixed_legacy_descriptors() { + let pubkey1 = bitcoin::PublicKey::from_str( + "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd", + ) + .unwrap(); + let pubkey2 = bitcoin::PublicKey::from_str( + "032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af", + ) + .unwrap(); + + check( + descriptor!(bare(multi 1,pubkey1,pubkey2)), + false, + true, + &["512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd21032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af52ae"], + ); + check( + descriptor!(pk(pubkey1)), + false, + true, + &["2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bdac"], + ); + check( + descriptor!(pkh(pubkey1)), + false, + true, + &["muZpTpBYhxmRFuCjLc7C6BBDF32C8XVJUi"], + ); + check( + descriptor!(sh(multi 1,pubkey1,pubkey2)), + false, + true, + &["2MymURoV1bzuMnWMGiXzyomDkeuxXY7Suey"], + ); + } + + #[test] + fn test_fixed_segwitv0_descriptors() { + let pubkey1 = bitcoin::PublicKey::from_str( + "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd", + ) + .unwrap(); + let pubkey2 = bitcoin::PublicKey::from_str( + "032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af", + ) + .unwrap(); + + check( + descriptor!(wpkh(pubkey1)), + true, + true, + &["bcrt1qngw83fg8dz0k749cg7k3emc7v98wy0c7azaa6h"], + ); + check( + descriptor!(sh(wpkh(pubkey1))), + true, + true, + &["2N5LiC3CqzxDamRTPG1kiNv1FpNJQ7x28sb"], + ); + check( + descriptor!(wsh(multi 1,pubkey1,pubkey2)), + true, + true, + &["bcrt1qgw8jvv2hsrvjfa6q66rk6har7d32lrqm5unnf5cl63q9phxfvgps5fyfqe"], + ); + check( + descriptor!(sh(wsh(multi 1,pubkey1,pubkey2))), + true, + true, + &["2NCidRJysy7apkmE6JF5mLLaJFkrN3Ub9iy"], + ); + } + + #[test] + fn test_bip32_legacy_descriptors() { + let xprv = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + + let path = bip32::DerivationPath::from_str("m/0").unwrap(); + let desc_key = (xprv, path.clone()).to_descriptor_key().unwrap(); + check( + descriptor!(pk(desc_key)), + false, + false, + &[ + "2102363ad03c10024e1b597a5b01b9982807fb638e00b06f3b2d4a89707de3b93c37ac", + "2102063a21fd780df370ed2fc8c4b86aa5ea642630609c203009df631feb7b480dd2ac", + "2102ba2685ad1fa5891cb100f1656b2ce3801822ccb9bac0336734a6f8c1b93ebbc0ac", + ], + ); + + let desc_key = (xprv, path.clone()).to_descriptor_key().unwrap(); + check( + descriptor!(pkh(desc_key)), + false, + false, + &[ + "muvBdsVpJxpFuTHMKA47htJPdCvdt4F9DP", + "mxQSHK7DL2t1DN3xFxov1janCoXSSkrSPj", + "mfz43r15GiWo4nizmyzMNubsnkDpByFFAn", + ], + ); + + let path2 = bip32::DerivationPath::from_str("m/2147483647'/0").unwrap(); + let desc_key1 = (xprv, path).to_descriptor_key().unwrap(); + let desc_key2 = (xprv, path2).to_descriptor_key().unwrap(); + + check( + descriptor!(sh(multi 1,desc_key1,desc_key2)), + false, + false, + &[ + "2MtMDXsfwefZkEEhVViEPidvcKRUtJamJJ8", + "2MwAUZ1NYyWjhVvGTethFL6n7nZhS8WE6At", + "2MuT6Bj66HLwZd7s4SoD8XbK4GwriKEA6Gr", + ], + ); + } + + #[test] + fn test_bip32_segwitv0_descriptors() { + let xprv = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + + let path = bip32::DerivationPath::from_str("m/0").unwrap(); + let desc_key = (xprv, path.clone()).to_descriptor_key().unwrap(); + check( + descriptor!(wpkh(desc_key)), + true, + false, + &[ + "bcrt1qnhm8w9fhc8cxzgqsmqdf9fyjccyvc0gltnymu0", + "bcrt1qhylfd55rn75w9fj06zspctad5w4hz33rf0ttad", + "bcrt1qq5sq3a6k9av9d8cne0k9wcldy4nqey5yt6889r", + ], + ); + + let desc_key = (xprv, path.clone()).to_descriptor_key().unwrap(); + check( + descriptor!(sh(wpkh(desc_key))), + true, + false, + &[ + "2MxvjQCaLqZ5QxZ7XotZDQ63hZw3NPss763", + "2NDUoevN4QMzhvHDMGhKuiT2fN9HXbFRMwn", + "2NF4BEAY2jF1Fu8vqfN3NVKoFtom77pUxrx", + ], + ); + + let path2 = bip32::DerivationPath::from_str("m/2147483647'/0").unwrap(); + let desc_key1 = (xprv, path.clone()).to_descriptor_key().unwrap(); + let desc_key2 = (xprv, path2.clone()).to_descriptor_key().unwrap(); + check( + descriptor!(wsh(multi 1,desc_key1,desc_key2)), + true, + false, + &[ + "bcrt1qfxv8mxmlv5sz8q2mnuyaqdfe9jr4vvmx0csjhn092p6f4qfygfkq2hng49", + "bcrt1qerj85g243e6jlcdxpmn9spk0gefcwvu7nw7ee059d5ydzpdhkm2qwfkf5k", + "bcrt1qxkl2qss3k58q9ktc8e89pwr4gnptfpw4hju4xstxcjc0hkcae3jstluty7", + ], + ); + + let desc_key1 = (xprv, path).to_descriptor_key().unwrap(); + let desc_key2 = (xprv, path2).to_descriptor_key().unwrap(); + check( + descriptor!(sh(wsh(multi 1,desc_key1,desc_key2))), + true, + false, + &[ + "2NFCtXvx9q4ci2kvKub17iSTgvRXGctCGhz", + "2NB2PrFPv5NxWCpygas8tPrGJG2ZFgeuwJw", + "2N79ZAGo5cMi5Jt7Wo9L5YmF5GkEw7sjWdC", + ], + ); + } + + // - verify the valid_networks returned is correctly computed based on the keys present in the descriptor + #[test] + fn test_valid_networks() { + let xprv = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + let path = bip32::DerivationPath::from_str("m/0").unwrap(); + let desc_key = (xprv, path.clone()).to_descriptor_key().unwrap(); + + let (_desc, _key_map, valid_networks) = descriptor!(pkh(desc_key)).unwrap(); + assert_eq!(valid_networks, [Testnet, Regtest].iter().cloned().collect()); + + let xprv = bip32::ExtendedPrivKey::from_str("xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi").unwrap(); + let path = bip32::DerivationPath::from_str("m/10/20/30/40").unwrap(); + let desc_key = (xprv, path.clone()).to_descriptor_key().unwrap(); + + let (_desc, _key_map, valid_networks) = descriptor!(wpkh(desc_key)).unwrap(); + assert_eq!(valid_networks, [Bitcoin].iter().cloned().collect()); + } + + // - verify the key_maps are correctly merged together + #[test] + fn test_key_maps_merged() { + let xprv1 = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + let path1 = bip32::DerivationPath::from_str("m/0").unwrap(); + let desc_key1 = (xprv1, path1.clone()).to_descriptor_key().unwrap(); + + let xprv2 = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPegBHHnq7YEgM815dG24M2Jk5RVqipgDxF1HJ1tsnT815X5Fd5FRfMVUs8NZs9XCb6y9an8hRPThnhfwfXJ36intaekySHGF").unwrap(); + let path2 = bip32::DerivationPath::from_str("m/2147483647'/0").unwrap(); + let desc_key2 = (xprv2, path2.clone()).to_descriptor_key().unwrap(); + + let xprv3 = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPdZXrcHNLf5JAJWFAoJ2TrstMRdSKtEggz6PddbuSkvHKM9oKJyFgZV1B7rw8oChspxyYbtmEXYyg1AjfWbL3ho3XHDpHRZf").unwrap(); + let path3 = bip32::DerivationPath::from_str("m/10/20/30/40").unwrap(); + let desc_key3 = (xprv3, path3.clone()).to_descriptor_key().unwrap(); + + let (_desc, key_map, _valid_networks) = + descriptor!(sh(wsh(multi 2,desc_key1,desc_key2,desc_key3))).unwrap(); + assert_eq!(key_map.len(), 3); + + let desc_key1: DescriptorKey = + (xprv1, path1.clone()).to_descriptor_key().unwrap(); + let desc_key2: DescriptorKey = + (xprv2, path2.clone()).to_descriptor_key().unwrap(); + let desc_key3: DescriptorKey = + (xprv3, path3.clone()).to_descriptor_key().unwrap(); + + let (key1, _key_map, _valid_networks) = desc_key1.extract().unwrap(); + let (key2, _key_map, _valid_networks) = desc_key2.extract().unwrap(); + let (key3, _key_map, _valid_networks) = desc_key3.extract().unwrap(); + assert_eq!(key_map.get(&key1).unwrap().to_string(), "tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy/0/*"); + assert_eq!(key_map.get(&key2).unwrap().to_string(), "tprv8ZgxMBicQKsPegBHHnq7YEgM815dG24M2Jk5RVqipgDxF1HJ1tsnT815X5Fd5FRfMVUs8NZs9XCb6y9an8hRPThnhfwfXJ36intaekySHGF/2147483647'/0/*"); + assert_eq!(key_map.get(&key3).unwrap().to_string(), "tprv8ZgxMBicQKsPdZXrcHNLf5JAJWFAoJ2TrstMRdSKtEggz6PddbuSkvHKM9oKJyFgZV1B7rw8oChspxyYbtmEXYyg1AjfWbL3ho3XHDpHRZf/10/20/30/40/*"); + } + + // - verify the ScriptContext is correctly validated (i.e. passing a type that only impl ToDescriptorKey to a pkh() descriptor should throw a compilation error + #[test] + fn test_script_context_validation() { + // this compiles + let xprv = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + let path = bip32::DerivationPath::from_str("m/0").unwrap(); + let desc_key: DescriptorKey = (xprv, path.clone()).to_descriptor_key().unwrap(); + + let (desc, _key_map, _valid_networks) = descriptor!(pkh(desc_key)).unwrap(); + assert_eq!(desc.to_string(), "pkh(tpubD6NzVbkrYhZ4WR7a4vY1VT3khMJMeAxVsfq9TBJyJWrNk247zCJtV7AWf6UJP7rAVsn8NNKdJi3gFyKPTmWZS9iukb91xbn2HbFSMQm2igY/0/*)"); + + // as expected this does not compile due to invalid context + //let desc_key:DescriptorKey = (xprv, path.clone()).to_descriptor_key().unwrap(); + //let (desc, _key_map, _valid_networks) = descriptor!(pkh(desc_key)).unwrap(); + } +} diff --git a/src/descriptor/template.rs b/src/descriptor/template.rs index 6cc6b17f..64a4a399 100644 --- a/src/descriptor/template.rs +++ b/src/descriptor/template.rs @@ -423,4 +423,272 @@ 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 +#[cfg(test)] +mod test { + // test existing descriptor templates, make sure they are expanded to the right descriptors + + use super::*; + use crate::descriptor::DescriptorMeta; + use crate::keys::{KeyError, ValidNetworks}; + use bitcoin::hashes::core::str::FromStr; + use bitcoin::network::constants::Network::Regtest; + use bitcoin::util::bip32::ChildNumber; + use miniscript::descriptor::{DescriptorPublicKey, KeyMap}; + use miniscript::Descriptor; + + // verify template descriptor generates expected address(es) + fn check( + desc: Result<(Descriptor, KeyMap, ValidNetworks), KeyError>, + is_witness: bool, + is_fixed: bool, + expected: &[&str], + ) { + let (desc, _key_map, _networks) = desc.unwrap(); + assert_eq!(desc.is_witness(), is_witness); + assert_eq!(desc.is_fixed(), is_fixed); + for i in 0..expected.len() { + let index = i as u32; + let child_desc = if desc.is_fixed() { + desc.clone() + } else { + desc.derive(&[ChildNumber::from_normal_idx(index).unwrap()]) + }; + let address = child_desc.address(Regtest).unwrap(); + assert_eq!(address.to_string(), *expected.get(i).unwrap()); + } + } + + // P2PKH + #[test] + fn test_p2ph_template() { + let prvkey = + bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um") + .unwrap(); + check( + P2PKH(prvkey).build(), + false, + true, + &["mwJ8hxFYW19JLuc65RCTaP4v1rzVU8cVMT"], + ); + + let pubkey = bitcoin::PublicKey::from_str( + "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd", + ) + .unwrap(); + check( + P2PKH(pubkey).build(), + false, + true, + &["muZpTpBYhxmRFuCjLc7C6BBDF32C8XVJUi"], + ); + } + + // P2WPKH-P2SH `sh(wpkh(key))` + #[test] + fn test_p2wphp2sh_template() { + let prvkey = + bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um") + .unwrap(); + check( + P2WPKH_P2SH(prvkey).build(), + true, + true, + &["2NB4ox5VDRw1ecUv6SnT3VQHPXveYztRqk5"], + ); + + let pubkey = bitcoin::PublicKey::from_str( + "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd", + ) + .unwrap(); + check( + P2WPKH_P2SH(pubkey).build(), + true, + true, + &["2N5LiC3CqzxDamRTPG1kiNv1FpNJQ7x28sb"], + ); + } + + // P2WPKH `wpkh(key)` + #[test] + fn test_p2wph_template() { + let prvkey = + bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um") + .unwrap(); + check( + P2WPKH(prvkey).build(), + true, + true, + &["bcrt1q4525hmgw265tl3drrl8jjta7ayffu6jfcwxx9y"], + ); + + let pubkey = bitcoin::PublicKey::from_str( + "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd", + ) + .unwrap(); + check( + P2WPKH(pubkey).build(), + true, + true, + &["bcrt1qngw83fg8dz0k749cg7k3emc7v98wy0c7azaa6h"], + ); + } + + // BIP44 `pkh(key/44'/0'/0'/{0,1}/*)` + #[test] + fn test_bip44_template() { + let prvkey = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + check( + BIP44(prvkey, ScriptType::External).build(), + false, + false, + &[ + "n453VtnjDHPyDt2fDstKSu7A3YCJoHZ5g5", + "mvfrrumXgTtwFPWDNUecBBgzuMXhYM7KRP", + "mzYvhRAuQqbdSKMVVzXNYyqihgNdRadAUQ", + ], + ); + check( + BIP44(prvkey, ScriptType::Internal).build(), + false, + false, + &[ + "muHF98X9KxEzdKrnFAX85KeHv96eXopaip", + "n4hpyLJE5ub6B5Bymv4eqFxS5KjrewSmYR", + "mgvkdv1ffmsXd2B1sRKQ5dByK3SzpG42rA", + ], + ); + } + + // BIP44 public `pkh(key/{0,1}/*)` + #[test] + fn test_bip44_public_template() { + let pubkey = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU").unwrap(); + let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f").unwrap(); + check( + BIP44Public(pubkey, fingerprint, ScriptType::External).build(), + false, + false, + &[ + "miNG7dJTzJqNbFS19svRdTCisC65dsubtR", + "n2UqaDbCjWSFJvpC84m3FjUk5UaeibCzYg", + "muCPpS6Ue7nkzeJMWDViw7Lkwr92Yc4K8g", + ], + ); + check( + BIP44Public(pubkey, fingerprint, ScriptType::Internal).build(), + false, + false, + &[ + "moDr3vJ8wpt5nNxSK55MPq797nXJb2Ru9H", + "ms7A1Yt4uTezT2XkefW12AvLoko8WfNJMG", + "mhYiyat2rtEnV77cFfQsW32y1m2ceCGHPo", + ], + ); + } + + // BIP49 `sh(wpkh(key/49'/0'/0'/{0,1}/*))` + #[test] + fn test_bip49_template() { + let prvkey = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + check( + BIP49(prvkey, ScriptType::External).build(), + true, + false, + &[ + "2N9bCAJXGm168MjVwpkBdNt6ucka3PKVoUV", + "2NDckYkqrYyDMtttEav5hB3Bfw9EGAW5HtS", + "2NAFTVtksF9T4a97M7nyCjwUBD24QevZ5Z4", + ], + ); + check( + BIP49(prvkey, ScriptType::Internal).build(), + true, + false, + &[ + "2NB3pA8PnzJLGV8YEKNDFpbViZv3Bm1K6CG", + "2NBiX2Wzxngb5rPiWpUiJQ2uLVB4HBjFD4p", + "2NA8ek4CdQ6aMkveYF6AYuEYNrftB47QGTn", + ], + ); + } + + // BIP49 public `sh(wpkh(key/{0,1}/*))` + #[test] + fn test_bip49_public_template() { + let pubkey = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L").unwrap(); + let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f").unwrap(); + check( + BIP49Public(pubkey, fingerprint, ScriptType::External).build(), + true, + false, + &[ + "2N3K4xbVAHoiTQSwxkZjWDfKoNC27pLkYnt", + "2NCTQfJ1sZa3wQ3pPseYRHbaNEpC3AquEfX", + "2MveFxAuC8BYPzTybx7FxSzW8HSd8ATT4z7", + ], + ); + check( + BIP49Public(pubkey, fingerprint, ScriptType::Internal).build(), + true, + false, + &[ + "2NF2vttKibwyxigxtx95Zw8K7JhDbo5zPVJ", + "2Mtmyd8taksxNVWCJ4wVvaiss7QPZGcAJuH", + "2NBs3CTVYPr1HCzjB4YFsnWCPCtNg8uMEfp", + ], + ); + } + + // BIP84 `wpkh(key/84'/0'/0'/{0,1}/*)` + #[test] + fn test_bip84_template() { + let prvkey = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + check( + BIP84(prvkey, ScriptType::External).build(), + true, + false, + &[ + "bcrt1qkmvk2nadgplmd57ztld8nf8v2yxkzmdvwtjf8s", + "bcrt1qx0v6zgfwe50m4kqc58cqzcyem7ay2sfl3gvqhp", + "bcrt1q4h7fq9zhxst6e69p3n882nfj649l7w9g3zccfp", + ], + ); + check( + BIP84(prvkey, ScriptType::Internal).build(), + true, + false, + &[ + "bcrt1qtrwtz00wxl69e5xex7amy4xzlxkaefg3gfdkxa", + "bcrt1qqqasfhxpkkf7zrxqnkr2sfhn74dgsrc3e3ky45", + "bcrt1qpks7n0gq74hsgsz3phn5vuazjjq0f5eqhsgyce", + ], + ); + } + + // BIP84 public `wpkh(key/{0,1}/*)` + #[test] + fn test_bip84_public_template() { + let pubkey = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q").unwrap(); + let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f").unwrap(); + check( + BIP84Public(pubkey, fingerprint, ScriptType::External).build(), + true, + false, + &[ + "bcrt1qedg9fdlf8cnnqfd5mks6uz5w4kgpk2prcdvd0h", + "bcrt1q3lncdlwq3lgcaaeyruynjnlccr0ve0kakh6ana", + "bcrt1qt9800y6xl3922jy3uyl0z33jh5wfpycyhcylr9", + ], + ); + check( + BIP84Public(pubkey, fingerprint, ScriptType::Internal).build(), + true, + false, + &[ + "bcrt1qm6wqukenh7guu792lj2njgw9n78cmwsy8xy3z2", + "bcrt1q694twxtjn4nnrvnyvra769j0a23rllj5c6cgwp", + "bcrt1qhlac3c5ranv5w5emlnqs7wxhkxt8maelylcarp", + ], + ); + } +} diff --git a/src/keys/mod.rs b/src/keys/mod.rs index d8fe8bda..34b29406 100644 --- a/src/keys/mod.rs +++ b/src/keys/mod.rs @@ -68,6 +68,7 @@ pub fn merge_networks(a: &ValidNetworks, b: &ValidNetworks) -> ValidNetworks { } /// Container for public or secret keys +#[derive(Debug)] pub enum DescriptorKey { #[doc(hidden)] Public(DescriptorPublicKey, ValidNetworks, PhantomData), diff --git a/src/lib.rs b/src/lib.rs index 69fc670e..d946c4f6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,9 +66,6 @@ pub mod cli; extern crate testutils; #[cfg(test)] #[macro_use] -extern crate testutils_macros; -#[cfg(test)] -#[macro_use] extern crate serial_test; #[macro_use]